mirror of
https://github.com/cc65/cc65.git
synced 2024-09-28 10:55:43 +00:00
Fixed and improved the code for compares. Before, compares of chars to a
constant where sometimes passed down to the code generator in a way that caused wrong code to be generated. This change may go into 2.13 after some testing. git-svn-id: svn://svn.cc65.org/cc65/trunk@4743 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
4cd7eec075
commit
2bb2d97ab0
160
src/cc65/expr.c
160
src/cc65/expr.c
@ -109,12 +109,13 @@ void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr)
|
|||||||
/* Do some checks if code generation is still constistent */
|
/* Do some checks if code generation is still constistent */
|
||||||
if (StackPtr != OldSP) {
|
if (StackPtr != OldSP) {
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf (stderr,
|
Error ("Code generation messed up: "
|
||||||
"Code generation messed up!\n"
|
|
||||||
"StackPtr is %d, should be %d",
|
"StackPtr is %d, should be %d",
|
||||||
StackPtr, OldSP);
|
StackPtr, OldSP);
|
||||||
} else {
|
} else {
|
||||||
Internal ("StackPtr is %d, should be %d\n", StackPtr, OldSP);
|
Internal ("Code generation messed up: "
|
||||||
|
"StackPtr is %d, should be %d",
|
||||||
|
StackPtr, OldSP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,6 +256,18 @@ void PushAddr (const ExprDesc* Expr)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void WarnConstCompareResult (void)
|
||||||
|
/* If the result of a comparison is constant, this is suspicious when not in
|
||||||
|
* preprocessor mode.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if (!Preprocessing) {
|
||||||
|
Warning ("Result of comparison is constant");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* code */
|
/* code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -1904,6 +1917,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
/* Helper function for the compare operators */
|
/* Helper function for the compare operators */
|
||||||
{
|
{
|
||||||
ExprDesc Expr2;
|
ExprDesc Expr2;
|
||||||
|
CodeMark Mark0;
|
||||||
CodeMark Mark1;
|
CodeMark Mark1;
|
||||||
CodeMark Mark2;
|
CodeMark Mark2;
|
||||||
const GenDesc* Gen;
|
const GenDesc* Gen;
|
||||||
@ -1912,10 +1926,14 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
int rconst; /* Operand is a constant */
|
int rconst; /* Operand is a constant */
|
||||||
|
|
||||||
|
|
||||||
|
GetCodePos (&Mark0);
|
||||||
hienext (Expr);
|
hienext (Expr);
|
||||||
|
|
||||||
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
||||||
|
|
||||||
|
/* Remember the generator function */
|
||||||
|
void (*GenFunc) (unsigned, unsigned long) = Gen->Func;
|
||||||
|
|
||||||
/* Remember the operator token, then skip it */
|
/* Remember the operator token, then skip it */
|
||||||
Tok = CurTok.Tok;
|
Tok = CurTok.Tok;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
@ -1971,9 +1989,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
/* If the result is constant, this is suspicious when not in
|
/* If the result is constant, this is suspicious when not in
|
||||||
* preprocessor mode.
|
* preprocessor mode.
|
||||||
*/
|
*/
|
||||||
if (!Preprocessing) {
|
WarnConstCompareResult ();
|
||||||
Warning ("Result of comparison is constant");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Both operands are constant, remove the generated code */
|
/* Both operands are constant, remove the generated code */
|
||||||
RemoveCode (&Mark1);
|
RemoveCode (&Mark1);
|
||||||
@ -2026,27 +2042,139 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the type of the operation result. If the left
|
/* Determine the type of the operation. */
|
||||||
* operand is of type char and the right is a constant, or
|
if (IsTypeChar (Expr->Type) && rconst) {
|
||||||
* if both operands are of type char, we will encode the
|
|
||||||
* operation as char operation. Otherwise the default
|
/* Left side is unsigned char, right side is constant */
|
||||||
* promotions are used.
|
int LeftSigned = IsSignSigned (Expr->Type);
|
||||||
|
int RightSigned = IsSignSigned (Expr2.Type);
|
||||||
|
|
||||||
|
/* Determine the minimum and maximum values */
|
||||||
|
int LeftMin, LeftMax;
|
||||||
|
if (LeftSigned) {
|
||||||
|
LeftMin = -128;
|
||||||
|
LeftMax = 127;
|
||||||
|
} else {
|
||||||
|
LeftMin = 0;
|
||||||
|
LeftMax = 255;
|
||||||
|
}
|
||||||
|
/* An integer value is always represented as a signed in the
|
||||||
|
* ExprDesc structure. This may lead to false results below,
|
||||||
|
* if it is actually unsigned, but interpreted as signed
|
||||||
|
* because of the representation. Fortunately, in this case,
|
||||||
|
* the actual value doesn't matter, since it's always greater
|
||||||
|
* than what can be represented in a char. So correct the
|
||||||
|
* value accordingly.
|
||||||
*/
|
*/
|
||||||
if (IsTypeChar (Expr->Type) && (IsTypeChar (Expr2.Type) || rconst)) {
|
if (!RightSigned && Expr2.IVal < 0) {
|
||||||
flags |= CF_CHAR;
|
/* Correct the value so it is an unsigned. It will then
|
||||||
if (IsSignUnsigned (Expr->Type) || IsSignUnsigned (Expr2.Type)) {
|
* anyway match one of the cases below.
|
||||||
|
*/
|
||||||
|
Expr2.IVal = LeftMax + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comparing a char against a constant may have a constant
|
||||||
|
* result.
|
||||||
|
*/
|
||||||
|
switch (Tok) {
|
||||||
|
|
||||||
|
case TOK_EQ:
|
||||||
|
if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
|
||||||
|
ED_MakeConstAbsInt (Expr, 0);
|
||||||
|
WarnConstCompareResult ();
|
||||||
|
RemoveCode (&Mark0);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_NE:
|
||||||
|
if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
|
||||||
|
ED_MakeConstAbsInt (Expr, 1);
|
||||||
|
WarnConstCompareResult ();
|
||||||
|
RemoveCode (&Mark0);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_LT:
|
||||||
|
if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
|
||||||
|
ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax);
|
||||||
|
WarnConstCompareResult ();
|
||||||
|
RemoveCode (&Mark0);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_LE:
|
||||||
|
if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
|
||||||
|
ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax);
|
||||||
|
WarnConstCompareResult ();
|
||||||
|
RemoveCode (&Mark0);
|
||||||
|
goto Done;
|
||||||
|
} else if (!LeftSigned && Expr2.IVal == 0) {
|
||||||
|
/* We can replace this by a compare to zero, because
|
||||||
|
* the value of lhs may never be negative.
|
||||||
|
*/
|
||||||
|
GenFunc = g_eq;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_GE:
|
||||||
|
if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
|
||||||
|
ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin);
|
||||||
|
WarnConstCompareResult ();
|
||||||
|
RemoveCode (&Mark0);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_GT:
|
||||||
|
if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
|
||||||
|
ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin);
|
||||||
|
WarnConstCompareResult ();
|
||||||
|
RemoveCode (&Mark0);
|
||||||
|
goto Done;
|
||||||
|
} else if (!LeftSigned && Expr2.IVal == 0) {
|
||||||
|
/* We can replace this by a compare to zero, because
|
||||||
|
* the value of lhs may never be negative.
|
||||||
|
*/
|
||||||
|
GenFunc = g_ne;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Internal ("hie_compare: got token 0x%X\n", Tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the result is not already constant (as evaluated in the
|
||||||
|
* switch above), we can execute the operation as a char op,
|
||||||
|
* since the right side constant is in a valid range.
|
||||||
|
*/
|
||||||
|
flags |= (CF_CHAR | CF_FORCECHAR);
|
||||||
|
if (!LeftSigned) {
|
||||||
flags |= CF_UNSIGNED;
|
flags |= CF_UNSIGNED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (IsTypeChar (Expr->Type) && IsTypeChar (Expr2.Type) &&
|
||||||
|
GetSignedness (Expr->Type) == GetSignedness (Expr2.Type)) {
|
||||||
|
|
||||||
|
/* Both are chars with the same signedness. We can encode the
|
||||||
|
* operation as a char operation.
|
||||||
|
*/
|
||||||
|
flags |= CF_CHAR;
|
||||||
if (rconst) {
|
if (rconst) {
|
||||||
flags |= CF_FORCECHAR;
|
flags |= CF_FORCECHAR;
|
||||||
}
|
}
|
||||||
|
if (IsSignUnsigned (Expr->Type)) {
|
||||||
|
flags |= CF_UNSIGNED;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST);
|
unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST);
|
||||||
flags |= g_typeadjust (ltype, rtype);
|
flags |= g_typeadjust (ltype, rtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate code */
|
/* Generate code */
|
||||||
Gen->Func (flags, Expr2.IVal);
|
GenFunc (flags, Expr2.IVal);
|
||||||
|
|
||||||
/* The result is an rvalue in the primary */
|
/* The result is an rvalue in the primary */
|
||||||
ED_MakeRValExpr (Expr);
|
ED_MakeRValExpr (Expr);
|
||||||
@ -2055,7 +2183,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
/* Result type is always int */
|
/* Result type is always int */
|
||||||
Expr->Type = type_int;
|
Expr->Type = type_int;
|
||||||
|
|
||||||
/* Condition codes are set */
|
Done: /* Condition codes are set */
|
||||||
ED_TestDone (Expr);
|
ED_TestDone (Expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user