* src/SDCCicode.c (geniCodeAddressOf): fixed part of bug #840381
[fw/sdcc] / src / SDCCicode.c
index c2feabde7fb799ac69ea0dbec88f4471b4f25fbd..2672a1ab6812af6dad99c95312aeaadb6c4652d5 100644 (file)
@@ -51,6 +51,7 @@ operand *geniCodeArray2Ptr (operand *);
 operand *geniCodeRValue (operand *, bool);
 operand *geniCodeDerefPtr (operand *,int);
 int isLvaluereq(int lvl);
+void  setOClass (sym_link * ptr, sym_link * spec);
 
 #define PRINTFUNC(x) void x (FILE *of, iCode *ic, char *s)
 /* forward definition of ic print functions */
@@ -67,6 +68,9 @@ PRINTFUNC (picIfx);
 PRINTFUNC (picJumpTable);
 PRINTFUNC (picInline);
 PRINTFUNC (picReceive);
+PRINTFUNC (picDummyRead);
+PRINTFUNC (picCritical);
+PRINTFUNC (picEndCritical);
 
 iCodeTable codeTable[] =
 {
@@ -113,12 +117,16 @@ iCodeTable codeTable[] =
   {RECEIVE, "recv", picReceive, NULL},
   {SEND, "send", picGenericOne, NULL},
   {ARRAYINIT, "arrayInit", picGenericOne, NULL},
+  {DUMMY_READ_VOLATILE, "dummy = (volatile)", picDummyRead, NULL},
+  {CRITICAL, "critical_start", picCritical, NULL},
+  {ENDCRITICAL, "critical_end", picEndCritical, NULL}
 };
 
 /*-----------------------------------------------------------------*/
 /* 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)
@@ -126,7 +134,7 @@ iCodeTable codeTable[] =
      pedantic>1: "char c=200" is not allowed (evaluates to -56)
 */
 
-void checkConstantRange(sym_link *ltype, value *val, char *msg, 
+void checkConstantRange(sym_link *ltype, value *val, char *msg,
                        int pedantic) {
   double max;
   int warnings=0;
@@ -180,7 +188,7 @@ void checkConstantRange(sym_link *ltype, value *val, char *msg,
 
 #if 0 // temporary disabled, leaving the warning as a reminder
   if (warnings) {
-    sprintf (message, "for %s %s in %s", 
+    SNPRINTF (message, sizeof(message), "for %s %s in %s", 
             SPEC_USIGN(ltype) ? "unsigned" : "signed",
             nounName(ltype), msg);
     werror (W_CONST_RANGE, message);
@@ -216,7 +224,7 @@ printOperand (operand * op, FILE * file)
       if (SPEC_NOUN (opetype) == V_FLOAT)
        fprintf (file, "%g {", SPEC_CVAL (opetype).v_float);
       else
-       fprintf (file, "0x%x {", (int) floatFromVal (op->operand.valOperand));
+       fprintf (file, "0x%x {", (unsigned) floatFromVal (op->operand.valOperand));
       printTypeChain (operandType (op), file);
       fprintf (file, "}");
       break;
@@ -224,13 +232,14 @@ printOperand (operand * op, FILE * file)
     case SYMBOL:
 #define REGA 1
 #ifdef REGA
-      fprintf (file, "%s [k%d lr%d:%d so:%d]{ ia%d re%d rm%d nos%d ru%d}",             /*{ar%d rm%d ru%d p%d a%d u%d i%d au%d k%d ks%d}"  , */
+      fprintf (file, "%s [k%d lr%d:%d so:%d]{ ia%d re%d rm%d nos%d ru%d dp%d}",                /*{ar%d rm%d ru%d p%d a%d u%d i%d au%d k%d ks%d}"  , */
               (OP_SYMBOL (op)->rname[0] ? OP_SYMBOL (op)->rname : OP_SYMBOL (op)->name),
               op->key,
               OP_LIVEFROM (op), OP_LIVETO (op),
               OP_SYMBOL (op)->stack,
-              op->isaddr, OP_SYMBOL (op)->isreqv, OP_SYMBOL (op)->remat,OP_SYMBOL(op)->noSpilLoc,
-              OP_SYMBOL(op)->ruonly
+              op->isaddr, OP_SYMBOL (op)->isreqv, 
+              OP_SYMBOL (op)->remat,OP_SYMBOL(op)->noSpilLoc,
+              OP_SYMBOL(op)->ruonly,OP_SYMBOL(op)->dptr
        );
       {
        fprintf (file, "{");
@@ -385,6 +394,9 @@ PRINTFUNC (picGenericOne)
   if (!IC_RESULT (ic) && !IC_LEFT (ic))
     fprintf (of, s);
 
+  if (ic->op == SEND || ic->op == RECEIVE) {
+      fprintf(of,"{argreg = %d}",ic->argreg);
+  }
   fprintf (of, "\n");
 }
 
@@ -457,10 +469,40 @@ PRINTFUNC (picReceive)
   fprintf (of, "\n");
 }
 
+PRINTFUNC (picDummyRead)
+{
+  fprintf (of, "\t");
+  fprintf (of, "%s ", s);
+  printOperand (IC_RIGHT (ic), of);
+  fprintf (of, "\n");
+}
+
+PRINTFUNC (picCritical)
+{
+  fprintf (of, "\t");
+  if (IC_RESULT (ic))
+    printOperand (IC_RESULT (ic), of);
+  else
+    fprintf (of, "(stack)");
+  fprintf (of, " = %s ", s);
+  fprintf (of, "\n");
+}
+
+PRINTFUNC (picEndCritical)
+{
+  fprintf (of, "\t");
+  fprintf (of, "%s = ", s);
+  if (IC_RIGHT (ic))
+    printOperand (IC_RIGHT (ic), of);
+  else
+    fprintf (of, "(stack)");
+  fprintf (of, "\n");
+}
+
 /*-----------------------------------------------------------------*/
 /* piCode - prints one iCode                                       */
 /*-----------------------------------------------------------------*/
-int 
+int
 piCode (void *item, FILE * of)
 {
   iCode *ic = item;
@@ -484,7 +526,7 @@ void PICC(iCode *ic)
 /*-----------------------------------------------------------------*/
 /* printiCChain - prints intermediate code for humans              */
 /*-----------------------------------------------------------------*/
-void 
+void
 printiCChain (iCode * icChain, FILE * of)
 {
   iCode *loop;
@@ -496,7 +538,7 @@ printiCChain (iCode * icChain, FILE * of)
     {
       if ((icTab = getTableEntry (loop->op)))
        {
-         fprintf (of, "%s(%d:%d:%d:%d:%d)\t",
+         fprintf (of, "%s(l%d:s%d:k%d:d%d:s%d)\t",
                   loop->filename, loop->lineno,
                   loop->seq, loop->key, loop->depth, loop->supportRtn);
 
@@ -573,7 +615,7 @@ newiCodeLabelGoto (int op, symbol * label)
 
   ic = newiCode (op, NULL, NULL);
   ic->op = op;
-  ic->argLabel.label = label;
+  ic->label = label;
   IC_LEFT (ic) = NULL;
   IC_RIGHT (ic) = NULL;
   IC_RESULT (ic) = NULL;
@@ -589,11 +631,16 @@ newiTemp (char *s)
   symbol *itmp;
 
   if (s)
-    sprintf (buffer, "%s", s);
+  {
+      SNPRINTF (buffer, sizeof(buffer), "%s", s);
+  }
   else
-    sprintf (buffer, "iTemp%d", iTempNum++);
+  {
+      SNPRINTF (buffer, sizeof(buffer), "iTemp%d", iTempNum++);
+  }
+    
   itmp = newSymbol (buffer, 1);
-  strcpy (itmp->rname, itmp->name);
+  strncpyz (itmp->rname, itmp->name, SDCC_NAME_MAX);
   itmp->isitmp = 1;
 
   return itmp;
@@ -612,10 +659,12 @@ newiTempLabel (char *s)
     return itmplbl;
 
   if (s)
-    itmplbl = newSymbol (s, 1);
+    {
+       itmplbl = newSymbol (s, 1);
+    }
   else
     {
-      sprintf (buffer, "iTempLbl%d", iTempLblNum++);
+      SNPRINTF (buffer, sizeof(buffer), "iTempLbl%d", iTempLblNum++);
       itmplbl = newSymbol (buffer, 1);
     }
 
@@ -634,7 +683,7 @@ newiTempPreheaderLabel ()
 {
   symbol *itmplbl;
 
-  sprintf (buffer, "preHeaderLbl%d", iTempLblNum++);
+  SNPRINTF (buffer, sizeof(buffer), "preHeaderLbl%d", iTempLblNum++);
   itmplbl = newSymbol (buffer, 1);
 
   itmplbl->isitmp = 1;
@@ -711,7 +760,7 @@ copyiCode (iCode * ic)
 iCodeTable *
 getTableEntry (int oper)
 {
-  int i;
+  unsigned i;
 
   for (i = 0; i < (sizeof (codeTable) / sizeof (iCodeTable)); i++)
     if (oper == codeTable[i].icode)
@@ -788,6 +837,8 @@ isParameterToCall (value * args, operand * op)
 {
   value *tval = args;
 
+  wassert (IS_SYMOP(op));
+    
   while (tval)
     {
       if (tval->sym &&
@@ -810,7 +861,7 @@ isOperandGlobal (operand * op)
   if (IS_ITEMP (op))
     return 0;
 
-  if (op->type == SYMBOL &&
+  if (IS_SYMOP(op) &&
       (op->operand.symOperand->level == 0 ||
        IS_STATIC (op->operand.symOperand->etype) ||
        IS_EXTERN (op->operand.symOperand->etype))
@@ -833,13 +884,13 @@ isOperandVolatile (operand * op, bool chkTemp)
     return 0;
 
   opetype = getSpec (optype = operandType (op));
-
-  if (IS_PTR (optype) && DCL_PTR_VOLATILE (optype))
-    return 1;
-
-  if (IS_VOLATILE (opetype))
-    return 1;
-  return 0;
+    
+  if (IS_PTR (optype) && DCL_PTR_VOLATILE (optype))   
+    return 1;   
+    
+  if (IS_VOLATILE (opetype))   
+    return 1;   
+  return 0; 
 }
 
 /*-----------------------------------------------------------------*/
@@ -917,12 +968,11 @@ isOperandInDirSpace (operand * op)
   return (IN_DIRSPACE (SPEC_OCLS (etype)) ? TRUE : FALSE);
 }
 
-/*-----------------------------------------------------------------*/
-/* isOperandOnStack - will return true if operand is on stack      */
-/*-----------------------------------------------------------------*/
-#if 0
+/*--------------------------------------------------------------------*/
+/* isOperandInCodeSpace - will return true if operand is in codeSpace */
+/*--------------------------------------------------------------------*/
 bool 
-isOperandOnStack (operand * op)
+isOperandInCodeSpace (operand * op)
 {
   sym_link *etype;
 
@@ -934,9 +984,23 @@ isOperandOnStack (operand * op)
 
   etype = getSpec (operandType (op));
 
-  return ((IN_STACK (etype)) ? TRUE : FALSE);
+  if (!IS_TRUE_SYMOP (op))
+    {
+      if (SPIL_LOC (op))
+       etype = SPIL_LOC (op)->etype;
+      else
+       return FALSE;
+    }
+  else
+    {
+      etype = getSpec (operandType (op));
+    }
+  return (IN_CODESPACE (SPEC_OCLS (etype)) ? TRUE : FALSE);
 }
-#else
+
+/*-----------------------------------------------------------------*/
+/* isOperandOnStack - will return true if operand is on stack      */
+/*-----------------------------------------------------------------*/
 bool 
 isOperandOnStack (operand * op)
 {
@@ -956,12 +1020,26 @@ isOperandOnStack (operand * op)
 
   return FALSE;
 }
-#endif
+
+/*-----------------------------------------------------------------*/
+/* isOclsExpensive - will return true if accesses to an output     */
+/*                   storage class are expensive                   */
+/*-----------------------------------------------------------------*/
+bool 
+isOclsExpensive (struct memmap *oclass)
+{
+  if (port->oclsExpense)
+    return port->oclsExpense (oclass) > 0;
+
+  /* In the absence of port specific guidance, assume only */
+  /* farspace is expensive. */
+  return IN_FARSPACE (oclass);
+}
 
 /*-----------------------------------------------------------------*/
 /* operandLitValue - literal value of an operand                   */
 /*-----------------------------------------------------------------*/
-double 
+double
 operandLitValue (operand * op)
 {
   assert (isOperandLiteral (op));
@@ -995,7 +1073,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,
@@ -1003,12 +1081,12 @@ operandOperation (operand * left, operand * right,
 {
   sym_link *let , *ret=NULL;
   operand *retval = (operand *) 0;
-  
+
   assert (isOperandLiteral (left));
   let = getSpec(operandType(left));
   if (right) {
     assert (isOperandLiteral (right));
-    ret = getSpec(operandType(left));
+    ret = getSpec(operandType(right));
   }
 
   switch (op)
@@ -1024,12 +1102,61 @@ 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 (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 (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;
@@ -1041,38 +1168,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)));
-
+      else
+        {
+          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:
-      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 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) <
@@ -1095,16 +1241,19 @@ operandOperation (operand * left, operand * right,
                               operandLitValue (right));
       break;
     case BITWISEAND:
-      retval = operandFromLit ((long)operandLitValue(left) & 
-                              (long)operandLitValue(right));
+      retval = operandFromValue (valCastLiteral (type,
+                                                 (TYPE_UDWORD)operandLitValue(left) &
+                                                (TYPE_UDWORD)operandLitValue(right)));
       break;
     case '|':
-      retval = operandFromLit ((long)operandLitValue (left) |
-                              (long)operandLitValue (right));
+      retval = operandFromValue (valCastLiteral (type,
+                                                 (TYPE_UDWORD)operandLitValue(left) |
+                                                (TYPE_UDWORD)operandLitValue(right)));
       break;
     case '^':
-      retval = operandFromLit ((long)operandLitValue (left) ^
-                              (long)operandLitValue (right));
+      retval = operandFromValue (valCastLiteral (type,
+                                                 (TYPE_UDWORD)operandLitValue(left) ^
+                                                (TYPE_UDWORD)operandLitValue(right)));
       break;
     case AND_OP:
       retval = operandFromLit (operandLitValue (left) &&
@@ -1116,7 +1265,7 @@ operandOperation (operand * left, operand * right,
       break;
     case RRC:
       {
-       long i = (long) operandLitValue (left);
+       TYPE_UDWORD i = (TYPE_UDWORD) operandLitValue (left);
 
        retval = operandFromLit ((i >> (getSize (operandType (left)) * 8 - 1)) |
                                 (i << 1));
@@ -1124,7 +1273,7 @@ operandOperation (operand * left, operand * right,
       break;
     case RLC:
       {
-       long i = (long) operandLitValue (left);
+       TYPE_UDWORD i = (TYPE_UDWORD) operandLitValue (left);
 
        retval = operandFromLit ((i << (getSize (operandType (left)) * 8 - 1)) |
                                 (i >> 1));
@@ -1132,11 +1281,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 (~((long) operandLitValue (left)));
+      retval = operandFromLit (~((TYPE_UDWORD) operandLitValue (left)));
       break;
 
     case '!':
@@ -1156,7 +1306,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 */
@@ -1344,6 +1494,7 @@ operandFromSymbol (symbol * sym)
      register equivalent for a local symbol */
   if (sym->level && sym->etype && SPEC_OCLS (sym->etype) &&
       (IN_FARSPACE (SPEC_OCLS (sym->etype)) &&
+      !TARGET_IS_HC08 &&
       (!(options.model == MODEL_FLAT24)) ) &&
       options.stackAuto == 0)
     ok = 0;
@@ -1360,7 +1511,7 @@ operandFromSymbol (symbol * sym)
       ok &&                    /* farspace check */
       !IS_BITVAR (sym->etype)  /* not a bit variable */
     )
-    {
+    {                                   
 
       /* we will use it after all optimizations
          and before liveRange calculation */
@@ -1483,10 +1634,13 @@ operandFromAst (ast * tree,int lvl)
 
     case EX_LINK:
       return operandFromLink (tree->opval.lnk);
-    }
+      break;
 
-  assert (0);
-  /*  Just to keep the comiler happy */
+    default:
+      assert (0);
+    }
+  
+  /*  Just to keep the compiler happy */
   return (operand *) 0;
 }
 
@@ -1581,15 +1735,16 @@ usualUnaryConversions (operand * op)
 /* perform "usual binary conversions"                              */
 /*-----------------------------------------------------------------*/
 sym_link *
-usualBinaryConversions (operand ** op1, operand ** op2, int implicit)
+usualBinaryConversions (operand ** op1, operand ** op2)
 {
   sym_link *ctype;
   sym_link *rtype = operandType (*op2);
   sym_link *ltype = operandType (*op1);
   
   ctype = computeType (ltype, rtype);
-  *op1 = geniCodeCast (ctype, *op1, implicit);
-  *op2 = geniCodeCast (ctype, *op2, implicit);
+
+  *op1 = geniCodeCast (ctype, *op1, TRUE);
+  *op2 = geniCodeCast (ctype, *op2, TRUE);
   
   return ctype;
 }
@@ -1619,7 +1774,7 @@ geniCodeRValue (operand * op, bool force)
   /* if this is not a temp symbol then */
   if (!IS_ITEMP (op) &&
       !force &&
-      !IN_FARSPACE (SPEC_OCLS (etype)))
+      !(IN_FARSPACE (SPEC_OCLS (etype)) && !TARGET_IS_HC08))
     {
       op = operandFromOperand (op);
       op->isaddr = 0;
@@ -1628,8 +1783,7 @@ geniCodeRValue (operand * op, bool force)
 
   if (IS_SPEC (type) &&
       IS_TRUE_SYMOP (op) &&
-      (!IN_FARSPACE (SPEC_OCLS (etype)) ||
-      /* TARGET_IS_DS390)) */
+      (!(IN_FARSPACE (SPEC_OCLS (etype)) && !TARGET_IS_HC08) ||
       (options.model == MODEL_FLAT24) ))
     {
       op = operandFromOperand (op);
@@ -1686,10 +1840,8 @@ geniCodeCast (sym_link * type, operand * op, bool implicit)
     if (!IS_PTR(optype) && !IS_FUNC(optype) && !IS_AGGREGATE(optype)) { // from a non pointer
       if (IS_INTEGRAL(optype)) { 
        // maybe this is NULL, than it's ok. 
-       // !implicit is always ok, e.g. "(char *) = (char *) + 3;"
-       if (implicit &&
-           !(IS_LITERAL(optype) && (SPEC_CVAL(optype).v_ulong ==0))) {
-         if (!TARGET_IS_Z80 && !TARGET_IS_GBZ80 && IS_GENPTR(type)) {
+       if (!(IS_LITERAL(optype) && (SPEC_CVAL(optype).v_ulong ==0))) {
+         if (port->s.gptr_size > port->s.fptr_size && IS_GENPTR(type)) {
            // no way to set the storage
            if (IS_LITERAL(optype)) {
              werror(E_LITERAL_GENERIC);
@@ -1698,7 +1850,7 @@ geniCodeCast (sym_link * type, operand * op, bool implicit)
              werror(E_NONPTR2_GENPTR);
              errors++;
            }
-         } else {
+         } else if (implicit) {
            werror(W_INTEGRAL2PTR_NOCAST);
            errors++;
          }
@@ -1712,7 +1864,7 @@ geniCodeCast (sym_link * type, operand * op, bool implicit)
        }
       }
     } else { // from a pointer to a pointer
-      if (!TARGET_IS_Z80 && !TARGET_IS_GBZ80) {
+      if (port->s.gptr_size > port->s.fptr_size /*!TARGET_IS_Z80 && !TARGET_IS_GBZ80*/) {
        // if not a pointer to a function
        if (!(IS_CODEPTR(type) && IS_FUNC(type->next) && IS_FUNC(optype))) {
          if (implicit) { // if not to generic, they have to match 
@@ -1767,7 +1919,8 @@ geniCodeCast (sym_link * type, operand * op, bool implicit)
   /* preserve the storage class & output class */
   /* of the original variable                  */
   restype = getSpec (operandType (IC_RESULT (ic)));
-  SPEC_SCLS (restype) = SPEC_SCLS (opetype);
+  if (!IS_LITERAL(opetype))
+      SPEC_SCLS (restype) = SPEC_SCLS (opetype);
   SPEC_OCLS (restype) = SPEC_OCLS (opetype);
 
   ADDTOCHAIN (ic);
@@ -1818,7 +1971,7 @@ geniCodeMultiply (operand * left, operand * right,int resultIsInt)
     p2 = powof2 ((unsigned long) floatFromVal (right->operand.valOperand));
   }
 
-  resType = usualBinaryConversions (&left, &right, TRUE);
+  resType = usualBinaryConversions (&left, &right);
 #if 1
   rtype = operandType (right);
   retype = getSpec (rtype);
@@ -1832,11 +1985,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)))
@@ -1875,12 +2028,14 @@ geniCodeDivision (operand * left, operand * right)
   sym_link *ltype = operandType (left);
   sym_link *letype = getSpec (ltype);
 
-  resType = usualBinaryConversions (&left, &right, TRUE);
+  resType = usualBinaryConversions (&left, &right);
 
-  /* if the right is a literal & power of 2 */
-  /* then make it a right shift             */
+  /* 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) &&
+      SPEC_USIGN(letype) &&
       (p2 = powof2 ((unsigned long)
                    floatFromVal (right->operand.valOperand)))) {
     ic = newiCode (RIGHT_OP, left, operandFromLit (p2)); /* right shift */
@@ -1912,7 +2067,7 @@ geniCodeModulus (operand * left, operand * right)
     return operandFromValue (valMod (left->operand.valOperand,
                                     right->operand.valOperand));
 
-  resType = usualBinaryConversions (&left, &right, TRUE);
+  resType = usualBinaryConversions (&left, &right);
 
   /* now they are the same size */
   ic = newiCode ('%', left, right);
@@ -1950,6 +2105,11 @@ geniCodePtrPtrSubtract (operand * left, operand * right)
   ADDTOCHAIN (ic);
 
 subtractExit:
+  if (IS_VOID(ltype->next) || IS_VOID(rtype->next)) {
+    return result;
+  }
+  
+  // should we really do this? is this ANSI?
   return geniCodeDivision (result,
                           operandFromLit (getSize (ltype->next)));
 }
@@ -1986,7 +2146,7 @@ geniCodeSubtract (operand * left, operand * right)
     }
   else
     {                          /* make them the same size */
-      resType = usualBinaryConversions (&left, &right, TRUE);
+      resType = usualBinaryConversions (&left, &right);
     }
 
   ic = newiCode ('-', left, right);
@@ -2006,7 +2166,7 @@ geniCodeSubtract (operand * left, operand * right)
 /* geniCodeAdd - generates iCode for addition                      */
 /*-----------------------------------------------------------------*/
 operand *
-geniCodeAdd (operand * left, operand * right, int lvl, int ptrMath)
+geniCodeAdd (operand * left, operand * right, int lvl)
 {
   iCode *ic;
   sym_link *resType;
@@ -2014,10 +2174,6 @@ geniCodeAdd (operand * left, operand * right, int lvl, int ptrMath)
   int isarray = 0;
   LRTYPE;
 
-  /* if left is an array then array access */
-  if (IS_ARRAY (ltype))
-    return geniCodeArray (left, right,lvl);
-
   /* if the right side is LITERAL zero */
   /* return the left side              */
   if (IS_LITERAL (retype) && right->isLiteral && !floatFromVal (valFromType (retype)))
@@ -2027,8 +2183,8 @@ geniCodeAdd (operand * left, operand * right, int lvl, int ptrMath)
   if (IS_LITERAL (letype) && left->isLiteral && !floatFromVal (valFromType (letype)))
     return right;
 
-  /* if left is an array or pointer then size */
-  if (ptrMath && IS_PTR (ltype))
+  /* if left is a pointer then size */
+  if (IS_PTR (ltype) || IS_ARRAY(ltype))
     {
       isarray = left->isaddr;
       // there is no need to multiply with 1
@@ -2040,7 +2196,7 @@ geniCodeAdd (operand * left, operand * right, int lvl, int ptrMath)
     }
   else
     { // make them the same size
-      resType = usualBinaryConversions (&left, &right, FALSE);
+      resType = usualBinaryConversions (&left, &right);
     }
 
   /* if they are both literals then we know */
@@ -2074,26 +2230,16 @@ aggrToPtr (sym_link * type, bool force)
   sym_link *etype;
   sym_link *ptype;
 
-
   if (IS_PTR (type) && !force)
     return type;
 
   etype = getSpec (type);
-  ptype = newLink ();
+  ptype = newLink (DECLARATOR);
 
   ptype->next = type;
-  /* if the output class is generic */
-  if ((DCL_TYPE (ptype) = PTR_TYPE (SPEC_OCLS (etype))) == CPOINTER)
-    DCL_PTR_CONST (ptype) = port->mem.code_ro;
-
-  /* if the variable was declared a constant */
-  /* then the pointer points to a constant */
-  if (IS_CONSTANT (etype))
-    DCL_PTR_CONST (ptype) = 1;
-
-  /* the variable was volatile then pointer to volatile */
-  if (IS_VOLATILE (etype))
-    DCL_PTR_VOLATILE (ptype) = 1;
+
+  /* set the pointer depending on the storage class */
+  DCL_TYPE (ptype) = PTR_TYPE (SPEC_OCLS (etype));
   return ptype;
 }
 
@@ -2107,18 +2253,8 @@ geniCodeArray2Ptr (operand * op)
   sym_link *opetype = getSpec (optype);
 
   /* set the pointer depending on the storage class */
-  if ((DCL_TYPE (optype) = PTR_TYPE (SPEC_OCLS (opetype))) == CPOINTER)
-    DCL_PTR_CONST (optype) = port->mem.code_ro;
-
-
-  /* if the variable was declared a constant */
-  /* then the pointer points to a constant */
-  if (IS_CONSTANT (opetype))
-    DCL_PTR_CONST (optype) = 1;
+  DCL_TYPE (optype) = PTR_TYPE (SPEC_OCLS (opetype));
 
-  /* the variable was volatile then pointer to volatile */
-  if (IS_VOLATILE (opetype))
-    DCL_PTR_VOLATILE (optype) = 1;
   op->isaddr = 0;
   return op;
 }
@@ -2132,14 +2268,15 @@ geniCodeArray (operand * left, operand * right,int lvl)
 {
   iCode *ic;
   sym_link *ltype = operandType (left);
-
+  
   if (IS_PTR (ltype))
     {
       if (IS_PTR (ltype->next) && left->isaddr)
        {
          left = geniCodeRValue (left, FALSE);
        }
-      return geniCodeDerefPtr (geniCodeAdd (left, right, lvl, 1), lvl);
+      
+      return geniCodeDerefPtr (geniCodeAdd (left, right, lvl), lvl);
     }
 
   right = geniCodeMultiply (right,
@@ -2164,6 +2301,7 @@ geniCodeArray (operand * left, operand * right,int lvl)
 
   IC_RESULT (ic)->isaddr = (!IS_AGGREGATE (ltype->next));
   ADDTOCHAIN (ic);
+
   return IC_RESULT (ic);
 }
 
@@ -2180,6 +2318,8 @@ geniCodeStruct (operand * left, operand * right, bool islval)
   symbol *element = getStructElement (SPEC_STRUCT (etype),
                                      right->operand.symOperand);
 
+  wassert(IS_SYMOP(right));
+    
   /* add the offset */
   ic = newiCode ('+', left, operandFromLit (element->offset));
 
@@ -2191,13 +2331,13 @@ geniCodeStruct (operand * left, operand * right, bool islval)
   SPEC_SCLS (retype) = SPEC_SCLS (etype);
   SPEC_OCLS (retype) = SPEC_OCLS (etype);
   SPEC_VOLATILE (retype) |= SPEC_VOLATILE (etype);
-
+  SPEC_CONST (retype) |= SPEC_CONST (etype);
+  
   if (IS_PTR (element->type))
     setOperandType (IC_RESULT (ic), aggrToPtr (operandType (IC_RESULT (ic)), TRUE));
-
+  
   IC_RESULT (ic)->isaddr = (!IS_AGGREGATE (element->type));
 
-
   ADDTOCHAIN (ic);
   return (islval ? IC_RESULT (ic) : geniCodeRValue (IC_RESULT (ic), TRUE));
 }
@@ -2252,7 +2392,7 @@ geniCodePostInc (operand * op)
 /* geniCodePreInc - generate code for preIncrement                 */
 /*-----------------------------------------------------------------*/
 operand *
-geniCodePreInc (operand * op)
+geniCodePreInc (operand * op, bool lvalue)
 {
   iCode *ic;
   sym_link *optype = operandType (op);
@@ -2278,8 +2418,11 @@ geniCodePreInc (operand * op)
   IC_RESULT (ic) = result = newiTempOperand (roptype, 0);
   ADDTOCHAIN (ic);
 
-
-  return geniCodeAssign (op, result, 0);
+  (void) geniCodeAssign (op, result, 0);
+  if (lvalue || IS_TRUE_SYMOP (op))
+    return op;
+  else
+    return result;
 }
 
 /*-----------------------------------------------------------------*/
@@ -2332,7 +2475,7 @@ geniCodePostDec (operand * op)
 /* geniCodePreDec - generate code for pre  decrement               */
 /*-----------------------------------------------------------------*/
 operand *
-geniCodePreDec (operand * op)
+geniCodePreDec (operand * op, bool lvalue)
 {
   iCode *ic;
   sym_link *optype = operandType (op);
@@ -2358,8 +2501,11 @@ geniCodePreDec (operand * op)
   IC_RESULT (ic) = result = newiTempOperand (roptype, 0);
   ADDTOCHAIN (ic);
 
-
-  return geniCodeAssign (op, result, 0);
+  (void) geniCodeAssign (op, result, 0);
+  if (lvalue || IS_TRUE_SYMOP (op))
+    return op;
+  else
+    return result;
 }
 
 
@@ -2393,6 +2539,13 @@ geniCodeAddressOf (operand * op)
   sym_link *optype = operandType (op);
   sym_link *opetype = getSpec (optype);
 
+  if (IS_ITEMP (op) && op->isaddr && IS_PTR (optype))
+    {
+      op = operandFromOperand (op);
+      op->isaddr = 0;
+      return op;
+    }
+  
   /* lvalue check already done in decorateType */
   /* this must be a lvalue */
 /*     if (!op->isaddr && !IS_AGGREGATE(optype)) { */
@@ -2400,19 +2553,10 @@ geniCodeAddressOf (operand * op)
 /*  return op; */
 /*     } */
 
-  p = newLink ();
-  p->class = DECLARATOR;
+  p = newLink (DECLARATOR);
 
   /* set the pointer depending on the storage class */
-  if ((DCL_TYPE (p) = PTR_TYPE (SPEC_OCLS (opetype))) == CPOINTER)
-    DCL_PTR_CONST (p) = port->mem.code_ro;
-
-  /* make sure we preserve the const & volatile */
-  if (IS_CONSTANT (opetype))
-    DCL_PTR_CONST (p) = 1;
-
-  if (IS_VOLATILE (opetype))
-    DCL_PTR_VOLATILE (p) = 1;
+  DCL_TYPE (p) = PTR_TYPE (SPEC_OCLS (opetype));
 
   p->next = copyLinkChain (optype);
 
@@ -2482,16 +2626,19 @@ geniCodeDerefPtr (operand * op,int lvl)
   sym_link *rtype, *retype;
   sym_link *optype = operandType (op);
 
-  /* if this is a pointer then generate the rvalue */
-  if (IS_PTR (optype))
+  // if this is an array then array access
+  if (IS_ARRAY (optype)) {
+    // don't worry, this will be optimized out later
+    return geniCodeArray (op, operandFromLit (0), lvl);
+  }
+
+  // just in case someone screws up
+  wassert (IS_PTR (optype));
+
+  if (IS_TRUE_SYMOP (op))
     {
-      if (IS_TRUE_SYMOP (op))
-       {
-         op->isaddr = 1;
-         op = geniCodeRValue (op, TRUE);
-       }
-      else
-       op = geniCodeRValue (op, TRUE);
+      op->isaddr = 1;
+      op = geniCodeRValue (op, TRUE);
     }
 
   /* now get rid of the pointer part */
@@ -2502,19 +2649,12 @@ geniCodeDerefPtr (operand * op,int lvl)
   else
     {
       retype = getSpec (rtype = copyLinkChain (optype->next));
+      /* outputclass needs 2b updated */
+      setOClass (optype, retype);
     }
-
-  /* if this is a pointer then outputclass needs 2b updated */
-  if (IS_PTR (optype))
-    setOClass (optype, retype);
-
+  
   op->isGptr = IS_GENPTR (optype);
 
-  /* if the pointer was declared as a constant */
-  /* then we cannot allow assignment to the derefed */
-  if (IS_PTR_CONST (optype))
-    SPEC_CONST (retype) = 1;
-
   op->isaddr = (IS_PTR (rtype) ||
                IS_STRUCT (rtype) ||
                IS_INT (rtype) ||
@@ -2590,11 +2730,54 @@ 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);
     }
 
-  ctype = usualBinaryConversions (&left, &right, TRUE);
+  /* if one operand is a pointer and the other is a literal generic void pointer,
+     change the type of the literal generic void pointer to match the other pointer */
+  if (IS_GENPTR (ltype) && IS_VOID (ltype->next) && IS_ITEMP (left)
+      && IS_PTR (rtype) && !IS_GENPTR(rtype))
+    {
+      /* find left's definition */
+      ic = (iCode *) setFirstItem (iCodeChain);
+      while (ic)
+        {
+          if (((ic->op == CAST) || (ic->op == '='))
+              && isOperandEqual(left, IC_RESULT (ic)))
+            break;
+          else
+            ic = setNextItem (iCodeChain);
+        }
+      /* if casting literal to generic pointer, then cast to rtype instead */
+      if (ic && (ic->op == CAST) && isOperandLiteral(IC_RIGHT (ic))) 
+        {
+          left = operandFromValue (valCastLiteral (rtype, operandLitValue (IC_RIGHT (ic))));
+          ltype = operandType(left);
+        }
+    }
+  if (IS_GENPTR (rtype) && IS_VOID (rtype->next) && IS_ITEMP (right)
+      && IS_PTR (ltype) && !IS_GENPTR(ltype))
+    {
+      /* find right's definition */
+      ic = (iCode *) setFirstItem (iCodeChain);
+      while (ic)
+        {
+          if (((ic->op == CAST) || (ic->op == '='))
+              && isOperandEqual(right, IC_RESULT (ic)))
+            break;
+          else
+            ic = setNextItem (iCodeChain);
+        }
+      /* if casting literal to generic pointer, then cast to rtype instead */
+      if (ic && (ic->op == CAST) && isOperandLiteral(IC_RIGHT (ic))) 
+        {
+          right = operandFromValue (valCastLiteral (ltype, operandLitValue (IC_RIGHT (ic))));
+          rtype = operandType(right);
+        }
+    }
+
+  ctype = usualBinaryConversions (&left, &right);
 
   ic = newiCode (op, left, right);
   IC_RESULT (ic) = newiTempOperand (newCharLink (), 1);
@@ -2702,11 +2885,12 @@ geniCodeAssign (operand * left, operand * right, int nosupdate)
   else if (compareType (ltype, rtype) < 0)
     right = geniCodeCast (ltype, right, TRUE);
 
-  /* if left is a true symbol & ! volatile
+  /* If left is a true symbol & ! volatile
      create an assignment to temporary for
      the right & then assign this temporary
-     to the symbol this is SSA . isn't it simple
-     and folks have published mountains of paper on it */
+     to the symbol. This is SSA (static single
+     assignment). Isn't it simple and folks have
+     published mountains of paper on it */
   if (IS_TRUE_SYMOP (left) &&
       !isOperandVolatile (left, FALSE) &&
       isOperandGlobal (left))
@@ -2734,6 +2918,24 @@ geniCodeAssign (operand * left, operand * right, int nosupdate)
   return left;
 }
 
+/*-----------------------------------------------------------------*/
+/* geniCodeDummyRead - generate code for dummy read                */
+/*-----------------------------------------------------------------*/
+static void
+geniCodeDummyRead (operand * op)
+{
+  iCode *ic;
+  sym_link *type = operandType (op);
+
+  if (!IS_VOLATILE(type))
+    return;
+    
+  ic = newiCode (DUMMY_READ_VOLATILE, NULL, op);
+  ADDTOCHAIN (ic);
+
+  ic->nosupdate = 1;
+}
+
 /*-----------------------------------------------------------------*/
 /* geniCodeSEParms - generate code for side effecting fcalls       */
 /*-----------------------------------------------------------------*/
@@ -2760,10 +2962,12 @@ geniCodeSEParms (ast * parms,int lvl)
       IS_ADDRESS_OF_OP (parms->right))
     parms->right->left->lvalue = 1;
 
-  parms->opval.oprnd =
+  parms->opval.oprnd = 
     geniCodeRValue (ast2iCode (parms,lvl+1), FALSE);
-
+               
   parms->type = EX_OPERAND;
+  AST_ARGREG(parms) = parms->etype ? SPEC_ARGREG(parms->etype) :
+               SPEC_ARGREG(parms->ftype);
 }
 
 /*-----------------------------------------------------------------*/
@@ -2816,6 +3020,7 @@ geniCodeParms (ast * parms, value *argVals, int *stack,
       IFFUNC_ISBUILTIN(func->type))
     {
       ic = newiCode (SEND, pval, NULL);
+      ic->argreg = SPEC_ARGREG(parms->etype);
       ic->builtinSEND = FUNC_ISBUILTIN(func->type);
       ADDTOCHAIN (ic);
     }
@@ -2828,7 +3033,7 @@ geniCodeParms (ast * parms, value *argVals, int *stack,
          /* assign */
          operand *top = operandFromSymbol (argVals->sym);
          /* clear useDef and other bitVectors */
-         OP_USES (top) = OP_DEFS (top) = OP_SYMBOL(top)->clashes = NULL;
+         OP_USES(top)=OP_DEFS(top)=OP_SYMBOL(top)->clashes = NULL;
          geniCodeAssign (top, pval, 1);
        }
       else
@@ -2873,10 +3078,11 @@ geniCodeCall (operand * left, ast * parms,int lvl)
   geniCodeParms (parms, NULL, &stack, getSpec (operandType (left)), OP_SYMBOL (left),lvl);
 
   /* now call : if symbol then pcall */
-  if (IS_OP_POINTER (left) || IS_ITEMP(left))
+  if (IS_OP_POINTER (left) || IS_ITEMP(left)) {
     ic = newiCode (PCALL, left, NULL);
-  else
+  } else {
     ic = newiCode (CALL, left, NULL);
+  }
 
   type = copyLinkChain (operandType (left)->next);
   etype = getSpec (type);
@@ -2900,7 +3106,7 @@ geniCodeReceive (value * args)
   /* for all arguments that are passed in registers */
   while (args)
     {
-
+      int first = 1;
       if (IS_REGPARM (args->etype))
        {
          operand *opr = operandFromValue (args);
@@ -2913,9 +3119,8 @@ geniCodeReceive (value * args)
          if (!sym->addrtaken && !IS_VOLATILE (sym->etype))
            {
 
-             if (IN_FARSPACE (SPEC_OCLS (sym->etype)) &&
+             if ((IN_FARSPACE (SPEC_OCLS (sym->etype)) && !TARGET_IS_HC08) &&
                  options.stackAuto == 0 &&
-                 /* !TARGET_IS_DS390) */
                  (!(options.model == MODEL_FLAT24)) )
                {
                }
@@ -2931,8 +3136,12 @@ geniCodeReceive (value * args)
                }
            }
 
-         ic = newiCode (RECEIVE, NULL, NULL);
-         currFunc->recvSize = getSize (sym->etype);
+         ic = newiCode (RECEIVE, NULL, NULL);    
+         ic->argreg = SPEC_ARGREG(args->etype);
+         if (first) {
+             currFunc->recvSize = getSize (sym->type);
+             first = 0;
+         }
          IC_RESULT (ic) = opr;
          ADDTOCHAIN (ic);
        }
@@ -2969,7 +3178,7 @@ geniCodeFunctionBody (ast * tree,int lvl)
 
   /* create a proc icode */
   ic = newiCode (FUNCTION, func, NULL);
-  ic->lineno = OP_SYMBOL (func)->lineDef;
+  lineno=ic->lineno = OP_SYMBOL (func)->lineDef;
 
   ADDTOCHAIN (ic);
 
@@ -3076,6 +3285,8 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
   operand *boundary;
   symbol *falseLabel;
   set *labels = NULL;
+  int needRangeCheck = !optimize.noJTabBoundary
+                       || tree->values.switchVals.swDefault;
 
   if (!tree || !caseVals)
     return 0;
@@ -3084,7 +3295,8 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
   /* all integer numbers between the maximum & minimum must */
   /* be present , the maximum value should not exceed 255 */
   min = max = (int) floatFromVal (vch = caseVals);
-  sprintf (buffer, "_case_%d_%d",
+  SNPRINTF (buffer, sizeof(buffer), 
+           "_case_%d_%d",
           tree->values.switchVals.swNum,
           min);
   addSet (&labels, newiTempLabel (buffer));
@@ -3097,7 +3309,8 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
     {
       if (((t = (int) floatFromVal (vch)) - max) != 1)
        return 0;
-      sprintf (buffer, "_case_%d_%d",
+      SNPRINTF (buffer, sizeof(buffer), 
+               "_case_%d_%d",
               tree->values.switchVals.swNum,
               t);
       addSet (&labels, newiTempLabel (buffer));
@@ -3109,20 +3322,25 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
   /* if the number of case statements <= 2 then */
   /* it is not economical to create the jump table */
   /* since two compares are needed for boundary conditions */
-  if ((!optimize.noJTabBoundary && cnt <= 2) || max > (255 / 3))
+  if ((needRangeCheck && cnt <= 2) || max > (255 / 3))
     return 0;
 
   if (tree->values.switchVals.swDefault)
-    sprintf (buffer, "_default_%d", tree->values.switchVals.swNum);
+    {
+       SNPRINTF (buffer, sizeof(buffer), "_default_%d", tree->values.switchVals.swNum);
+    }
   else
-    sprintf (buffer, "_swBrk_%d", tree->values.switchVals.swNum);
+    {
+       SNPRINTF (buffer, sizeof(buffer), "_swBrk_%d", tree->values.switchVals.swNum);
+    }
+    
 
   falseLabel = newiTempLabel (buffer);
 
   /* so we can create a jumptable */
   /* first we rule out the boundary conditions */
   /* if only optimization says so */
-  if (!optimize.noJTabBoundary)
+  if (needRangeCheck)
     {
       sym_link *cetype = getSpec (operandType (cond));
       /* no need to check the lower bound if
@@ -3144,7 +3362,8 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
   if (min)
     {
       cond = geniCodeSubtract (cond, operandFromLit (min));
-      setOperandType (cond, UCHARTYPE);
+      if (!IS_LITERAL(getSpec(operandType(cond))))
+        setOperandType (cond, UCHARTYPE);
     }
 
   /* now create the jumptable */
@@ -3158,13 +3377,36 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
 /*-----------------------------------------------------------------*/
 /* geniCodeSwitch - changes a switch to a if statement             */
 /*-----------------------------------------------------------------*/
-void 
+void
 geniCodeSwitch (ast * tree,int lvl)
 {
   iCode *ic;
   operand *cond = geniCodeRValue (ast2iCode (tree->left,lvl+1), FALSE);
   value *caseVals = tree->values.switchVals.swVals;
   symbol *trueLabel, *falseLabel;
+      
+  /* If the condition is a literal, then just jump to the */
+  /* appropriate case label. */
+  if (IS_LITERAL(getSpec(operandType(cond))))
+    {
+      int switchVal, caseVal;
+      
+      switchVal = (int) floatFromVal (cond->operand.valOperand);
+      while (caseVals)
+        {
+          caseVal = (int) floatFromVal (caseVals);
+          if (caseVal == switchVal)
+            {
+              SNPRINTF (buffer, sizeof(buffer), "_case_%d_%d",
+                       tree->values.switchVals.swNum, caseVal);
+              trueLabel = newiTempLabel (buffer);
+              geniCodeGoto (trueLabel);
+              goto jumpTable;
+            }
+          caseVals = caseVals->next;
+        }
+      goto defaultOrBreak;
+    }
 
   /* if we can make this a jump table */
   if (geniCodeJumpTable (cond, caseVals, tree))
@@ -3178,7 +3420,7 @@ geniCodeSwitch (ast * tree,int lvl)
                                        operandFromValue (caseVals),
                                        EQ_OP);
 
-      sprintf (buffer, "_case_%d_%d",
+      SNPRINTF (buffer, sizeof(buffer), "_case_%d_%d",
               tree->values.switchVals.swNum,
               (int) floatFromVal (caseVals));
       trueLabel = newiTempLabel (buffer);
@@ -3189,12 +3431,16 @@ geniCodeSwitch (ast * tree,int lvl)
     }
 
 
-
+defaultOrBreak:
   /* if default is present then goto break else break */
   if (tree->values.switchVals.swDefault)
-    sprintf (buffer, "_default_%d", tree->values.switchVals.swNum);
+    {
+       SNPRINTF (buffer, sizeof(buffer), "_default_%d", tree->values.switchVals.swNum);
+    }
   else
-    sprintf (buffer, "_swBrk_%d", tree->values.switchVals.swNum);
+    {
+       SNPRINTF (buffer, sizeof(buffer), "_swBrk_%d", tree->values.switchVals.swNum);
+    }
 
   falseLabel = newiTempLabel (buffer);
   geniCodeGoto (falseLabel);
@@ -3236,6 +3482,34 @@ geniCodeArrayInit (ast * tree, operand *array)
   }
   ADDTOCHAIN (ic);
 }
+       
+/*-----------------------------------------------------------------*/
+/* geniCodeCritical - intermediate code for a critical statement   */
+/*-----------------------------------------------------------------*/
+static void 
+geniCodeCritical (ast *tree, int lvl)
+{
+  iCode *ic;
+  operand *op = NULL;
+
+  /* If op is NULL, the original interrupt state will saved on */
+  /* the stack. Otherwise, it will be saved in op. */
+  
+  /* Generate a save of the current interrupt state & disabled */
+  ic = newiCode (CRITICAL, NULL, NULL);
+  IC_RESULT (ic) = op;
+  ADDTOCHAIN (ic);
+  
+  /* Generate the critical code sequence */
+  if (tree->left && tree->left->type == EX_VALUE)
+    geniCodeDummyRead (ast2iCode (tree->left,lvl+1));
+  else
+    ast2iCode (tree->left,lvl+1);
+  
+  /* Generate a restore of the original interrupt state */
+  ic = newiCode (ENDCRITICAL, NULL, op);
+  ADDTOCHAIN (ic);
+}
 
 /*-----------------------------------------------------------------*/
 /* Stuff used in ast2iCode to modify geniCodeDerefPtr in some      */
@@ -3309,6 +3583,7 @@ ast2iCode (ast * tree,int lvl)
   operand *right = NULL;
   if (!tree)
     return NULL;
+
   /* set the global variables for filename & line number */
   if (tree->filename)
     filename = tree->filename;
@@ -3330,8 +3605,14 @@ ast2iCode (ast * tree,int lvl)
      (tree->opval.op == NULLOP ||
      tree->opval.op == BLOCK))
     {
-      ast2iCode (tree->left,lvl+1);
-      ast2iCode (tree->right,lvl+1);
+      if (tree->left && tree->left->type == EX_VALUE)
+        geniCodeDummyRead (ast2iCode (tree->left,lvl+1));
+      else
+        ast2iCode (tree->left,lvl+1);
+      if (tree->right && tree->right->type == EX_VALUE)
+        geniCodeDummyRead (ast2iCode (tree->right,lvl+1));
+      else
+        ast2iCode (tree->right,lvl+1);
       return NULL;
     }
 
@@ -3344,7 +3625,8 @@ ast2iCode (ast * tree,int lvl)
       tree->opval.op != GOTO &&
       tree->opval.op != SWITCH &&
       tree->opval.op != FUNCTION &&
-      tree->opval.op != INLINEASM)
+      tree->opval.op != INLINEASM &&
+      tree->opval.op != CRITICAL)
     {
 
         if (IS_ASSIGN_OP (tree->opval.op) ||
@@ -3417,13 +3699,13 @@ ast2iCode (ast * tree,int lvl)
       if (left)
        return geniCodePostInc (left);
       else
-       return geniCodePreInc (right);
+       return geniCodePreInc (right, tree->lvalue);
 
     case DEC_OP:               /* decrement operator */
       if (left)
        return geniCodePostDec (left);
       else
-       return geniCodePreDec (right);
+       return geniCodePreDec (right, tree->lvalue);
 
     case '&':                  /* bitwise and or address of operator */
       if (right)
@@ -3457,7 +3739,7 @@ ast2iCode (ast * tree,int lvl)
        return geniCodeDerefPtr (geniCodeRValue (left, FALSE),lvl);
 
     case '-':
-      if (right)
+      if (right) 
        return geniCodeSubtract (geniCodeRValue (left, FALSE),
                                 geniCodeRValue (right, FALSE));
       else
@@ -3466,7 +3748,7 @@ ast2iCode (ast * tree,int lvl)
     case '+':
       if (right)
        return geniCodeAdd (geniCodeRValue (left, FALSE),
-                           geniCodeRValue (right, FALSE),lvl, 0);
+                           geniCodeRValue (right, FALSE),lvl);
       else
        return geniCodeRValue (left, FALSE);    /* unary '+' has no meaning */
 
@@ -3477,16 +3759,33 @@ ast2iCode (ast * tree,int lvl)
     case RIGHT_OP:
       return geniCodeRightShift (geniCodeRValue (left, FALSE),
                                 geniCodeRValue (right, FALSE));
-    case CAST:
+    case CAST: 
+#if 0 // this indeed needs a second thought
+      {
+       operand *op;
+       
+       // let's keep this simple: get the rvalue we need
+       op=geniCodeRValue (right, FALSE);
+       // now cast it to whatever we want
+       op=geniCodeCast (operandType(left), op, FALSE);
+       // if this is going to be used as an lvalue, make it so
+       if (tree->lvalue) {
+         op->isaddr=1;
+       }
+       return op;
+      }
+#else // bug #604575, is it a bug ????
       return geniCodeCast (operandType (left),
                           geniCodeRValue (right, FALSE), FALSE);
+#endif
 
     case '~':
-    case '!':
     case RRC:
     case RLC:
+    case SWAP:
       return geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op);
 
+    case '!':
     case GETHBIT:
       {
        operand *op = geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op);
@@ -3501,9 +3800,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);
 
@@ -3556,7 +3867,7 @@ ast2iCode (ast * tree,int lvl)
        return geniCodeAssign (left,
                     geniCodeAdd (geniCodeRValue (operandFromOperand (left),
                                                  FALSE),
-                                 right,lvl,1), 0);
+                                 right,lvl), 0);
       }
     case SUB_ASSIGN:
       {
@@ -3650,6 +3961,9 @@ ast2iCode (ast * tree,int lvl)
     case ARRAYINIT:
        geniCodeArrayInit(tree, ast2iCode (tree->left,lvl+1));
        return NULL;
+    
+    case CRITICAL:
+       geniCodeCritical (tree, lvl);    
     }
 
   return NULL;
@@ -3687,3 +4001,35 @@ iCodeFromAst (ast * tree)
   ast2iCode (tree,0);
   return reverseiCChain ();
 }
+
+static const char *opTypeToStr(OPTYPE op)
+{
+    switch(op)
+    {
+      case SYMBOL: return "symbol";
+      case VALUE: return "value";
+      case TYPE: return "type";
+    }
+    return "undefined type";    
+}
+
+
+operand *validateOpType(operand        *op, 
+                       const char      *macro,
+                       const char      *args,
+                       OPTYPE          type,
+                       const char      *file, 
+                       unsigned        line)
+{    
+    if (op && op->type == type)
+    {
+       return op;
+    }
+    fprintf(stderr, 
+           "Internal error: validateOpType failed in %s(%s) @ %s:%u:"
+           " expected %s, got %s\n",
+           macro, args, file, line, 
+           opTypeToStr(type), op ? opTypeToStr(op->type) : "null op");
+    exit(-1);
+    return op; // never reached, makes compiler happy.
+}