- /* Remember the operator token, then skip it */
- tok = CurTok.Tok;
- NextToken ();
-
- /* Get the lhs on stack */
- GetCodePos (&Mark1);
- ltype = TypeOf (Expr->Type);
- if (ED_IsConstAbs (Expr)) {
- /* Constant value */
- GetCodePos (&Mark2);
- g_push (ltype | CF_CONST, Expr->IVal);
- } else {
- /* Value not constant */
- LoadExpr (CF_NONE, Expr);
- GetCodePos (&Mark2);
- g_push (ltype, 0);
- }
-
- /* Get the right hand side */
- rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0);
-
- /* Make sure, the types are compatible */
- if (IsClassInt (Expr->Type)) {
- if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) {
- Error ("Incompatible types");
- }
- } else if (IsClassPtr (Expr->Type)) {
- if (IsClassPtr (Expr2.Type)) {
- /* Both pointers are allowed in comparison if they point to
- * the same type, or if one of them is a void pointer.
- */
- type* left = Indirect (Expr->Type);
- type* right = Indirect (Expr2.Type);
- if (TypeCmp (left, right) < TC_EQUAL && *left != T_VOID && *right != T_VOID) {
- /* Incomatible pointers */
- Error ("Incompatible types");
- }
- } else if (!ED_IsNullPtr (&Expr2)) {
- Error ("Incompatible types");
- }
- }
-
- /* Check for const operands */
- if (ED_IsConstAbs (Expr) && rconst) {
-
- /* Both operands are constant, remove the generated code */
- RemoveCode (&Mark1);
-
- /* Evaluate the result */
- Expr->IVal = kcalc (tok, Expr->IVal, Expr2.IVal);
-
- } else {
-
- /* If the right hand side is constant, and the generator function
- * expects the lhs in the primary, remove the push of the primary
- * now.
- */
- unsigned flags = 0;
- if (rconst) {
- flags |= CF_CONST;
- if ((Gen->Flags & GEN_NOPUSH) != 0) {
- RemoveCode (&Mark2);
- ltype |= CF_REG; /* Value is in register */
- }
- }
-
- /* Determine the type of the operation result. If the left
- * operand is of type char and the right is a constant, or
- * if both operands are of type char, we will encode the
- * operation as char operation. Otherwise the default
- * promotions are used.
- */
- if (IsTypeChar (Expr->Type) && (IsTypeChar (Expr2.Type) || rconst)) {
- flags |= CF_CHAR;
- if (IsSignUnsigned (Expr->Type) || IsSignUnsigned (Expr2.Type)) {
- flags |= CF_UNSIGNED;
- }
- if (rconst) {
- flags |= CF_FORCECHAR;
- }
- } else {
- unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST);
- flags |= g_typeadjust (ltype, rtype);
- }
-
- /* Generate code */
- Gen->Func (flags, Expr2.IVal);
+ /* Remember the generator function */
+ void (*GenFunc) (unsigned, unsigned long) = Gen->Func;
+
+ /* Remember the operator token, then skip it */
+ Tok = CurTok.Tok;
+ NextToken ();
+
+ /* If lhs is a function, convert it to pointer to function */
+ if (IsTypeFunc (Expr->Type)) {
+ Expr->Type = PointerTo (Expr->Type);
+ }
+
+ /* Get the lhs on stack */
+ GetCodePos (&Mark1);
+ ltype = TypeOf (Expr->Type);
+ if (ED_IsConstAbs (Expr)) {
+ /* Constant value */
+ GetCodePos (&Mark2);
+ g_push (ltype | CF_CONST, Expr->IVal);
+ } else {
+ /* Value not constant */
+ LoadExpr (CF_NONE, Expr);
+ GetCodePos (&Mark2);
+ g_push (ltype, 0);
+ }
+
+ /* Get the right hand side */
+ MarkedExprWithCheck (hienext, &Expr2);
+
+ /* If rhs is a function, convert it to pointer to function */
+ if (IsTypeFunc (Expr2.Type)) {
+ Expr2.Type = PointerTo (Expr2.Type);
+ }
+
+ /* Check for a constant expression */
+ rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2));
+ if (!rconst) {
+ /* Not constant, load into the primary */
+ LoadExpr (CF_NONE, &Expr2);
+ }
+
+ /* Some operations aren't allowed on function pointers */
+ if ((Gen->Flags & GEN_NOFUNC) != 0) {
+ /* Output only one message even if both sides are wrong */
+ if (IsTypeFuncPtr (Expr->Type)) {
+ Error ("Invalid left operand for relational operator");
+ /* Avoid further errors */
+ ED_MakeConstAbsInt (Expr, 0);
+ ED_MakeConstAbsInt (&Expr2, 0);
+ } else if (IsTypeFuncPtr (Expr2.Type)) {
+ Error ("Invalid right operand for relational operator");
+ /* Avoid further errors */
+ ED_MakeConstAbsInt (Expr, 0);
+ ED_MakeConstAbsInt (&Expr2, 0);
+ }
+ }
+
+ /* Make sure, the types are compatible */
+ if (IsClassInt (Expr->Type)) {
+ if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) {
+ Error ("Incompatible types");
+ }
+ } else if (IsClassPtr (Expr->Type)) {
+ if (IsClassPtr (Expr2.Type)) {
+ /* Both pointers are allowed in comparison if they point to
+ ** the same type, or if one of them is a void pointer.
+ */
+ Type* left = Indirect (Expr->Type);
+ Type* right = Indirect (Expr2.Type);
+ if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) {
+ /* Incompatible pointers */
+ Error ("Incompatible types");
+ }
+ } else if (!ED_IsNullPtr (&Expr2)) {
+ Error ("Incompatible types");
+ }
+ }
+
+ /* Check for const operands */
+ if (ED_IsConstAbs (Expr) && rconst) {
+
+ /* If the result is constant, this is suspicious when not in
+ ** preprocessor mode.
+ */
+ WarnConstCompareResult ();
+
+ /* Both operands are constant, remove the generated code */
+ RemoveCode (&Mark1);
+
+ /* Determine if this is a signed or unsigned compare */
+ if (IsClassInt (Expr->Type) && IsSignSigned (Expr->Type) &&
+ IsClassInt (Expr2.Type) && IsSignSigned (Expr2.Type)) {
+
+ /* Evaluate the result for signed operands */
+ signed long Val1 = Expr->IVal;
+ signed long Val2 = Expr2.IVal;
+ switch (Tok) {
+ case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
+ case TOK_NE: Expr->IVal = (Val1 != Val2); break;
+ case TOK_LT: Expr->IVal = (Val1 < Val2); break;
+ case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
+ case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
+ case TOK_GT: Expr->IVal = (Val1 > Val2); break;
+ default: Internal ("hie_compare: got token 0x%X\n", Tok);
+ }
+
+ } else {
+
+ /* Evaluate the result for unsigned operands */
+ unsigned long Val1 = Expr->IVal;
+ unsigned long Val2 = Expr2.IVal;
+ switch (Tok) {
+ case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
+ case TOK_NE: Expr->IVal = (Val1 != Val2); break;
+ case TOK_LT: Expr->IVal = (Val1 < Val2); break;
+ case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
+ case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
+ case TOK_GT: Expr->IVal = (Val1 > Val2); break;
+ default: Internal ("hie_compare: got token 0x%X\n", Tok);
+ }
+ }
+
+ } else {
+
+ /* Determine the signedness of the operands */
+ int LeftSigned = IsSignSigned (Expr->Type);
+ int RightSigned = IsSignSigned (Expr2.Type);
+
+ /* If the right hand side is constant, and the generator function
+ ** expects the lhs in the primary, remove the push of the primary
+ ** now.
+ */
+ unsigned flags = 0;
+ if (rconst) {
+ flags |= CF_CONST;
+ if ((Gen->Flags & GEN_NOPUSH) != 0) {
+ RemoveCode (&Mark2);
+ ltype |= CF_REG; /* Value is in register */
+ }
+ }
+
+ /* Determine the type of the operation. */
+ if (IsTypeChar (Expr->Type) && rconst) {
+
+ /* Left side is unsigned char, right side is constant.
+ ** 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 (!RightSigned && Expr2.IVal < 0) {
+ /* Correct the value so it is an unsigned. It will then
+ ** anyway match one of the cases below.
+ */
+ Expr2.IVal = LeftMax + 1;
+ }
+
+ /* Comparing a char against a constant may have a constant
+ ** result. Please note: It is not possible to remove the code
+ ** for the compare alltogether, because it may have side
+ ** effects.
+ */
+ switch (Tok) {
+
+ case TOK_EQ:
+ if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
+ ED_MakeConstAbsInt (Expr, 0);
+ WarnConstCompareResult ();
+ goto Done;
+ }
+ break;
+
+ case TOK_NE:
+ if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
+ ED_MakeConstAbsInt (Expr, 1);
+ WarnConstCompareResult ();
+ goto Done;
+ }
+ break;
+
+ case TOK_LT:
+ if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
+ ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax);
+ WarnConstCompareResult ();
+ goto Done;
+ }
+ break;
+
+ case TOK_LE:
+ if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
+ ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax);
+ WarnConstCompareResult ();
+ goto Done;
+ }
+ break;
+
+ case TOK_GE:
+ if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
+ ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin);
+ WarnConstCompareResult ();
+ goto Done;
+ }
+ break;
+
+ case TOK_GT:
+ if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
+ ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin);
+ WarnConstCompareResult ();
+ goto Done;
+ }
+ 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;
+ }
+
+ } 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) {
+ flags |= CF_FORCECHAR;
+ }
+ if (!LeftSigned) {
+ flags |= CF_UNSIGNED;
+ }
+ } else {
+ unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST);
+ flags |= g_typeadjust (ltype, rtype);
+ }
+
+ /* If the left side is an unsigned and the right is a constant,
+ ** we may be able to change the compares to something more
+ ** effective.
+ */
+ if (!LeftSigned && rconst) {
+
+ switch (Tok) {
+
+ case TOK_LT:
+ if (Expr2.IVal == 1) {
+ /* An unsigned compare to one means that the value
+ ** must be zero.
+ */
+ GenFunc = g_eq;
+ Expr2.IVal = 0;
+ }
+ break;
+
+ case TOK_LE:
+ if (Expr2.IVal == 0) {
+ /* An unsigned compare to zero means that the value
+ ** must be zero.
+ */
+ GenFunc = g_eq;
+ }
+ break;
+
+ case TOK_GE:
+ if (Expr2.IVal == 1) {
+ /* An unsigned compare to one means that the value
+ ** must not be zero.
+ */
+ GenFunc = g_ne;
+ Expr2.IVal = 0;
+ }
+ break;
+
+ case TOK_GT:
+ if (Expr2.IVal == 0) {
+ /* An unsigned compare to zero means that the value
+ ** must not be zero.
+ */
+ GenFunc = g_ne;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ /* Generate code */
+ GenFunc (flags, Expr2.IVal);