* src/z80/gen.c (aopPut, spillPairReg): fixed bug #800998
[fw/sdcc] / src / SDCCicode.c
index e4e54e7c68ea7121a7642fdb7e7e55b646e30416..36a4837e9c89a5b7b2c4b0eb77fea7bfaebada77 100644 (file)
@@ -121,6 +121,7 @@ iCodeTable codeTable[] =
 /* checkConstantRange: check a constant against the type           */
 /*-----------------------------------------------------------------*/
 
+
 /*   pedantic=0: allmost anything is allowed as long as the absolute
        value is within the bit range of the type, and -1 is treated as
        0xf..f for unsigned types (e.g. in assign)
@@ -996,7 +997,7 @@ isOperandOnStack (operand * op)
 /*-----------------------------------------------------------------*/
 /* operandLitValue - literal value of an operand                   */
 /*-----------------------------------------------------------------*/
-double 
+double
 operandLitValue (operand * op)
 {
   assert (isOperandLiteral (op));
@@ -1030,7 +1031,7 @@ iCode *getBuiltinParms (iCode *ic, int *pcount, operand **parms)
 }
 
 /*-----------------------------------------------------------------*/
-/* operandOperation - perforoms operations on operands             */
+/* operandOperation - performs operations on operands             */
 /*-----------------------------------------------------------------*/
 operand *
 operandOperation (operand * left, operand * right,
@@ -1043,7 +1044,7 @@ operandOperation (operand * left, operand * right,
   let = getSpec(operandType(left));
   if (right) {
     assert (isOperandLiteral (right));
-    ret = getSpec(operandType(left));
+    ret = getSpec(operandType(right));
   }
 
   switch (op)
@@ -1059,12 +1060,63 @@ operandOperation (operand * left, operand * right,
                                                 operandLitValue (right)));
       break;
     case '*':
+      /*
       retval = operandFromValue (valCastLiteral (type,
                                                 operandLitValue (left) *
                                                 operandLitValue (right)));
+      This could be all we've to do, but with gcc we've to take care about
+      overflows. Two examples:
+      ULONG_MAX * ULONG_MAX doesn't fit into a double, some of the least
+      significant bits are lost (52 in fraction, 63 bits would be
+      necessary to keep full precision).
+      If the resulting double value is greater than ULONG_MAX (resp.
+      USHRT_MAX, ...), then 0 will be assigned to v_ulong (resp. u_uint, ...)!
+      */
+
+      /* if it is not a specifier then we can assume that */
+      /* it will be an unsigned long                      */
+      if (IS_INT (type) ||
+          !IS_SPEC (type))
+        {
+         /* long is handled here, because it can overflow with double */
+         if (SPEC_LONG (type) ||
+             !IS_SPEC (type))
+         /* signed and unsigned mul are the same, as long as the precision
+            of the result isn't bigger than the precision of the operands. */
+           retval = operandFromValue (valCastLiteral (type,
+                    (TYPE_UDWORD) operandLitValue (left) *
+                    (TYPE_UDWORD) operandLitValue (right)));
+         else if (SPEC_USIGN (type)) /* unsigned int */
+           {
+             /* unsigned int is handled here in order to detect overflow */
+             TYPE_UDWORD ul = (TYPE_UWORD) operandLitValue (left) *
+                              (TYPE_UWORD) operandLitValue (right);
+
+             retval = operandFromValue (valCastLiteral (type, (TYPE_UWORD) ul));
+             if (!options.lessPedantic &&
+                 ul != (TYPE_UWORD) ul)
+               werror (W_INT_OVL);
+           }
+         else /* signed int */
+           {
+             /* signed int is handled here in order to detect overflow */
+             TYPE_DWORD l = (TYPE_WORD) operandLitValue (left) *
+                            (TYPE_WORD) operandLitValue (right);
+
+             retval = operandFromValue (valCastLiteral (type, (TYPE_WORD) l));
+             if (!options.lessPedantic &&
+                 l != (TYPE_WORD) l)
+               werror (W_INT_OVL);
+           }
+       }
+      else
+       /* all others go here: */
+       retval = operandFromValue (valCastLiteral (type,
+                                                  operandLitValue (left) *
+                                                  operandLitValue (right)));
       break;
     case '/':
-      if ((unsigned long) operandLitValue (right) == 0)
+      if ((TYPE_UDWORD) operandLitValue (right) == 0)
        {
          werror (E_DIVIDE_BY_ZERO);
          retval = right;
@@ -1076,51 +1128,57 @@ operandOperation (operand * left, operand * right,
                                                   operandLitValue (right)));
       break;
     case '%':
-      if ((unsigned long) operandLitValue (right) == 0) {
+      if ((TYPE_UDWORD) operandLitValue (right) == 0) {
          werror (E_DIVIDE_BY_ZERO);
          retval = right;
       }
       else
-       retval = operandFromLit ((SPEC_USIGN(let) ?
-                                 (unsigned long) operandLitValue (left) :
-                                 (long) operandLitValue (left)) %
-                                (SPEC_USIGN(ret) ?
-                                 (unsigned long) operandLitValue (right) :
-                                 (long) operandLitValue (right)));
-
+        {
+          if (SPEC_USIGN(let) || SPEC_USIGN(ret))
+           /* one of the operands is unsigned */
+           retval = operandFromLit ((TYPE_UDWORD) operandLitValue (left) %
+                                    (TYPE_UDWORD) operandLitValue (right));
+         else
+           /* both operands are signed */
+           retval = operandFromLit ((TYPE_DWORD) operandLitValue (left) %
+                                    (TYPE_DWORD) operandLitValue (right));
+        }
       break;
     case LEFT_OP:
-      retval = operandFromLit ((SPEC_USIGN(let) ?
-                                 (unsigned long) operandLitValue (left) :
-                                 (long) operandLitValue (left)) <<
-                                (SPEC_USIGN(ret) ?
-                                 (unsigned long) operandLitValue (right) :
-                                 (long) operandLitValue (right)));
+      /* The number of left shifts is always unsigned. Signed doesn't make
+        sense here. Shifting by a negative number is impossible. */
+      retval = operandFromLit ((TYPE_UDWORD) operandLitValue (left) <<
+                              (TYPE_UDWORD) operandLitValue (right));
       break;
-    case RIGHT_OP: {
-      double lval = operandLitValue(left), rval = operandLitValue(right);
-      double res=0;
-      switch ((SPEC_USIGN(let) ? 2 : 0) + (SPEC_USIGN(ret) ? 1 : 0))
-       {
-       case 0: // left=unsigned right=unsigned
-         res=(unsigned long)lval >> (unsigned long)rval;
-         break;
-       case 1: // left=unsigned right=signed
-         res=(unsigned long)lval >> (signed long)rval;
-         break;
-       case 2: // left=signed right=unsigned
-         res=(signed long)lval >> (unsigned long)rval;
-         break;
-       case 3: // left=signed right=signed
-         res=(signed long)lval >> (signed long)rval;
-         break;
-       }
-      retval = operandFromLit (res);
+    case RIGHT_OP:
+      /* The number of right shifts is always unsigned. Signed doesn't make
+        sense here. Shifting by a negative number is impossible. */
+      if (SPEC_USIGN(let))
+        /* unsigned: logic shift right */
+        retval = operandFromLit ((TYPE_UDWORD) operandLitValue (left) >>
+                                (TYPE_UDWORD) operandLitValue (right));
+      else
+        /* signed: arithmetic shift right */
+        retval = operandFromLit ((TYPE_DWORD ) operandLitValue (left) >>
+                                (TYPE_UDWORD) operandLitValue (right));
       break;
-    }
     case EQ_OP:
-      retval = operandFromLit (operandLitValue (left) ==
-                              operandLitValue (right));
+      /* this op doesn't care about signedness */
+      {
+       TYPE_UDWORD l, r;
+
+       l = (TYPE_UDWORD) operandLitValue (left);
+       if (SPEC_NOUN(OP_VALUE(left)->type) == V_CHAR)
+         l &= 0xff;
+       else if (!SPEC_LONG (OP_VALUE(left)->type))
+         l &= 0xffff;
+       r = (TYPE_UDWORD) operandLitValue (right);
+       if (SPEC_NOUN(OP_VALUE(right)->type) == V_CHAR)
+         r &= 0xff;
+       else if (!SPEC_LONG (OP_VALUE(right)->type))
+         r &= 0xffff;
+       retval = operandFromLit (l == r);
+      }
       break;
     case '<':
       retval = operandFromLit (operandLitValue (left) <
@@ -1143,16 +1201,19 @@ operandOperation (operand * left, operand * right,
                               operandLitValue (right));
       break;
     case BITWISEAND:
-      retval = operandFromLit ((unsigned long)operandLitValue(left) & 
-                              (unsigned long)operandLitValue(right));
+      retval = operandFromValue (valCastLiteral (type,
+                                                 (TYPE_UDWORD)operandLitValue(left) &
+                                                (TYPE_UDWORD)operandLitValue(right)));
       break;
     case '|':
-      retval = operandFromLit ((unsigned long)operandLitValue (left) |
-                              (unsigned long)operandLitValue (right));
+      retval = operandFromValue (valCastLiteral (type,
+                                                 (TYPE_UDWORD)operandLitValue(left) |
+                                                (TYPE_UDWORD)operandLitValue(right)));
       break;
     case '^':
-      retval = operandFromLit ((unsigned long)operandLitValue (left) ^
-                              (unsigned long)operandLitValue (right));
+      retval = operandFromValue (valCastLiteral (type,
+                                                 (TYPE_UDWORD)operandLitValue(left) ^
+                                                (TYPE_UDWORD)operandLitValue(right)));
       break;
     case AND_OP:
       retval = operandFromLit (operandLitValue (left) &&
@@ -1164,7 +1225,7 @@ operandOperation (operand * left, operand * right,
       break;
     case RRC:
       {
-       unsigned long i = (unsigned long) operandLitValue (left);
+       TYPE_UDWORD i = (TYPE_UDWORD) operandLitValue (left);
 
        retval = operandFromLit ((i >> (getSize (operandType (left)) * 8 - 1)) |
                                 (i << 1));
@@ -1172,7 +1233,7 @@ operandOperation (operand * left, operand * right,
       break;
     case RLC:
       {
-       unsigned long i = (unsigned long) operandLitValue (left);
+       TYPE_UDWORD i = (TYPE_UDWORD) operandLitValue (left);
 
        retval = operandFromLit ((i << (getSize (operandType (left)) * 8 - 1)) |
                                 (i >> 1));
@@ -1180,11 +1241,12 @@ operandOperation (operand * left, operand * right,
       break;
 
     case UNARYMINUS:
-      retval = operandFromLit (-1 * operandLitValue (left));
+      retval = operandFromValue (valCastLiteral (type,
+                                                 -1 * operandLitValue (left)));
       break;
 
     case '~':
-      retval = operandFromLit (~((unsigned long) operandLitValue (left)));
+      retval = operandFromLit (~((TYPE_UDWORD) operandLitValue (left)));
       break;
 
     case '!':
@@ -1204,7 +1266,7 @@ operandOperation (operand * left, operand * right,
 /*-----------------------------------------------------------------*/
 /* isOperandEqual - compares two operand & return 1 if they r =    */
 /*-----------------------------------------------------------------*/
-int 
+int
 isOperandEqual (operand * left, operand * right)
 {
   /* if the pointers are equal then they are equal */
@@ -1882,11 +1944,11 @@ geniCodeMultiply (operand * left, operand * right,int resultIsInt)
 
   /* if the right is a literal & power of 2 */
   /* then make it a left shift              */
-  /* code generated for 1 byte * 1 byte literal = 2 bytes result is more 
-     efficient in most cases than 2 bytes result = 2 bytes << literal 
+  /* code generated for 1 byte * 1 byte literal = 2 bytes result is more
+     efficient in most cases than 2 bytes result = 2 bytes << literal
      if port has 1 byte muldiv */
   if (p2 && !IS_FLOAT (letype) &&
-      !((resultIsInt) && (getSize (resType) != getSize (ltype)) && 
+      !((resultIsInt) && (getSize (resType) != getSize (ltype)) &&
        (port->support.muldiv == 1)))
     {
       if ((resultIsInt) && (getSize (resType) != getSize (ltype)))
@@ -1927,8 +1989,8 @@ geniCodeDivision (operand * left, operand * right)
 
   resType = usualBinaryConversions (&left, &right);
 
-  /* if the right is a literal & power of 2 
-     and left is unsigned then make it a    
+  /* if the right is a literal & power of 2
+     and left is unsigned then make it a
      right shift */
   if (IS_LITERAL (retype) &&
       !IS_FLOAT (letype) &&
@@ -2648,7 +2710,7 @@ geniCodeLogic (operand * left, operand * right, int op)
      check if the literal value is within bounds */
   if (IS_INTEGRAL (ltype) && IS_VALOP (right) && IS_LITERAL (rtype))
     {
-      checkConstantRange(ltype, 
+      checkConstantRange(ltype,
                         OP_VALUE(right), "compare operation", 1);
     }
 
@@ -3230,7 +3292,7 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
 /*-----------------------------------------------------------------*/
 /* geniCodeSwitch - changes a switch to a if statement             */
 /*-----------------------------------------------------------------*/
-void 
+void
 geniCodeSwitch (ast * tree,int lvl)
 {
   iCode *ic;
@@ -3575,11 +3637,11 @@ ast2iCode (ast * tree,int lvl)
 #endif
 
     case '~':
-    case '!':
     case RRC:
     case RLC:
       return geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op);
 
+    case '!':
     case GETHBIT:
       {
        operand *op = geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op);
@@ -3594,9 +3656,21 @@ ast2iCode (ast * tree,int lvl)
     case NE_OP:
     case AND_OP:
     case OR_OP:
+      /* different compilers (even different gccs) evaluate
+        the two calls in a different order. to get the same
+        result on all machines we've to specify a clear sequence.
       return geniCodeLogic (geniCodeRValue (left, FALSE),
-                           geniCodeRValue (right, FALSE),
-                           tree->opval.op);
+                            geniCodeRValue (right, FALSE),
+                            tree->opval.op);
+      */
+      {
+       operand *leftOp, *rightOp;
+
+       rightOp = geniCodeRValue (right, FALSE);
+       leftOp  = geniCodeRValue (left , FALSE);
+
+       return geniCodeLogic (leftOp, rightOp, tree->opval.op);
+      }
     case '?':
       return geniCodeConditional (tree,lvl);