* src/SDCCopt.c (convertToFcall): fixed modulus with divisors 1 and ffffffffu
[fw/sdcc] / src / SDCCopt.c
index 863116101342ba22c3ba41db73fd3e30fe67aa63..bf6d4cbee4fc01a534b652222eccb918ace0331a 100644 (file)
@@ -67,39 +67,77 @@ cnvToFcall (iCode * ic, eBBlock * ebp)
   left = IC_LEFT (ic);
   right = IC_RIGHT (ic);
 
-  switch (ic->op)
-    {
-    case '+':
-      func = __fsadd;
-      break;
-    case '-':
-      func = __fssub;
-      break;
-    case '/':
-      func = __fsdiv;
-      break;
-    case '*':
-      func = __fsmul;
-      break;
-    case EQ_OP:
-      func = __fseq;
-      break;
-    case NE_OP:
-      func = __fsneq;
-      break;
-    case '<':
-      func = __fslt;
-      break;
-    case '>':
-      func = __fsgt;
-      break;
-    case LE_OP:
-      func = __fslteq;
-      break;
-    case GE_OP:
-      func = __fsgteq;
-      break;
-    }
+  if(IS_FLOAT(operandType( IC_RIGHT( ic ) ))) {
+    switch (ic->op)
+      {
+      case '+':
+        func = __fsadd;
+        break;
+      case '-':
+        func = __fssub;
+        break;
+      case '/':
+        func = __fsdiv;
+        break;
+      case '*':
+        func = __fsmul;
+        break;
+      case EQ_OP:
+        func = __fseq;
+        break;
+      case NE_OP:
+        func = __fsneq;
+        break;
+      case '<':
+        func = __fslt;
+        break;
+      case '>':
+        func = __fsgt;
+        break;
+      case LE_OP:
+        func = __fslteq;
+        break;
+      case GE_OP:
+        func = __fsgteq;
+        break;
+      }
+  } else
+  if(IS_FIXED16X16 (operandType (IC_RIGHT(ic)))) {
+    switch (ic->op)
+      {
+      case '+':
+        func = __fps16x16_add;
+        break;
+      case '-':
+        func = __fps16x16_sub;
+        break;
+      case '/':
+        func = __fps16x16_div;
+        break;
+      case '*':
+        func = __fps16x16_mul;
+        break;
+      case EQ_OP:
+        func = __fps16x16_eq;
+        break;
+      case NE_OP:
+        func = __fps16x16_neq;
+        break;
+      case '<':
+        func = __fps16x16_lt;
+        break;
+      case '>':
+        func = __fps16x16_gt;
+        break;
+      case LE_OP:
+        func = __fps16x16_lteq;
+        break;
+      case GE_OP:
+        func = __fps16x16_gteq;
+        break;
+      }
+  }
+  
 
   /* if float support routines NOT compiled as reentrant */
   if (!options.float_rent)
@@ -148,7 +186,8 @@ cnvToFcall (iCode * ic, eBBlock * ebp)
        {
          newic = newiCode (IPUSH, right, NULL);
          newic->parmPush = 1;
-         bytesPushed+=4;
+         //bytesPushed+=4;
+         bytesPushed += getSize(operandType(right));
        }
 
       addiCodeToeBBlock (ebp, newic, ip);
@@ -164,7 +203,8 @@ cnvToFcall (iCode * ic, eBBlock * ebp)
        {
          newic = newiCode (IPUSH, left, NULL);
          newic->parmPush = 1;
-         bytesPushed+=4;
+         //bytesPushed+=4;
+         bytesPushed += getSize(operandType(left));
        }
       addiCodeToeBBlock (ebp, newic, ip);
       newic->lineno = lineno;
@@ -174,6 +214,23 @@ cnvToFcall (iCode * ic, eBBlock * ebp)
   IC_RESULT (newic) = IC_RESULT (ic);
   newic->lineno = lineno;
   newic->parmBytes+=bytesPushed;
+  ebp->hasFcall = 1;
+  if (currFunc)
+    FUNC_HASFCALL (currFunc->type) = 1;
+    
+  if(TARGET_IS_PIC16) {
+       /* normally these functions aren't marked external, so we can use their
+        * _extern field to marked as already added to symbol table */
+
+       if(!SPEC_EXTR(func->etype)) {
+           memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+               
+               SPEC_EXTR(func->etype) = 1;
+               seg = SPEC_OCLS( func->etype );
+               addSet(&seg->syms, func);
+       }
+  }
+
   addiCodeToeBBlock (ebp, newic, ip);
 }
 
@@ -188,6 +245,7 @@ cnvToFloatCast (iCode * ic, eBBlock * ebp)
   sym_link *type = operandType (IC_RIGHT (ic));
   int linenno = ic->lineno;
   int bwd, su;
+  int bytesPushed=0;
 
   ip = ic->next;
   /* remove it from the iCode */
@@ -204,6 +262,12 @@ cnvToFloatCast (iCode * ic, eBBlock * ebp)
            }
        }
     }
+
+  if(compareType (type, fixed16x16Type) == 1) {
+    func = __fp16x16conv[0][3][0];
+    goto found;
+  }
+
   assert (0);
 found:
 
@@ -236,6 +300,7 @@ found:
        {
          newic = newiCode (IPUSH, IC_RIGHT (ic), NULL);
          newic->parmPush = 1;
+         bytesPushed += getSize(operandType(IC_RIGHT(ic)));
        }
       addiCodeToeBBlock (ebp, newic, ip);
       newic->lineno = linenno;
@@ -245,9 +310,118 @@ found:
   /* make the call */
   newic = newiCode (CALL, operandFromSymbol (func), NULL);
   IC_RESULT (newic) = IC_RESULT (ic);
+  newic->parmBytes+=bytesPushed;
+  ebp->hasFcall = 1;
+  if (currFunc)
+    FUNC_HASFCALL (currFunc->type) = 1;
+
+  if(TARGET_IS_PIC16) {
+       /* normally these functions aren't marked external, so we can use their
+        * _extern field to marked as already added to symbol table */
+
+       if(!SPEC_EXTR(func->etype)) {
+           memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+               
+               SPEC_EXTR(func->etype) = 1;
+               seg = SPEC_OCLS( func->etype );
+               addSet(&seg->syms, func);
+       }
+  }
+
   addiCodeToeBBlock (ebp, newic, ip);
   newic->lineno = linenno;
+}
+
+/*----------------------------------------------------------------------*/
+/* cnvToFixed16x16Cast - converts casts to fixed16x16 to function calls */
+/*----------------------------------------------------------------------*/
+static void 
+cnvToFixed16x16Cast (iCode * ic, eBBlock * ebp)
+{
+  iCode *ip, *newic;
+  symbol *func = NULL;
+  sym_link *type = operandType (IC_RIGHT (ic));
+  int linenno = ic->lineno;
+  int bwd, su;
+  int bytesPushed=0;
+
+  ip = ic->next;
+  /* remove it from the iCode */
+  remiCodeFromeBBlock (ebp, ic);
+  /* depending on the type */
+  for (bwd = 0; bwd < 3; bwd++)
+    {
+      for (su = 0; su < 2; su++)
+       {
+         if (compareType (type, __multypes[bwd][su]) == 1)
+           {
+             func = __fp16x16conv[0][bwd][su];
+             goto found;
+           }
+       }
+    }
+  assert (0);
+found:
+
+  /* if float support routines NOT compiled as reentrant */
+  if (!options.float_rent)
+    {
+      /* first one */
+       if (IS_REGPARM (FUNC_ARGS(func->type)->etype)) 
+           {
+               newic = newiCode (SEND, IC_RIGHT (ic), NULL);
+               newic->argreg = SPEC_ARGREG(FUNC_ARGS(func->type)->etype);
+           }
+      else
+       {
+         newic = newiCode ('=', NULL, IC_RIGHT (ic));
+         IC_RESULT (newic) = operandFromValue (FUNC_ARGS(func->type));
+       }
+      addiCodeToeBBlock (ebp, newic, ip);
+      newic->lineno = linenno;
+
+    }
+  else
+    {
+      /* push the left */
+       if (IS_REGPARM (FUNC_ARGS(func->type)->etype)) {
+           newic = newiCode (SEND, IC_RIGHT (ic), NULL);
+           newic->argreg = SPEC_ARGREG(FUNC_ARGS(func->type)->etype);
+       }
+      else
+       {
+         newic = newiCode (IPUSH, IC_RIGHT (ic), NULL);
+         newic->parmPush = 1;
+         bytesPushed += getSize(operandType(IC_RIGHT(ic)));
+       }
+      addiCodeToeBBlock (ebp, newic, ip);
+      newic->lineno = linenno;
+
+    }
 
+  /* make the call */
+  newic = newiCode (CALL, operandFromSymbol (func), NULL);
+  IC_RESULT (newic) = IC_RESULT (ic);
+  newic->parmBytes+=bytesPushed;
+  ebp->hasFcall = 1;
+  if (currFunc)
+    FUNC_HASFCALL (currFunc->type) = 1;
+
+  if(TARGET_IS_PIC16) {
+       /* normally these functions aren't marked external, so we can use their
+        * _extern field to marked as already added to symbol table */
+
+       if(!SPEC_EXTR(func->etype)) {
+           memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+               
+               SPEC_EXTR(func->etype) = 1;
+               seg = SPEC_OCLS( func->etype );
+               addSet(&seg->syms, func);
+       }
+  }
+
+  addiCodeToeBBlock (ebp, newic, ip);
+  newic->lineno = linenno;
 }
 
 /*-----------------------------------------------------------------*/
@@ -261,6 +435,7 @@ cnvFromFloatCast (iCode * ic, eBBlock * ebp)
   sym_link *type = operandType (IC_LEFT (ic));
   int lineno = ic->lineno;
   int bwd, su;
+  int bytesPushed=0;
 
   ip = ic->next;
   /* remove it from the iCode */
@@ -310,6 +485,7 @@ found:
        {
          newic = newiCode (IPUSH, IC_RIGHT (ic), NULL);
          newic->parmPush = 1;
+         bytesPushed += getSize(operandType(IC_RIGHT(ic)));
        }
       addiCodeToeBBlock (ebp, newic, ip);
       newic->lineno = lineno;
@@ -319,11 +495,130 @@ found:
   /* make the call */
   newic = newiCode (CALL, operandFromSymbol (func), NULL);
   IC_RESULT (newic) = IC_RESULT (ic);
+  newic->parmBytes+=bytesPushed;
+  ebp->hasFcall = 1;
+  if (currFunc)
+    FUNC_HASFCALL (currFunc->type) = 1;
+
+  if(TARGET_IS_PIC16) {
+       /* normally these functions aren't marked external, so we can use their
+        * _extern field to marked as already added to symbol table */
+
+       if(!SPEC_EXTR(func->etype)) {
+           memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+               
+               SPEC_EXTR(func->etype) = 1;
+               seg = SPEC_OCLS( func->etype );
+               addSet(&seg->syms, func);
+       }
+  }
+
   addiCodeToeBBlock (ebp, newic, ip);
   newic->lineno = lineno;
+}
+
+/*--------------------------------------------------------------------------*/
+/* cnvFromFixed16x16Cast - converts casts from fixed16x16 to function calls */
+/*--------------------------------------------------------------------------*/
+static void 
+cnvFromFixed16x16Cast (iCode * ic, eBBlock * ebp)
+{
+  iCode *ip, *newic;
+  symbol *func = NULL;
+  sym_link *type = operandType (IC_LEFT (ic));
+  int lineno = ic->lineno;
+  int bwd, su;
+  int bytesPushed=0;
+
+  ip = ic->next;
+  /* remove it from the iCode */
+  remiCodeFromeBBlock (ebp, ic);
+
+  /* depending on the type */
+  for (bwd = 0; bwd < 3; bwd++)
+    {
+      for (su = 0; su < 2; su++)
+       {
+         if (compareType (type, __multypes[bwd][su]) == 1)
+           {
+             func = __fp16x16conv[1][bwd][su];
+             goto found;
+           }
+       }
+    }
+    
+  if (compareType (type, floatType) == 1)
+    {
+      func = __fp16x16conv[1][3][0];
+      goto found;
+    }
+    
+  assert (0);
+found:
+
+  /* if float support routines NOT compiled as reentrant */
+  if (!options.float_rent)
+    {
+      /* first one */
+       if (IS_REGPARM (FUNC_ARGS(func->type)->etype)) {
+           newic = newiCode (SEND, IC_RIGHT (ic), NULL);
+           newic->argreg = SPEC_ARGREG(FUNC_ARGS(func->type)->etype);
+       }
+      else
+       {
+         newic = newiCode ('=', NULL, IC_RIGHT (ic));
+         IC_RESULT (newic) = operandFromValue (FUNC_ARGS(func->type));
+       }
+      addiCodeToeBBlock (ebp, newic, ip);
+      newic->lineno = lineno;
 
+    }
+  else
+    {
+
+      /* push the left */
+       if (IS_REGPARM (FUNC_ARGS(func->type)->etype)) {
+           newic = newiCode (SEND, IC_RIGHT (ic), NULL);
+           newic->argreg = SPEC_ARGREG(FUNC_ARGS(func->type)->etype);
+       }
+      else
+       {
+         newic = newiCode (IPUSH, IC_RIGHT (ic), NULL);
+         newic->parmPush = 1;
+         bytesPushed += getSize(operandType(IC_RIGHT(ic)));
+       }
+      addiCodeToeBBlock (ebp, newic, ip);
+      newic->lineno = lineno;
+
+    }
+
+  /* make the call */
+  newic = newiCode (CALL, operandFromSymbol (func), NULL);
+  IC_RESULT (newic) = IC_RESULT (ic);
+  newic->parmBytes+=bytesPushed;
+  ebp->hasFcall = 1;
+  if (currFunc)
+    FUNC_HASFCALL (currFunc->type) = 1;
+
+  if(TARGET_IS_PIC16) {
+       /* normally these functions aren't marked external, so we can use their
+        * _extern field to marked as already added to symbol table */
+
+       if(!SPEC_EXTR(func->etype)) {
+           memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+               
+               SPEC_EXTR(func->etype) = 1;
+               seg = SPEC_OCLS( func->etype );
+               addSet(&seg->syms, func);
+       }
+  }
+
+  addiCodeToeBBlock (ebp, newic, ip);
+  newic->lineno = lineno;
 }
 
+extern operand *geniCodeRValue (operand *, bool);
+
 /*-----------------------------------------------------------------*/
 /* convilong - converts int or long mults or divs to fcalls        */
 /*-----------------------------------------------------------------*/
@@ -338,8 +633,8 @@ convilong (iCode * ic, eBBlock * ebp, sym_link * type, int op)
   int su;
   int bytesPushed=0;
 
-  remiCodeFromeBBlock (ebp, ic);
-
+  remiCodeFromeBBlock (ebp, ic);    
+    
   /* depending on the type */
   for (bwd = 0; bwd < 3; bwd++)
     {
@@ -441,6 +736,23 @@ found:
   IC_RESULT (newic) = IC_RESULT (ic);
   newic->lineno = lineno;
   newic->parmBytes+=bytesPushed; // to clear the stack after the call
+  ebp->hasFcall = 1;
+  if (currFunc)
+    FUNC_HASFCALL (currFunc->type) = 1;
+
+  if(TARGET_IS_PIC16) {
+       /* normally these functions aren't marked external, so we can use their
+        * _extern field to marked as already added to symbol table */
+
+       if(!SPEC_EXTR(func->etype)) {
+           memmap *seg = SPEC_OCLS(OP_SYMBOL(IC_LEFT(newic))->etype);
+               
+               SPEC_EXTR(func->etype) = 1;
+               seg = SPEC_OCLS( func->etype );
+               addSet(&seg->syms, func);
+       }
+  }
+
   addiCodeToeBBlock (ebp, newic, ip);
 }
 
@@ -465,7 +777,8 @@ convertToFcall (eBBlock ** ebbs, int count)
             converted to function calls */
          if ((IS_CONDITIONAL (ic) ||
               IS_ARITHMETIC_OP (ic)) &&
-             (IS_FLOAT (operandType (IC_RIGHT (ic)))))
+             (IS_FLOAT (operandType (IC_RIGHT (ic)))
+               || IS_FIXED( operandType (IC_RIGHT (ic)))))
            {
 
              cnvToFcall (ic, ebbs[i]);
@@ -478,8 +791,46 @@ convertToFcall (eBBlock ** ebbs, int count)
                cnvFromFloatCast (ic, ebbs[i]);
              else if (IS_FLOAT (operandType (IC_LEFT (ic))))
                cnvToFloatCast (ic, ebbs[i]);
+             if (IS_FIXED16X16 (operandType (IC_RIGHT (ic))))
+               cnvFromFixed16x16Cast (ic, ebbs[i]);
+             else if (IS_FIXED16X16 (operandType (IC_LEFT (ic))))
+               cnvToFixed16x16Cast (ic, ebbs[i]);
            }
 
+          // Easy special case which avoids function call: modulo by a literal power
+          // of two can be replaced by a bitwise AND.
+          if (ic->op == '%' && isOperandLiteral(IC_RIGHT(ic)) &&
+              IS_UNSIGNED(operandType(IC_LEFT(ic))))
+            {
+              unsigned litVal = fabs(operandLitValue(IC_RIGHT(ic)));
+
+              /* modulo by 1: no remainder */
+              if (litVal == 1)
+                {
+                  ic->op = '=';
+                  IC_RIGHT (ic) = operandFromLit(0);
+                  IC_LEFT (ic) = NULL;
+                  continue;
+                }
+              // See if literal value is a power of 2.
+              while (litVal && !(litVal & 1))
+                {
+                  litVal >>= 1;
+                }
+              if (litVal)
+                {
+                  // discard lowest set bit.
+                  litVal >>= 1;
+                }
+
+              if (!litVal)
+                {
+                  ic->op = BITWISEAND;
+                  IC_RIGHT(ic) = operandFromLit(operandLitValue(IC_RIGHT(ic)) - 1);
+                  continue;
+                }
+            }
+
          /* if long / int mult or divide or mod */
          if (ic->op == '*' || ic->op == '/' || ic->op == '%')
            {
@@ -514,14 +865,47 @@ convertToFcall (eBBlock ** ebbs, int count)
     }
 }
 
+/*-----------------------------------------------------------------*/
+/* isLocalWithoutDef - return 1 if sym might be used without a     */
+/*                     defining iCode                              */
+/*-----------------------------------------------------------------*/
+static int
+isLocalWithoutDef (symbol * sym)
+{
+  if (!IS_AUTO (sym))
+    return 0;
+  
+  if (IS_VOLATILE (sym->type))
+    return 0;
+  
+  if (sym->_isparm)
+    return 0;
+  
+  if (IS_AGGREGATE (sym->type))
+    return 0;
+  
+  if (sym->addrtaken)
+    return 0;
+  
+  return !sym->defs;
+}
+
 /*-----------------------------------------------------------------*/
 /* replaceRegEqv - replace all local variables with their reqv     */
 /*-----------------------------------------------------------------*/
 static void 
-replaceRegEqv (eBBlock ** ebbs, int count)
+replaceRegEqv (ebbIndex * ebbi)
 {
+  eBBlock ** ebbs = ebbi->bbOrder;
+  int count = ebbi->count;
   int i;
 
+  /* Update the symbols' def bitvector so we know if there is   */
+  /* a defining iCode or not. Only replace a local variable     */
+  /* with its register equivalent if there is a defining iCode; */
+  /* otherwise, the port's register allocater may choke.        */
+  cseAllBlocks (ebbi, TRUE);
+
   for (i = 0; i < count; i++)
     {
 
@@ -535,7 +919,17 @@ replaceRegEqv (eBBlock ** ebbs, int count)
 
          if (ic->op == IFX)
            {
-
+             if (IC_COND (ic) &&
+                 IS_TRUE_SYMOP (IC_COND (ic)) &&
+                  isLocalWithoutDef (OP_SYMBOL (IC_COND (ic))))
+               {
+                 werrorfl (ic->filename, ic->lineno,
+                         W_LOCAL_NOINIT,
+                         OP_SYMBOL (IC_COND (ic))->name);
+                 OP_REQV (IC_COND (ic)) = NULL;
+                 OP_SYMBOL (IC_COND (ic))->allocreq = 1;
+               }
+             
              if (IS_TRUE_SYMOP (IC_COND (ic)) &&
                  OP_REQV (IC_COND (ic)))
                IC_COND (ic) = opFromOpWithDU (OP_REQV (IC_COND (ic)),
@@ -545,8 +939,20 @@ replaceRegEqv (eBBlock ** ebbs, int count)
              continue;
            }
 
+         
          if (ic->op == JUMPTABLE)
            {
+             if (IC_JTCOND (ic) &&
+                 IS_TRUE_SYMOP (IC_JTCOND (ic)) &&
+                  isLocalWithoutDef (OP_SYMBOL (IC_JTCOND (ic))))
+               {
+                 werrorfl (ic->filename, ic->lineno,
+                         W_LOCAL_NOINIT,
+                         OP_SYMBOL (IC_JTCOND (ic))->name);
+                 OP_REQV (IC_JTCOND (ic)) = NULL;
+                 OP_SYMBOL (IC_JTCOND (ic))->allocreq = 1;
+               }
+             
              if (IS_TRUE_SYMOP (IC_JTCOND (ic)) &&
                  OP_REQV (IC_JTCOND (ic)))
                IC_JTCOND (ic) = opFromOpWithDU (OP_REQV (IC_JTCOND (ic)),
@@ -579,6 +985,17 @@ replaceRegEqv (eBBlock ** ebbs, int count)
                                          OP_SYMBOL (IC_RESULT (ic))->uses);
            }
 
+         if (IC_RIGHT (ic) &&
+             IS_TRUE_SYMOP (IC_RIGHT (ic)) &&
+             isLocalWithoutDef (OP_SYMBOL (IC_RIGHT (ic))))
+           {
+             werrorfl (ic->filename, ic->lineno,
+                       W_LOCAL_NOINIT,
+                       OP_SYMBOL (IC_RIGHT (ic))->name);
+             OP_REQV (IC_RIGHT (ic)) = NULL;
+             OP_SYMBOL (IC_RIGHT (ic))->allocreq = 1;
+           }
+         
          if (IC_RIGHT (ic) &&
              IS_TRUE_SYMOP (IC_RIGHT (ic)) &&
              OP_REQV (IC_RIGHT (ic)))
@@ -589,6 +1006,17 @@ replaceRegEqv (eBBlock ** ebbs, int count)
              IC_RIGHT (ic)->isaddr = 0;
            }
 
+         if (IC_LEFT (ic) &&
+             IS_TRUE_SYMOP (IC_LEFT (ic)) &&
+             isLocalWithoutDef (OP_SYMBOL (IC_LEFT (ic))))
+           {
+             werrorfl (ic->filename, ic->lineno,
+                       W_LOCAL_NOINIT,
+                       OP_SYMBOL (IC_LEFT (ic))->name);
+             OP_REQV (IC_LEFT (ic)) = NULL;
+             OP_SYMBOL (IC_LEFT (ic))->allocreq = 1;
+           }
+            
          if (IC_LEFT (ic) &&
              IS_TRUE_SYMOP (IC_LEFT (ic)) &&
              OP_REQV (IC_LEFT (ic)))
@@ -602,12 +1030,59 @@ replaceRegEqv (eBBlock ** ebbs, int count)
     }
 }
 
+/*-----------------------------------------------------------------*/
+/* findReqv - search for a register equivalent                     */
+/*-----------------------------------------------------------------*/
+operand *
+findReqv (symbol * prereqv, eBBlock ** ebbs, int count)
+{
+  int i;
+  iCode * ic;
+  
+  /* for all blocks do */
+  for (i=0; i<count; i++)
+    {
+      /* for all instructions in the block do */
+      for (ic = ebbs[i]->sch; ic; ic = ic->next)
+       {
+         if (ic->op == IFX)
+           {
+             if (IS_ITEMP (IC_COND (ic))
+                 && OP_SYMBOL (IC_COND (ic))->prereqv == prereqv)
+               return IC_COND (ic);
+           }
+         else if (ic->op == JUMPTABLE)
+           {
+             if (IS_ITEMP (IC_JTCOND (ic))
+                 && OP_SYMBOL (IC_JTCOND (ic))->prereqv == prereqv)
+               return IC_JTCOND (ic);
+           }
+         else
+           {
+             if (IS_ITEMP (IC_LEFT (ic))
+                 && OP_SYMBOL (IC_LEFT (ic))->prereqv == prereqv)
+               return IC_LEFT (ic);
+             if (IS_ITEMP (IC_RIGHT (ic))
+                 && OP_SYMBOL (IC_RIGHT (ic))->prereqv == prereqv)
+               return IC_RIGHT (ic);
+             if (IS_ITEMP (IC_RESULT (ic))
+                 && OP_SYMBOL (IC_RESULT (ic))->prereqv == prereqv)
+               return IC_RESULT (ic);
+           }
+       }
+    }
+  
+  return NULL;
+}
+
 /*-----------------------------------------------------------------*/
 /* killDeadCode - eliminates dead assignments                      */
 /*-----------------------------------------------------------------*/
 int 
-killDeadCode (eBBlock ** ebbs, int count)
+killDeadCode (ebbIndex * ebbi)
 {
+  eBBlock ** ebbs = ebbi->dfOrder;
+  int count = ebbi->count;
   int change = 1;
   int gchange = 0;
   int i = 0;
@@ -643,9 +1118,16 @@ killDeadCode (eBBlock ** ebbs, int count)
 
              if (SKIP_IC (ic) ||
                  ic->op == IFX ||
-                 ic->op == RETURN)
+                 ic->op == RETURN ||
+                  ic->op == DUMMY_READ_VOLATILE ||
+                  ic->op == CRITICAL ||
+                  ic->op == ENDCRITICAL)
                continue;
 
+             /* Since both IFX & JUMPTABLE (in SKIP_IC) have been tested for */
+             /* it is now safe to assume IC_LEFT, IC_RIGHT, & IC_RESULT are  */
+             /* valid. */
+
              /* if the result is volatile then continue */
              if (IC_RESULT (ic) && isOperandVolatile (IC_RESULT (ic), FALSE))
                continue;
@@ -653,6 +1135,10 @@ killDeadCode (eBBlock ** ebbs, int count)
              /* if the result is a temp & isaddr then skip */
              if (IC_RESULT (ic) && POINTER_SET (ic))
                continue;
+              
+              if (POINTER_GET (ic) && IS_VOLATILE (operandType (IC_LEFT (ic))->next)
+                 && !SPIL_LOC (IC_RESULT (ic)))
+                continue;
 
              /* if the result is used in the remainder of the */
              /* block then skip */
@@ -689,17 +1175,45 @@ killDeadCode (eBBlock ** ebbs, int count)
                    continue;
 
                  kill = 1;
-               }
+                }
 
            kill:
              /* kill this one if required */
              if (kill)
                {
+                 bool volLeft = IS_SYMOP (IC_LEFT (ic))
+                                && isOperandVolatile (IC_LEFT (ic), FALSE);
+                 bool volRight = IS_SYMOP (IC_RIGHT (ic)) 
+                                 && isOperandVolatile (IC_RIGHT (ic), FALSE);
+
+                 /* a dead address-of operation should die, even if volatile */
+                 if (ic->op == ADDRESS_OF)
+                   volLeft = FALSE;
+              
+                 if (ic->next && ic->seqPoint == ic->next->seqPoint
+                     && (ic->next->op == '+' || ic->next->op == '-'))
+                   {
+                     if (isOperandEqual (IC_LEFT(ic), IC_LEFT(ic->next))
+                         || isOperandEqual (IC_LEFT(ic), IC_RIGHT(ic->next)))
+                       volLeft = FALSE;
+                     if (isOperandEqual (IC_RIGHT(ic), IC_LEFT(ic->next))
+                         || isOperandEqual (IC_RIGHT(ic), IC_RIGHT(ic->next)))
+                       volRight = FALSE;
+                   }
+                 
+                 if (POINTER_GET (ic) && IS_VOLATILE (operandType (IC_LEFT (ic))->next))
+                   {
+                     if (SPIL_LOC (IC_RESULT (ic)))
+                       {
+                         IC_RESULT (ic) = newiTempFromOp (IC_RESULT (ic));
+                         SPIL_LOC (IC_RESULT (ic)) = NULL;
+                       }
+                     continue;
+                   }
+                                 
                  change = 1;
                  gchange++;
-                 /* eliminate this */
-                 remiCodeFromeBBlock (ebbs[i], ic);
-
+                 
                  /* now delete from defUseSet */
                  deleteItemIf (&ebbs[i]->outExprs, ifDiCodeIsX, ic);
                  bitVectUnSetBit (ebbs[i]->outDefs, ic->key);
@@ -707,18 +1221,62 @@ killDeadCode (eBBlock ** ebbs, int count)
                  /* and defset of the block */
                  bitVectUnSetBit (ebbs[i]->defSet, ic->key);
 
-                 /* for the left & right remove the usage */
-                 if (IS_SYMOP (IC_LEFT (ic)))
-                   bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key);
+                 /* If this is the last of a register equivalent, */
+                 /* look for a successor register equivalent. */
+                 bitVectUnSetBit (OP_DEFS (IC_RESULT (ic)), ic->key);
+                 if (IS_ITEMP (IC_RESULT (ic))
+                     && OP_SYMBOL (IC_RESULT (ic))->isreqv
+                     && bitVectIsZero (OP_DEFS (IC_RESULT (ic))))
+                   {
+                     symbol * resultsym = OP_SYMBOL (IC_RESULT (ic));
+                     symbol * prereqv = resultsym->prereqv;
+                     
+                     if (prereqv && prereqv->reqv && (OP_SYMBOL (prereqv->reqv) == resultsym))
+                       {
+                         operand * newreqv;
+
+                         IC_RESULT (ic) = NULL;
+                         newreqv = findReqv (prereqv, ebbs, count);
+                         if (newreqv)
+                           {
+                             prereqv->reqv = newreqv;
+                           }
+                       }
+                   }
 
-                 if (IS_SYMOP (IC_RIGHT (ic)))
-                   bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key);
+                 /* delete the result */
+                 IC_RESULT (ic) = NULL;
+                 
+                 if (volLeft || volRight)
+                   {
+                     /* something is volatile, so keep the iCode */
+                     /* and change the operator instead */
+                     ic->op = DUMMY_READ_VOLATILE;
+
+                     /* keep only the volatile operands */      
+                     if (!volLeft)
+                       IC_LEFT (ic) = NULL;
+                     if (!volRight)
+                       IC_RIGHT (ic) = NULL;
+                   }
+                 else
+                   {
+                     /* nothing is volatile, eliminate the iCode */
+                     remiCodeFromeBBlock (ebbs[i], ic);
+
+                     /* for the left & right remove the usage */
+                     if (IS_SYMOP (IC_LEFT (ic)))
+                       bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key);
+
+                     if (IS_SYMOP (IC_RIGHT (ic)))
+                       bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key);
+                   }
                }
 
            }                   /* end of all instructions */
 
          if (!ebbs[i]->sch && !ebbs[i]->noPath)
-           disconBBlock (ebbs[i], ebbs, count);
+           disconBBlock (ebbs[i], ebbi);
 
        }                       /* end of for all blocks */
 
@@ -778,6 +1336,76 @@ discardDeadParamReceives (eBBlock ** ebbs, int count)
     }
 }
 
+/*-----------------------------------------------------------------*/
+/* optimizeCastCast - remove unneeded intermediate casts.          */
+/* Integer promotion may cast (un)signed char to int and then      */
+/* recast the int to (un)signed long. If the signedness of the     */
+/* char and long are the same, the cast can be safely performed in */
+/* a single step.                                                  */
+/*-----------------------------------------------------------------*/
+static void 
+optimizeCastCast (eBBlock ** ebbs, int count)
+{
+  int i;
+  iCode *ic;
+  iCode *uic;
+  sym_link * type1;
+  sym_link * type2;
+  sym_link * type3;
+  symbol * sym;
+
+  for (i = 0; i < count; i++)
+    {
+      for (ic = ebbs[i]->sch; ic; ic = ic->next)
+       {
+         
+         if (ic->op == CAST && IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
+           {
+             type1 = operandType (IC_RIGHT (ic));
+             type2 = operandType (IC_RESULT (ic));
+
+             /* Look only for a cast from an integer type to an */
+             /* integer type that has no loss of bits */
+             if (!IS_INTEGRAL (type1) || !IS_INTEGRAL (type2))
+               continue;
+             if (getSize (type2) < getSize (type1))
+               continue;
+             
+             /* There must be only one use of this first result */
+             if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) != 1)
+               continue;
+             
+             /* This use must be a second cast */
+             uic = hTabItemWithKey (iCodehTab,
+                       bitVectFirstBit (OP_USES (IC_RESULT (ic))));
+             if (!uic || uic->op != CAST)
+               continue;
+  
+             /* It must be a cast to another integer type that */
+             /* has no loss of bits */
+             type3 = operandType (IC_RESULT (uic));
+             if (!IS_INTEGRAL (type3))
+                continue;
+             if (getSize (type3) < getSize (type2))
+                continue;
+             
+             /* The signedness between the first and last types */
+             /* must match */
+             if (SPEC_USIGN (type3) != SPEC_USIGN (type1))
+                continue;
+
+             /* Change the first cast to a simple assignment and */
+             /* let the second cast do all the work */
+             ic->op = '=';
+             IC_LEFT (ic) = NULL;
+             sym = OP_SYMBOL (IC_RESULT (ic));
+             sym->type = copyLinkChain (type1);
+             sym->etype = getSpec (sym->type);
+           }
+       }
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* eBBlockFromiCode - creates extended basic blocks from iCode     */
 /*                    will return an array of eBBlock pointers     */
@@ -785,9 +1413,7 @@ discardDeadParamReceives (eBBlock ** ebbs, int count)
 eBBlock **
 eBBlockFromiCode (iCode * ic)
 {
-  eBBlock **ebbs = NULL;
-  int count = 0;
-  int saveCount = 0;
+  ebbIndex *ebbi = NULL;
   int change = 1;
   int lchange = 0;
   int kchange = 0;
@@ -797,7 +1423,6 @@ eBBlockFromiCode (iCode * ic)
   if (!ic)
     return NULL;
 
-  count = 0;
   eBBNum = 0;
 
   /* optimize the chain for labels & gotos 
@@ -806,65 +1431,72 @@ eBBlockFromiCode (iCode * ic)
   ic = iCodeLabelOptimize (ic);
 
   /* break it down into basic blocks */
-  ebbs = iCodeBreakDown (ic, &count);
-  saveCount = count;
-
+  ebbi = iCodeBreakDown (ic);
+  
+  /* hash the iCode keys so that we can quickly index */
+  /* them in the rest of the optimization steps */
+  setToNull ((void *) &iCodehTab);
+  iCodehTab = newHashTable (iCodeKey);
+  hashiCodeKeys (ebbi->bbOrder, ebbi->count);
+  
   /* compute the control flow */
-  computeControlFlow (ebbs, count, 0);
+  computeControlFlow (ebbi);
 
   /* dumpraw if asked for */
   if (options.dump_raw)
-    dumpEbbsToFileExt (DUMP_RAW0, ebbs, count);
+    dumpEbbsToFileExt (DUMP_RAW0, ebbi);
 
   /* replace the local variables with their
      register equivalents : the liveRange computation
      along with the register allocation will determine
      if it finally stays in the registers */
-  replaceRegEqv (ebbs, count);
+  replaceRegEqv (ebbi);
 
   /* create loop regions */
-  loops = createLoopRegions (ebbs, count);
+  loops = createLoopRegions (ebbi);
 
   /* dumpraw if asked for */
   if (options.dump_raw)
-    dumpEbbsToFileExt (DUMP_RAW1, ebbs, count);
+    dumpEbbsToFileExt (DUMP_RAW1, ebbi);
 
+  optimizeCastCast (ebbi->bbOrder, ebbi->count);
+    
   /* do common subexpression elimination for each block */
-  change = cseAllBlocks (ebbs, saveCount, FALSE);
+  change = cseAllBlocks (ebbi, FALSE);
 
   /* dumpraw if asked for */
   if (options.dump_raw)
-    dumpEbbsToFileExt (DUMP_CSE, ebbs, count);
+    dumpEbbsToFileExt (DUMP_CSE, ebbi);
 
   /* compute the data flow */
-  computeDataFlow (ebbs, saveCount);
+  computeDataFlow (ebbi);
 
   /* dumpraw if asked for */
   if (options.dump_raw)
-    dumpEbbsToFileExt (DUMP_DFLOW, ebbs, count);
+    dumpEbbsToFileExt (DUMP_DFLOW, ebbi);
 
   /* global common subexpression elimination  */
   if (optimize.global_cse)
     {
-      change += cseAllBlocks (ebbs, saveCount, TRUE);
+      change += cseAllBlocks (ebbi, FALSE);
       if (options.dump_gcse)
-       dumpEbbsToFileExt (DUMP_GCSE, ebbs, saveCount);
+       dumpEbbsToFileExt (DUMP_GCSE, ebbi);
     }
   else
     {
       // compute the dataflow only
-      assert(cseAllBlocks (ebbs, saveCount, FALSE)==0);
+      assert(cseAllBlocks (ebbi, TRUE)==0);
     }
   /* kill dead code */
-  kchange = killDeadCode (ebbs, saveCount);
+  kchange = killDeadCode (ebbi);
 
   if (options.dump_kill)
-    dumpEbbsToFileExt (DUMP_DEADCODE, ebbs, count);
+    dumpEbbsToFileExt (DUMP_DEADCODE, ebbi);
 
   /* do loop optimizations */
-  change += (lchange = loopOptimizations (loops, ebbs, count));
+  change += (lchange = loopOptimizations (loops, ebbi));
   if (options.dump_loop)
-    dumpEbbsToFileExt (DUMP_LOOP, ebbs, count);
+    dumpEbbsToFileExt (DUMP_LOOP, ebbi);
 
   /* recompute the data flow and apply global cse again 
      if loops optimizations or dead code caused a change:
@@ -875,36 +1507,39 @@ eBBlockFromiCode (iCode * ic)
      subexpression once more */
   if (lchange || kchange)
     {
-      computeDataFlow (ebbs, saveCount);
-      change += cseAllBlocks (ebbs, saveCount, TRUE);
+      computeDataFlow (ebbi);
+      change += cseAllBlocks (ebbi, FALSE);
       if (options.dump_loop)
-       dumpEbbsToFileExt (DUMP_LOOPG, ebbs, count);
+       dumpEbbsToFileExt (DUMP_LOOPG, ebbi);
 
       /* if loop optimizations caused a change then do
          dead code elimination once more : this will
          get rid of the extra assignments to the induction
          variables created during loop optimizations */
-      killDeadCode (ebbs, saveCount);
+      killDeadCode (ebbi);
 
       if (options.dump_loop)
-       dumpEbbsToFileExt (DUMP_LOOPD, ebbs, count);
+       dumpEbbsToFileExt (DUMP_LOOPD, ebbi);
 
     }
 
   /* sort it back by block number */
-  qsort (ebbs, saveCount, sizeof (eBBlock *), bbNumCompare);
+  //qsort (ebbs, saveCount, sizeof (eBBlock *), bbNumCompare);
 
   if (!options.lessPedantic) {
     // this is a good place to check missing return values
     if (currFunc) {
-      if (!IS_VOID(currFunc->etype)) {
+      // the user is on his own with naked functions...
+      if (!IS_VOID(currFunc->etype)
+       && !FUNC_ISNAKED(currFunc->type)) {
        eBBlock *bp;
        // make sure all predecessors of the last block end in a return
-       for (bp=setFirstItem(ebbs[saveCount-1]->predList); 
+       for (bp=setFirstItem(ebbi->bbOrder[ebbi->count-1]->predList); 
             bp; 
-            bp=setNextItem(ebbs[saveCount-1]->predList)) {
+            bp=setNextItem(ebbi->bbOrder[ebbi->count-1]->predList)) {
          if (bp->ech->op != RETURN) {
-           werror (W_VOID_FUNC, currFunc->name);
+           werrorfl (bp->ech->filename, bp->ech->lineno,
+                     W_VOID_FUNC, currFunc->name);
          }
        }
       }
@@ -913,34 +1548,31 @@ eBBlockFromiCode (iCode * ic)
 
   /* if cyclomatic info requested then print it */
   if (options.cyclomatic)
-    printCyclomatic (ebbs, saveCount);
+    printCyclomatic (ebbi->bbOrder, ebbi->count);
 
   /* convert operations with support routines
      written in C to function calls : Iam doing
      this at this point since I want all the
      operations to be as they are for optimzations */
-  convertToFcall (ebbs, count);
+  convertToFcall (ebbi->bbOrder, ebbi->count);
 
   /* compute the live ranges */
-  computeLiveRanges (ebbs, count);
+  computeLiveRanges (ebbi->bbOrder, ebbi->count);
 
   if (options.dump_range)
-    dumpEbbsToFileExt (DUMP_RANGE, ebbs, count);
+    dumpEbbsToFileExt (DUMP_RANGE, ebbi);
 
   /* Now that we have the live ranges, discard parameter
    * receives for unused parameters.
    */
-  discardDeadParamReceives (ebbs, count);
+  discardDeadParamReceives (ebbi->bbOrder, ebbi->count);
 
   /* allocate registers & generate code */
-  port->assignRegisters (ebbs, count);
+  port->assignRegisters (ebbi);
 
   /* throw away blocks */
-  setToNull ((void **) &graphEdges);
-  ebbs = NULL;
+  setToNull ((void *) &graphEdges);
   
-  currFunc=NULL;
-
   return NULL;
 }