* src/SDCCcse.c (algebraicOpts): fix bug converting op from value to type
authorbernhardheld <bernhardheld@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Wed, 13 Aug 2003 20:10:57 +0000 (20:10 +0000)
committerbernhardheld <bernhardheld@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Wed, 13 Aug 2003 20:10:57 +0000 (20:10 +0000)
* src/SDCCicode.c (operandOperation): rewritten some ops (*, ==, unary_minus) to fix possible overflows and to accord with ANSI
* src/SDCCsymt.c (computeType): literals are handled the same way as any other type
* src/SDCCval.c (cheapestVal): removed, it doesn't accord with ANSI (can be re-activated by defining REDUCE_LITERALS)
* src/SDCCval.c (constVal): fixed; hex and octal constants can be unsigned, but are signed by default
* src/SDCCval.c (constVal): rearranged
* src/SDCCval.c (valMod): preliminary fix
* src/SDCCval.c (valCastLiteral): use TYPE_* types
* support/regression/literalop.c: added, work in progress

git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@2825 4a8a32a2-be11-0410-ad9d-d568d2c75423

ChangeLog
src/SDCCcse.c
src/SDCCicode.c
src/SDCCsymt.c
src/SDCCval.c
support/regression/tests/literalop.c [new file with mode: 0644]

index b1fb8c309e3e03eff1db3d7c10634718208fb418..cb3c009fef9e3ad66f8226613bc10907abf77475 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2003-08-13  Bernhard Held <bernhard@bernhardheld.de>
+
+       * src/SDCCcse.c (algebraicOpts): fix bug converting op from value to type
+       * src/SDCCicode.c (operandOperation): rewritten some ops
+       (*, ==, unary_minus) to fix possible overflows and to accord with ANSI
+       * src/SDCCsymt.c (computeType): literals are handled the same way as any
+       other type
+       * src/SDCCval.c (cheapestVal): removed, it doesn't accord with ANSI (can
+       be re-activated by defining REDUCE_LITERALS)
+       * src/SDCCval.c (constVal): fixed; hex and octal constants can be
+       unsigned, but are signed by default
+       * src/SDCCval.c (constVal): rearranged
+       * src/SDCCval.c (valMod): preliminary fix
+       * src/SDCCval.c (valCastLiteral): use TYPE_* types
+       * support/regression/literalop.c: added, work in progress
+
 2003-08-12  Erik Petrich <epetrich@ivorytower.norman.ok.us>
 
        Generate warnings for useless declarations like "char data;"
@@ -9,7 +25,7 @@
 
 2003-08-09  Bernhard Held <bernhard@bernhardheld.de>
 
-       * src/SDCCval.c (valMult): fixex overflow detection of negativ int
+       * src/SDCCval.c (valMult): fix overflow detection of negative int
 
 2003-08-07  Erik Petrich <epetrich@ivorytower.norman.ok.us>
 
index 32badbcc36cbc60151fc12144d3c66f81a96d669..3c9c205cd355fdebe629e43bccd4b34c5e776b5f 100644 (file)
@@ -83,8 +83,8 @@ pcseDef (void *item, va_list ap)
 
 void ReplaceOpWithCheaperOp(operand **op, operand *cop) {
 #ifdef RANGEHUNT
-  printf ("ReplaceOpWithCheaperOp %s with %s: ", 
-         IS_SYMOP((*op)) ? OP_SYMBOL((*op))->name : "!SYM", 
+  printf ("ReplaceOpWithCheaperOp %s with %s: ",
+         IS_SYMOP((*op)) ? OP_SYMBOL((*op))->name : "!SYM",
          IS_SYMOP(cop) ? OP_SYMBOL(cop)->name : "!SYM");
   // if op is a register equivalent
   if (IS_ITEMP(cop) && OP_SYMBOL((*op))->isreqv) {
@@ -107,7 +107,7 @@ void ReplaceOpWithCheaperOp(operand **op, operand *cop) {
 /* replaceAllSymBySym - replaces all operands by operand in an     */
 /*                      instruction chain                          */
 /*-----------------------------------------------------------------*/
-void 
+void
 replaceAllSymBySym (iCode * ic, operand * from, operand * to, bitVect ** ndpset)
 {
   iCode *lic;
@@ -325,8 +325,8 @@ DEFSETFUNC (findCheaperOp)
       IS_ITEMP (IC_RESULT (cdp->diCode)))
     *opp = IC_RESULT (cdp->diCode);
 
-  if ((*opp) && 
-      (isOperandLiteral(*opp) || !checkSign || 
+  if ((*opp) &&
+      (isOperandLiteral(*opp) || !checkSign ||
        (checkSign &&
        IS_SPEC(operandType (cop)) && IS_SPEC(operandType (*opp)) &&
        (SPEC_USIGN(operandType (cop))==SPEC_USIGN(operandType (*opp)) &&
@@ -353,11 +353,11 @@ DEFSETFUNC (findCheaperOp)
          *opp = operandFromOperand (*opp);
          (*opp)->isaddr = cop->isaddr;
        }
-         
+
       if (IS_SPEC(operandType (cop)) && IS_SPEC(operandType (*opp)) &&
          SPEC_NOUN(operandType(cop)) != SPEC_NOUN(operandType(*opp)))
        {
-           // special case: we can make an unsigned char literal 
+           // special case: we can make an unsigned char literal
            // into an int literal with no cost.
            if (isOperandLiteral(*opp)
             && SPEC_NOUN(operandType(*opp)) == V_CHAR
@@ -372,9 +372,9 @@ DEFSETFUNC (findCheaperOp)
                *opp = NULL;
                return 0;
            }
-           
+
         }
-         
+
       return 1;
 
     }
@@ -517,7 +517,7 @@ DEFSETFUNC (ifOperandsHave)
 /*-----------------------------------------------------------------*/
 /* ifDefSymIs - if a definition is found in the set                */
 /*-----------------------------------------------------------------*/
-int 
+int
 ifDefSymIs (set * cseSet, operand * sym)
 {
   cseDef *loop;
@@ -554,7 +554,7 @@ DEFSETFUNC (ifDefSymIsX)
 /*-----------------------------------------------------------------*/
 /* ifDiCodeIs - returns truw if diCode is same                     */
 /*-----------------------------------------------------------------*/
-int 
+int
 ifDiCodeIs (set * cseSet, iCode * ic)
 {
   cseDef *loop;
@@ -825,6 +825,7 @@ algebraicOpts (iCode * ic, eBBlock * ebp)
                {
                  ic->op = CAST;
                  IC_LEFT (ic)->type = TYPE;
+                 IC_LEFT (ic)->isLiteral = 0;
                  setOperandType (IC_LEFT (ic), operandType (IC_RESULT (ic)));
                }
              return;
@@ -863,6 +864,7 @@ algebraicOpts (iCode * ic, eBBlock * ebp)
                  IC_RIGHT (ic) = IC_LEFT (ic);
                  IC_LEFT (ic) = op;
                  IC_LEFT (ic)->type = TYPE;
+                 IC_LEFT (ic)->isLiteral = 0;
                  setOperandType (IC_LEFT (ic), operandType (IC_RESULT (ic)));
                }
              return;
@@ -1783,7 +1785,7 @@ cseBBlock (eBBlock * ebb, int computeOnly,
          /* update the spill location for this */
          updateSpillLocation (ic,0);
 
-         if (POINTER_SET (ic) && 
+         if (POINTER_SET (ic) &&
              !(IS_BITFIELD (OP_SYMBOL (IC_RESULT (ic))->etype)))
            {
              pdop = NULL;
@@ -1854,7 +1856,7 @@ cseBBlock (eBBlock * ebb, int computeOnly,
            change = 1;
          }
        }
-       
+
       /* if left or right changed then do algebraic */
       if (!computeOnly && change)
        {
@@ -1889,15 +1891,15 @@ cseBBlock (eBBlock * ebb, int computeOnly,
          if (pdic && compareType (operandType (IC_RESULT (pdic)),
                                 operandType (IC_RESULT (ic))) != 1)
            pdic = NULL;
-         if (pdic && port->cseOk && (*port->cseOk)(ic,pdic) == 0) 
+         if (pdic && port->cseOk && (*port->cseOk)(ic,pdic) == 0)
              pdic = NULL;
        }
 
       /* Alternate code */
       if (pdic && IS_ITEMP(IC_RESULT(ic))) {
        if (POINTER_GET(ic) && bitVectBitValue(ebb->ptrsSet,IC_LEFT(ic)->key)) {
-         /* Mmm, found an equivalent pointer get at a lower level. 
-            This could be a loop however with the same pointer set 
+         /* Mmm, found an equivalent pointer get at a lower level.
+            This could be a loop however with the same pointer set
             later on */
        } else {
          /* if previous definition found change this to an assignment */
@@ -1905,7 +1907,7 @@ cseBBlock (eBBlock * ebb, int computeOnly,
          IC_LEFT(ic) = NULL;
          IC_RIGHT(ic) = operandFromOperand(IC_RESULT(pdic));
          SET_ISADDR(IC_RESULT(ic),0);
-         SET_ISADDR(IC_RIGHT (ic),0);    
+         SET_ISADDR(IC_RIGHT (ic),0);
        }
       }
 
index d3b6298114c79b33d4bcc824332bc4cc475a05c4..eac7ec101b03bae495ee0353fc33b12be159b045 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,
@@ -1059,13 +1060,60 @@ operandOperation (operand * left, operand * right,
                                                 operandLitValue (right)));
       break;
     case '*':
+      /*
       retval = operandFromValue (valCastLiteral (type,
                                                 operandLitValue (left) *
                                                 operandLitValue (right)));
-      if (!options.lessPedantic &&
-         !IS_FLOAT (OP_VALUE(retval)->type) &&
-         !SPEC_LONG (OP_VALUE(retval)->type))
-        ; /* TODO: werror (W_INT_OVL) */
+      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 /* int */
+           {
+             /* 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 ((TYPE_UDWORD) operandLitValue (right) == 0)
@@ -1102,7 +1150,7 @@ operandOperation (operand * left, operand * right,
       retval = operandFromLit ((TYPE_UDWORD) operandLitValue (left) <<
                               (TYPE_UDWORD) operandLitValue (right));
       break;
-    case RIGHT_OP: {
+    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))
@@ -1114,10 +1162,23 @@ operandOperation (operand * left, operand * 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) <
@@ -1180,7 +1241,8 @@ operandOperation (operand * left, operand * right,
       break;
 
     case UNARYMINUS:
-      retval = operandFromLit (-1 * operandLitValue (left));
+      retval = operandFromValue (valCastLiteral (type,
+                                                 -1 * 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)))
@@ -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;
index c085bc09f2766a2cd5e15c16c2ac64ca71dbbe55..7b3b6f584df7c4e99041aa8523d06b735667f87a 100644 (file)
@@ -1416,13 +1416,13 @@ computeType (sym_link * type1, sym_link * type2)
   reType = getSpec (rType);
 
   /* if either of them unsigned but not val then make this unsigned */
-  if (((!IS_LITERAL(type1) && SPEC_USIGN (etype1)) || 
-       (!IS_LITERAL(type2) && SPEC_USIGN (etype2))) && 
+  if (((/*!IS_LITERAL(type1) &&*/ SPEC_USIGN (etype1)) ||
+       (/*!IS_LITERAL(type2) &&*/ SPEC_USIGN (etype2))) &&
       !IS_FLOAT (reType))
     SPEC_USIGN (reType) = 1;
   else
     SPEC_USIGN (reType) = 0;
-  
+
   /* if result is a literal then make not so */
   if (IS_LITERAL (reType))
     SPEC_SCLS (reType) = S_REGISTER;
@@ -1433,7 +1433,7 @@ computeType (sym_link * type1, sym_link * type2)
 /*--------------------------------------------------------------------*/
 /* compareType - will do type check return 1 if match, -1 if castable */
 /*--------------------------------------------------------------------*/
-int 
+int
 compareType (sym_link * dest, sym_link * src)
 {
   if (!dest && !src)
index 62ffcec2a1670ff07d3443ab3fc7a03778b6d5b8..5d95986e21480e0eaf0d3489029791013fb554fd 100644 (file)
@@ -228,7 +228,7 @@ copyIlist (initList * src)
 /*------------------------------------------------------------------*/
 /* list2int - converts the first element of the list to value       */
 /*------------------------------------------------------------------*/
-double 
+double
 list2int (initList * val)
 {
   initList *i = val;
@@ -315,6 +315,7 @@ symbolVal (symbol * sym)
   return val;
 }
 
+#if defined(REDUCE_LITERALS)
 /*--------------------------------------------------------------------*/
 /* cheapestVal - convert a val to the cheapest as possible value      */
 /*--------------------------------------------------------------------*/
@@ -368,6 +369,7 @@ static value *cheapestVal (value *val) {
   }
   return val;
 }
+#endif
 
 /*-----------------------------------------------------------------*/
 /* valueFromLit - creates a value from a literal                   */
@@ -453,7 +455,6 @@ value *constVal (char *s)
     unsigned long sval;
     sscanf (s, scanFmt, &sval);
     dval=sval;
-    SPEC_USIGN (val->type) = 1;
   } else {
     sscanf (s, scanFmt, &dval);
   }
@@ -482,13 +483,26 @@ value *constVal (char *s)
       SPEC_NOUN (val->type) = V_INT;
     }
     else if (dval>0x7f && !SPEC_USIGN (val->type)) { // check if we have to promote to int
-      SPEC_NOUN (val->type) = V_INT;
+      if ((hex || octal) && /* hex or octal constants may be stored in unsigned type */
+          dval<=0xff) {
+        SPEC_USIGN (val->type) = 1;
+      } else {
+         SPEC_NOUN (val->type) = V_INT;
+      }
     }
     if (dval>0xffff && SPEC_USIGN (val->type)) { // check if we have to promote to long
       SPEC_LONG (val->type) = 1;
     }
     else if (dval>0x7fff && !SPEC_USIGN (val->type)) { // check if we have to promote to long int
-      SPEC_LONG (val->type) = 1;
+      if ((hex || octal) && /* hex or octal constants may be stored in unsigned type */
+          dval<=0xffff) {
+        SPEC_USIGN (val->type) = 1;
+      } else {
+        SPEC_LONG (val->type) = 1;
+        if (dval>0x7fffffff) {
+          SPEC_USIGN (val->type) = 1;
+       }
+      }
     }
   }
 
@@ -527,7 +541,7 @@ unsigned char hexEscape(char **src)
 {
   char *s ;
   unsigned long value ;
-  
+
   (*src)++ ;   /* Skip over the 'x' */
   s = *src ;   /* Save for error detection */
   
@@ -869,7 +883,7 @@ valFromType (sym_link * type)
 /*------------------------------------------------------------------*/
 /* floatFromVal - value to double float conversion                  */
 /*------------------------------------------------------------------*/
-double 
+double
 floatFromVal (value * val)
 {
   if (!val)
@@ -896,7 +910,7 @@ floatFromVal (value * val)
       else
        return (double) SPEC_CVAL (val->etype).v_long;
     }
-  
+
   if (SPEC_NOUN (val->etype) == V_INT) {
     if (SPEC_USIGN (val->etype))
       return (double) SPEC_CVAL (val->etype).v_uint;
@@ -925,7 +939,6 @@ floatFromVal (value * val)
   return 0;
 }
 
-
 /*------------------------------------------------------------------*/
 /* valUnaryPM - does the unary +/- operation on a constant          */
 /*------------------------------------------------------------------*/
@@ -1032,38 +1045,36 @@ valMult (value * lval, value * rval)
 
   if (IS_FLOAT (val->type))
     SPEC_CVAL (val->type).v_float = floatFromVal (lval) * floatFromVal (rval);
-  else
-    {
       /* signed and unsigned mul are the same, as long as the precision of the
          result isn't bigger than the precision of the operands. */
-      if (SPEC_LONG (val->type))
-        SPEC_CVAL (val->type).v_ulong = (TYPE_UDWORD) floatFromVal (lval) *
-                                       (TYPE_UDWORD) floatFromVal (rval);
-      else /* int */
-        {
-          TYPE_UDWORD ul = (TYPE_UWORD) floatFromVal (lval) *
-                           (TYPE_UWORD) floatFromVal (rval);
-
-          SPEC_CVAL (val->type).v_uint = (TYPE_UWORD) ul;
-          if (!options.lessPedantic)
-            {
-              if (SPEC_USIGN (val->type))
-                {
-                  if (ul != SPEC_CVAL (val->type).v_uint)
-                    werror (W_INT_OVL);
-                }
-              else /* signed result */
-                {
-                  TYPE_DWORD l = (TYPE_WORD) floatFromVal (lval) *
-                                 (TYPE_WORD) floatFromVal (rval);
-
-                  if (l != SPEC_CVAL (val->type).v_int)
-                    werror (W_INT_OVL);
-                }
-            }
-        }
+  else if (SPEC_LONG (val->type))
+    SPEC_CVAL (val->type).v_ulong = (TYPE_UDWORD) floatFromVal (lval) *
+                                   (TYPE_UDWORD) floatFromVal (rval);
+  else if (SPEC_USIGN (val->type)) /* unsigned */
+    {
+      TYPE_UDWORD ul = (TYPE_UWORD) floatFromVal (lval) *
+                       (TYPE_UWORD) floatFromVal (rval);
+
+      SPEC_CVAL (val->type).v_uint = (TYPE_UWORD) ul;
+      if (!options.lessPedantic &&
+          ul != SPEC_CVAL (val->type).v_uint)
+        werror (W_INT_OVL);
+    }
+  else /* int */
+    {
+      TYPE_DWORD l = (TYPE_WORD) floatFromVal (lval) *
+                     (TYPE_WORD) floatFromVal (rval);
+
+      SPEC_CVAL (val->type).v_int = (TYPE_WORD) l;
+      if (!options.lessPedantic &&
+          l != SPEC_CVAL (val->type).v_int)
+        werror (W_INT_OVL);
     }
+#ifdef REDUCE_LITERALS
   return cheapestVal(val);
+#else
+  return val;
+#endif
 }
 
 /*------------------------------------------------------------------*/
@@ -1087,7 +1098,7 @@ valDiv (value * lval, value * rval)
                           IS_FLOAT (rval->etype) ? V_FLOAT : V_INT);
   SPEC_SCLS (val->etype) = S_LITERAL;
   SPEC_USIGN (val->type) = (SPEC_USIGN (lval->etype) | SPEC_USIGN (rval->etype));
-  SPEC_LONG (val->type) = (SPEC_LONG (lval->etype) | SPEC_LONG (rval->etype));
+  SPEC_LONG  (val->type) = (SPEC_LONG  (lval->etype) | SPEC_LONG  (rval->etype));
 
   if (IS_FLOAT (val->type))
     SPEC_CVAL (val->type).v_float = floatFromVal (lval) / floatFromVal (rval);
@@ -1096,25 +1107,28 @@ valDiv (value * lval, value * rval)
       if (SPEC_LONG (val->type))
        {
          if (SPEC_USIGN (val->type))
-           SPEC_CVAL (val->type).v_ulong = 
-             (unsigned long) floatFromVal (lval) /
-             (unsigned long) floatFromVal (rval);
+           SPEC_CVAL (val->type).v_ulong = (TYPE_UDWORD) floatFromVal (lval) /
+             (TYPE_UDWORD) floatFromVal (rval);
          else
-           SPEC_CVAL (val->type).v_long = (long) floatFromVal (lval) /
-             (long) floatFromVal (rval);
+           SPEC_CVAL (val->type).v_long = (TYPE_DWORD) floatFromVal (lval) /
+             (TYPE_DWORD) floatFromVal (rval);
        }
       else
        {
          if (SPEC_USIGN (val->type)) {
-           SPEC_CVAL (val->type).v_uint = (unsigned) floatFromVal (lval) /
-             (unsigned) floatFromVal (rval);
+           SPEC_CVAL (val->type).v_uint = (TYPE_UWORD) floatFromVal (lval) /
+             (TYPE_UWORD) floatFromVal (rval);
          } else {
-           SPEC_CVAL (val->type).v_int = (int) floatFromVal (lval) /
-             (int) floatFromVal (rval);
+           SPEC_CVAL (val->type).v_int = (TYPE_WORD) floatFromVal (lval) /
+             (TYPE_WORD) floatFromVal (rval);
          }
        }
     }
+#ifdef REDUCE_LITERALS
   return cheapestVal(val);
+#else
+  return val;
+#endif
 }
 
 /*------------------------------------------------------------------*/
@@ -1131,29 +1145,33 @@ valMod (value * lval, value * rval)
   SPEC_NOUN (val->type) = V_INT;       /* type is int */
   SPEC_SCLS (val->type) = S_LITERAL;   /* will remain literal */
   SPEC_USIGN (val->type) = (SPEC_USIGN (lval->etype) | SPEC_USIGN (rval->etype));
-  SPEC_LONG (val->type) = (SPEC_LONG (lval->etype) | SPEC_LONG (rval->etype));
+  SPEC_LONG  (val->type) = (SPEC_LONG  (lval->etype) | SPEC_LONG  (rval->etype));
 
   if (SPEC_LONG (val->type))
     {
       if (SPEC_USIGN (val->type))
-       SPEC_CVAL (val->type).v_ulong = (unsigned long) floatFromVal (lval) %
-         (unsigned long) floatFromVal (rval);
+       SPEC_CVAL (val->type).v_ulong = (TYPE_UDWORD) floatFromVal (lval) %
+         (TYPE_UDWORD) floatFromVal (rval);
       else
-       SPEC_CVAL (val->type).v_long = (unsigned long) floatFromVal (lval) %
-         (unsigned long) floatFromVal (rval);
+       SPEC_CVAL (val->type).v_long = (TYPE_DWORD) floatFromVal (lval) %
+         (TYPE_DWORD) floatFromVal (rval);
     }
   else
     {
       if (SPEC_USIGN (val->type)) {
-       SPEC_CVAL (val->type).v_uint = (unsigned) floatFromVal (lval) %
-         (unsigned) floatFromVal (rval);
+       SPEC_CVAL (val->type).v_uint = (TYPE_UWORD) floatFromVal (lval) %
+         (TYPE_UWORD) floatFromVal (rval);
       } else {
-       SPEC_CVAL (val->type).v_int = (unsigned) floatFromVal (lval) %
-         (unsigned) floatFromVal (rval);
+       SPEC_CVAL (val->type).v_int = (TYPE_WORD) floatFromVal (lval) %
+         (TYPE_WORD) floatFromVal (rval);
       }
     }
 
+#ifdef REDUCE_LITERALS
   return cheapestVal(val);
+#else
+  return val;
+#endif
 }
 
 /*------------------------------------------------------------------*/
@@ -1170,11 +1188,11 @@ valPlus (value * lval, value * rval)
   SPEC_NOUN (val->type) = (IS_FLOAT (lval->etype) ||
                           IS_FLOAT (rval->etype) ? V_FLOAT : V_INT);
   SPEC_SCLS (val->type) = S_LITERAL;   /* will remain literal */
-  SPEC_USIGN (val->type) = 
+  SPEC_USIGN (val->type) =
     SPEC_USIGN (lval->etype) &&
     SPEC_USIGN (rval->etype) &&
     (floatFromVal(lval)+floatFromVal(rval))>=0;
-    
+
   SPEC_LONG (val->type) = 1;
 
   if (IS_FLOAT (val->type))
@@ -1191,7 +1209,11 @@ valPlus (value * lval, value * rval)
              (long) floatFromVal (rval);
        }
     }
+#ifdef REDUCE_LITERALS
   return cheapestVal(val);
+#else
+  return val;
+#endif
 }
 
 /*------------------------------------------------------------------*/
@@ -1241,7 +1263,11 @@ valMinus (value * lval, value * rval)
          }
        }
     }
+#ifdef REDUCE_LITERALS
   return cheapestVal(val);
+#else
+  return val;
+#endif
 }
 
 /*------------------------------------------------------------------*/
@@ -1271,7 +1297,11 @@ valShift (value * lval, value * rval, int lr)
          (long) floatFromVal (lval) >> (long) floatFromVal (rval);
     }
 
+#ifdef REDUCE_LITERALS
   return cheapestVal(val);
+#else
+  return val;
+#endif
 }
 
 /*------------------------------------------------------------------*/
@@ -1401,7 +1431,11 @@ valBitwise (value * lval, value * rval, int op)
       break;
     }
 
+#ifdef REDUCE_LITERALS
   return cheapestVal(val);
+#else
+  return val;
+#endif
 }
 
 /*------------------------------------------------------------------*/
@@ -1448,27 +1482,33 @@ valCastLiteral (sym_link * dtype, double fval)
   val = newValue ();
   val->etype = getSpec (val->type = copyLinkChain (dtype));
   SPEC_SCLS (val->etype) = S_LITERAL;
+  TYPE_UDWORD l = (TYPE_UDWORD)fval;
+
   /* if it is not a specifier then we can assume that */
   /* it will be an unsigned long                      */
   if (!IS_SPEC (val->type)) {
-      SPEC_CVAL (val->etype).v_ulong = (unsigned long) fval;
+      SPEC_CVAL (val->etype).v_ulong = l;
       return val;
   }
 
   if (SPEC_NOUN (val->etype) == V_FLOAT)
       SPEC_CVAL (val->etype).v_float = fval;
-  else {
-      unsigned long l = (unsigned long)fval;
+  else if (SPEC_NOUN (val->etype) == V_CHAR) {
+      if (SPEC_USIGN (val->etype))
+         SPEC_CVAL (val->etype).v_uint= (TYPE_UBYTE) l;
+      else
+         SPEC_CVAL (val->etype).v_int = (TYPE_BYTE) l;
+  } else {
       if (SPEC_LONG (val->etype)) {
          if (SPEC_USIGN (val->etype))
-             SPEC_CVAL (val->etype).v_ulong = (unsigned long) l;
+             SPEC_CVAL (val->etype).v_ulong = (TYPE_UDWORD) l;
          else
-             SPEC_CVAL (val->etype).v_long = (long) l;
+             SPEC_CVAL (val->etype).v_long = (TYPE_DWORD) l;
       } else {
          if (SPEC_USIGN (val->etype))
-             SPEC_CVAL (val->etype).v_uint = (unsigned short)l;
+             SPEC_CVAL (val->etype).v_uint = (TYPE_UWORD)l;
          else
-             SPEC_CVAL (val->etype).v_int = (short)l;
+             SPEC_CVAL (val->etype).v_int = (TYPE_WORD)l;
       }
   }
   return val;
@@ -1477,7 +1517,7 @@ valCastLiteral (sym_link * dtype, double fval)
 /*------------------------------------------------------------------*/
 /* getNelements - determines # of elements from init list           */
 /*------------------------------------------------------------------*/
-int 
+int
 getNelements (sym_link * type, initList * ilist)
 {
   int i;
diff --git a/support/regression/tests/literalop.c b/support/regression/tests/literalop.c
new file mode 100644 (file)
index 0000000..23b42c4
--- /dev/null
@@ -0,0 +1,126 @@
+/* Test operandOperation() in SDCCicode.c
+
+    type: char, short, long
+ */
+#include <testfwk.h>
+
+typedef   signed {type} stype;
+typedef unsigned {type} utype;
+
+#define _{type}
+
+#if defined(PORT_HOST) || defined(SDCC_z80) || defined(SDCC_gbz80)
+#  define idata
+#  define code
+#endif
+
+volatile char is8 = 8;
+
+signed char  sc;
+signed short ss;
+signed long  sl;
+unsigned char  uc;
+unsigned short us;
+unsigned long  ul;
+volatile signed char  vsc;
+volatile signed short vss;
+volatile signed long  vsl;
+volatile unsigned char  vuc;
+volatile unsigned short vus;
+volatile unsigned long  vul;
+stype s;
+volatile stype vs;
+utype u;
+volatile utype vu;
+
+unsigned long t1, t2;
+
+void
+testOpOp(void)
+{
+  /* mul ast */
+  ASSERT((stype) -3 * (stype) -1 == (stype)  3);
+  ASSERT((stype) -3 * (stype)  1 == (stype) -3);
+  ASSERT((stype)  3 * (stype) -1 == (stype) -3);
+
+  ASSERT((stype)  1 * (utype) 0xfffffff7 == (utype) 0xfffffff7);
+
+  ASSERT((unsigned char ) 0xfffffff8 * (unsigned char ) 0xfffffff7 == 0xef48);
+  ASSERT((unsigned short) 0xfffffff8 * (unsigned short) 0xfffffff7 == (sizeof(int) == 2 ? 0x0048 : 0xffef0048));
+  ASSERT((unsigned long ) 0xfffffff8 * (unsigned long ) 0xfffffff7 == 0x0048);
+
+  ASSERT((stype         ) 0xfffffff8 * (stype         ) 0xfffffff7 == 72);
+
+  ASSERT((signed char ) -1 * (unsigned char ) 0xfffffff7 == (sizeof(int) == 2 ? 0xff09 : 0xffffff09));
+  ASSERT((signed short) -1 * (unsigned short) 0xfffffff7 == (sizeof(int) == 2 ?     9u : 0xffff0009));
+  ASSERT((signed long ) -1 * (unsigned long ) 0xfffffff7 == 9u);
+
+  ASSERT((signed char ) -2 * (unsigned char ) 0x8004 == (sizeof(int) == 2 ? 0xfff8 : 0xfffffff8));
+  ASSERT((signed short) -2 * (unsigned short) 0x8004 == (sizeof(int) == 2 ? 0xfff8 : 0xfffefff8));
+  ASSERT((signed long ) -2 * (unsigned long ) 0x8004 == 0xfffefff8);
+
+  ASSERT(-1 * 0xfff7 == (sizeof(int) == 2 ? 9 : 0xffff0009)); // 0xfff7 is stored in 'unsigned int'
+  // but:
+  ASSERT(-1 * 65527  == -65527); // 65527 (== 0xfff7) is stored in 'signed long'
+  ASSERT(-1 * 33000  == -33000);
+
+  ASSERT(1 *  10000  * is8 == (sizeof(int) == 2 ? 14464  :  80000)); /* int     */
+  ASSERT(1 *  10000l * is8 == 80000);                               /* long     */
+  ASSERT(1 *  40000u * is8 == (sizeof(int) == 2 ? 57856u : 320000)); /* unsigned */
+  ASSERT(1 *  40000  * is8 == 320000);                              /* long     */
+  ASSERT(1 * 0x4000  * is8 == (sizeof(int) == 2 ? 0 : 0x20000));     /* unsigned */
+
+  ASSERT(-1 * 1  < 0);
+  ASSERT(-1 * 1u > 0);
+
+
+  /* mul icode */
+  s = -3;
+  ASSERT(s * (stype) -1 == (stype)  3);
+  ASSERT(s * (stype)  1 == (stype) -3);
+  s =  3;
+  ASSERT(s * (stype) -1 == (stype) -3);
+
+  s = 1;
+  ASSERT(s * (utype) 0xfffffff7 == (utype) 0xfffffff7);
+  uc = (unsigned char ) 0xfffffff8;
+  ASSERT(uc * (unsigned char ) 0xfffffff7 == 0xef48);
+  us = (unsigned short) 0xfffffff8;
+  ASSERT(us * (unsigned short) 0xfffffff7 == (sizeof(int) == 2 ? 0x0048 : 0xffef0048));
+  ul = (unsigned long ) 0xfffffff8;
+  ASSERT(ul * (unsigned long ) 0xfffffff7 == 0x0048);
+  ul = (unsigned long ) 0xfffffff8;
+
+  ASSERT((stype         ) 0xfffffff8 * (stype         ) 0xfffffff7 == 72);
+
+  ASSERT((signed char ) -1 * (unsigned char ) 0xfffffff7 == (sizeof(int) == 2 ? 0xff09 : 0xffffff09));
+  ASSERT((signed short) -1 * (unsigned short) 0xfffffff7 == (sizeof(int) == 2 ?     9u : 0xffff0009));
+  ASSERT((signed long ) -1 * (unsigned long ) 0xfffffff7 == 9u);
+
+  ASSERT((signed char ) -2 * (unsigned char ) 0x8004 == (sizeof(int) == 2 ? 0xfff8 : 0xfffffff8));
+  ASSERT((signed short) -2 * (unsigned short) 0x8004 == (sizeof(int) == 2 ? 0xfff8 : 0xfffefff8));
+  ASSERT((signed long ) -2 * (unsigned long ) 0x8004 == 0xfffefff8);
+
+
+
+  ASSERT((stype) -12 / (stype) -3 == (stype)  4);
+  ASSERT((stype) -12 / (stype)  3 == (stype) -4);
+  ASSERT((stype)  12 / (stype) -3 == (stype) -4);
+
+//  ASSERT((stype) -12 / (utype) -3 == (stype)  4);
+//  ASSERT((utype) -12 / (stype) -3 == (stype)  4);
+//  ASSERT((utype) -12 / (utype) -3 == (stype)  4);
+
+
+  ASSERT(12u / 3 * 10000 == 40000);
+
+  ASSERT(-1 / 1 < 0);
+
+
+
+  ASSERT((stype) -14 % (stype) -3 == (stype) -2);
+  ASSERT((stype) -14 % (stype)  3 == (stype) -2);
+  ASSERT((stype)  14 % (stype) -3 == (stype)  2);
+
+  ASSERT(-3 % 2 < 0);
+}