* doc/Makefile,
[fw/sdcc] / src / SDCCicode.c
index 7e3321fce9c01432d6ff0f31eb91a4c99a112cbd..01bf6e6c232326da5db0bf8c6b5af430f9fc9256 100644 (file)
@@ -120,7 +120,8 @@ iCodeTable codeTable[] =
   {ARRAYINIT, "arrayInit", picGenericOne, NULL},
   {DUMMY_READ_VOLATILE, "dummy = (volatile)", picDummyRead, NULL},
   {CRITICAL, "critical_start", picCritical, NULL},
-  {ENDCRITICAL, "critical_end", picEndCritical, NULL}
+  {ENDCRITICAL, "critical_end", picEndCritical, NULL},
+  {SWAP, "swap", picGenericOne, NULL}
 };
 
 /*-----------------------------------------------------------------*/
@@ -233,12 +234,12 @@ 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 dp%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 a2p%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->isaddr, op->aggr2ptr, OP_SYMBOL (op)->isreqv, 
               OP_SYMBOL (op)->remat,OP_SYMBOL(op)->noSpilLoc,
               OP_SYMBOL(op)->ruonly,OP_SYMBOL(op)->dptr
        );
@@ -1527,16 +1528,15 @@ operandFromSymbol (symbol * sym)
     ok = 0;
 
   if (!IS_AGGREGATE (sym->type) &&     /* not an aggregate */
-      !IS_FUNC (sym->type) &&  /* not a function   */
-      !sym->_isparm &&         /* not a parameter  */
-      sym->level &&            /* is a local variable */
-      !sym->addrtaken &&       /* whose address has not been taken */
-      !sym->reqv &&            /* does not already have a reg equivalence */
+      !IS_FUNC (sym->type) &&          /* not a function   */
+      !sym->_isparm &&                 /* not a parameter  */
+      IS_AUTO (sym) &&                 /* is a local auto variable */
+      !sym->addrtaken &&               /* whose address has not been taken */
+      !sym->reqv &&                    /* does not already have a reg equivalence */
       !IS_VOLATILE (sym->etype) &&     /* not declared as volatile */
-      !IS_STATIC (sym->etype) &&       /* and not declared static  */
-      !sym->islbl &&           /* not a label */
-      ok &&                    /* farspace check */
-      !IS_BITVAR (sym->etype)  /* not a bit variable */
+      !sym->islbl &&                   /* not a label */
+      ok &&                            /* farspace check */
+      !IS_BITVAR (sym->etype)          /* not a bit variable */
     )
     {                                   
 
@@ -1920,7 +1920,13 @@ geniCodeCast (sym_link * type, operand * op, bool implicit)
        }
       }
     } else { // from a pointer to a pointer
-      if (port->s.gptr_size > port->s.fptr_size /*!TARGET_IS_Z80 && !TARGET_IS_GBZ80*/) {
+      if (IS_GENPTR(type) && IS_VOID(type->next))
+       { // cast to void* is always allowed
+       }
+      else if (IS_GENPTR(optype) && IS_VOID(optype->next))
+       { // cast from void* is always allowed
+       }
+      else 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
@@ -2301,7 +2307,7 @@ geniCodeAdd (operand * left, operand * right, RESULT_TYPE resultType, int lvl)
 }
 
 /*-----------------------------------------------------------------*/
-/* aggrToPtr - changes an aggregate to pointer to an aggregate     */
+/* aggrToPtr - changes an "aggregate" to a "pointer to aggregate"  */
 /*-----------------------------------------------------------------*/
 sym_link *
 aggrToPtr (sym_link * type, bool force)
@@ -2322,6 +2328,19 @@ aggrToPtr (sym_link * type, bool force)
   return ptype;
 }
 
+/*------------------------------------------------------------------*/
+/* aggrToPtrDclType - like aggrToPtr, but returns only the DCL_TYPE */
+/*------------------------------------------------------------------*/
+int
+aggrToPtrDclType (sym_link * type, bool force)
+{
+  if (IS_PTR (type) && !force)
+    return DCL_TYPE (type);
+
+  /* return the pointer depending on the storage class */
+  return PTR_TYPE (SPEC_OCLS (getSpec (type)));
+}
+
 /*-----------------------------------------------------------------*/
 /* geniCodeArray2Ptr - array to pointer                            */
 /*-----------------------------------------------------------------*/
@@ -2397,7 +2416,11 @@ geniCodeArray (operand * left, operand * right, int lvl)
                                      !IS_PTR (ltype->next))
                                     ? ltype : ltype->next), 0);
 
-  IC_RESULT (ic)->isaddr = (!IS_AGGREGATE (ltype->next));
+  if (!IS_AGGREGATE (ltype->next))
+    {
+      IC_RESULT (ic)->isaddr = 1;
+      IC_RESULT (ic)->aggr2ptr = 1;
+    }
   ADDTOCHAIN (ic);
 
   return IC_RESULT (ic);
@@ -2417,7 +2440,7 @@ geniCodeStruct (operand * left, operand * right, bool islval)
                                      right->operand.symOperand);
 
   wassert(IS_SYMOP(right));
-    
+
   /* add the offset */
   ic = newiCode ('+', left, operandFromLit (element->offset));
 
@@ -2430,10 +2453,10 @@ geniCodeStruct (operand * left, operand * right, bool islval)
   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);
@@ -2472,6 +2495,8 @@ geniCodePostInc (operand * op)
   geniCodeAssign (rOp, rv, 0, 0);
 
   size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1);
+  if (size == 0)
+    werror(W_SIZEOF_VOID);
   if (IS_FLOAT (rvtype))
     ic = newiCode ('+', rv, operandFromValue (constFloatVal ("1.0")));
   else
@@ -2507,8 +2532,9 @@ geniCodePreInc (operand * op, bool lvalue)
       return op;
     }
 
-
   size = (IS_PTR (roptype) ? getSize (roptype->next) : 1);
+  if (size == 0)
+    werror(W_SIZEOF_VOID);
   if (IS_FLOAT (roptype))
     ic = newiCode ('+', rop, operandFromValue (constFloatVal ("1.0")));
   else
@@ -2517,7 +2543,7 @@ geniCodePreInc (operand * op, bool lvalue)
   ADDTOCHAIN (ic);
 
   (void) geniCodeAssign (op, result, 0, 0);
-  if (lvalue || IS_TRUE_SYMOP (op))
+  if (lvalue || IS_TRUE_SYMOP (op) || IS_BITVAR (optype))
     return op;
   else
     return result;
@@ -2555,6 +2581,8 @@ geniCodePostDec (operand * op)
   geniCodeAssign (rOp, rv, 0, 0);
 
   size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1);
+  if (size == 0)
+    werror(W_SIZEOF_VOID);
   if (IS_FLOAT (rvtype))
     ic = newiCode ('-', rv, operandFromValue (constFloatVal ("1.0")));
   else
@@ -2590,8 +2618,9 @@ geniCodePreDec (operand * op, bool lvalue)
       return op;
     }
 
-
   size = (IS_PTR (roptype) ? getSize (roptype->next) : 1);
+  if (size == 0)
+    werror(W_SIZEOF_VOID);
   if (IS_FLOAT (roptype))
     ic = newiCode ('-', rop, operandFromValue (constFloatVal ("1.0")));
   else
@@ -2600,7 +2629,7 @@ geniCodePreDec (operand * op, bool lvalue)
   ADDTOCHAIN (ic);
 
   (void) geniCodeAssign (op, result, 0, 0);
-  if (lvalue || IS_TRUE_SYMOP (op))
+  if (lvalue || IS_TRUE_SYMOP (op) || IS_BITVAR (optype))
     return op;
   else
     return result;
@@ -3350,6 +3379,7 @@ geniCodeFunctionBody (ast * tree,int lvl)
   /* create a proc icode */
   ic = newiCode (FUNCTION, func, NULL);
   lineno=ic->lineno = OP_SYMBOL (func)->lineDef;
+  ic->tree = tree;
 
   ADDTOCHAIN (ic);
 
@@ -3365,6 +3395,7 @@ geniCodeFunctionBody (ast * tree,int lvl)
 
   /* now generate the end proc */
   ic = newiCode (ENDFUNCTION, func, NULL);
+  ic->tree = tree;
   ADDTOCHAIN (ic);
   return;
 }
@@ -3450,7 +3481,8 @@ exit:
 int 
 geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
 {
-  int min = 0, max = 0, t, cnt = 0;
+  int min, max, cnt = 1;
+  int i, t;
   value *vch;
   iCode *ic;
   operand *boundary;
@@ -3458,6 +3490,10 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
   set *labels = NULL;
   int needRangeCheck = !optimize.noJTabBoundary
                        || tree->values.switchVals.swDefault;
+  sym_link *cetype = getSpec (operandType (cond));
+  int sizeofMinCost, sizeofMaxCost;
+  int sizeofMatchJump, sizeofJumpTable;
+  int sizeIndex;
 
   if (!tree || !caseVals)
     return 0;
@@ -3465,50 +3501,122 @@ geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
   /* the criteria for creating a jump table is */
   /* all integer numbers between the maximum & minimum must */
   /* be present , the maximum value should not exceed 255 */
-  min = max = (int) floatFromVal (vch = caseVals);
-  SNPRINTF (buffer, sizeof(buffer), 
-           "_case_%d_%d",
-          tree->values.switchVals.swNum,
-          min);
-  addSet (&labels, newiTempLabel (buffer));
-
-  /* if there is only one case value then no need */
-  if (!(vch = vch->next))
-    return 0;
+  /* If not all integer numbers are present the algorithm */
+  /* inserts jumps to the default label for the missing numbers */
+  /* and decides later whether it is worth it */
+  min = (int) floatFromVal (vch = caseVals);
 
-  while (vch)
+  while (vch->next)
     {
-      if (((t = (int) floatFromVal (vch)) - max) != 1)
-       return 0;
-      SNPRINTF (buffer, sizeof(buffer), 
-               "_case_%d_%d",
-              tree->values.switchVals.swNum,
-              t);
-      addSet (&labels, newiTempLabel (buffer));
-      max = t;
       cnt++;
       vch = vch->next;
     }
+  max = (int) floatFromVal (vch);
 
-  /* 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 ((needRangeCheck && cnt <= 2) || max > (255 / 3))
+  /* Exit if the range is too large to handle with a jump table. */
+  if (1 + max - min > port->jumptableCost.maxCount)
     return 0;
 
-  if (tree->values.switchVals.swDefault)
+  switch (getSize (operandType (cond)))
     {
-       SNPRINTF (buffer, sizeof(buffer), "_default_%d", tree->values.switchVals.swNum);
+    case 1: sizeIndex = 0; break;
+    case 2: sizeIndex = 1; break;
+    case 4: sizeIndex = 2; break;
+    default: return 0;
     }
-  else
+  
+  /* Compute the size cost of the range check and subtraction. */
+  sizeofMinCost = 0;
+  sizeofMaxCost = 0;
+  if (needRangeCheck)
     {
-       SNPRINTF (buffer, sizeof(buffer), "_swBrk_%d", tree->values.switchVals.swNum);
+      if (!(min==0 && IS_UNSIGNED (cetype)))
+        sizeofMinCost = port->jumptableCost.sizeofRangeCompare[sizeIndex];
+      sizeofMaxCost = port->jumptableCost.sizeofRangeCompare[sizeIndex];
+    }
+  if (min)
+    sizeofMinCost += port->jumptableCost.sizeofSubtract;
+  
+  /* If the size cost of handling a non-zero minimum exceeds the */
+  /* cost of extending the range down to zero, then it might be */
+  /* better to extend the range to zero. */
+  if (min > 0 && sizeofMinCost >= (min * port->jumptableCost.sizeofElement))
+    {
+      /* Only extend the jump table if it would still be manageable. */
+      if (1 + max <= port->jumptableCost.maxCount)
+        min = 0;
     }
     
+  /* Compute the total size cost of a jump table. */
+  sizeofJumpTable = (1 + max - min) * port->jumptableCost.sizeofElement
+                     + port->jumptableCost.sizeofDispatch
+                     + sizeofMinCost + sizeofMaxCost;
+
+  /* Compute the total size cost of a match & jump sequence */
+  sizeofMatchJump = cnt * port->jumptableCost.sizeofMatchJump[sizeIndex];
+  
+  /* If the size cost of the jump table is uneconomical then exit */
+  if (sizeofMatchJump <  sizeofJumpTable)
+    return 0;
 
+  /* The jump table is preferable. */
+  
+  /* First, a label for the default or missing cases. */
+  if (tree->values.switchVals.swDefault)
+    {
+      SNPRINTF (buffer, sizeof(buffer),
+                "_default_%d",
+                tree->values.switchVals.swNum);
+    }
+  else
+    {
+      SNPRINTF (buffer, sizeof(buffer),
+                "_swBrk_%d",
+                tree->values.switchVals.swNum);
+    }
   falseLabel = newiTempLabel (buffer);
 
-  /* so we can create a jumptable */
+  /* Build the list of labels for the jump table. */
+  vch = caseVals;
+  t = (int) floatFromVal (vch);
+  for (i=min; i<=max; i++)
+    {
+      if (vch && t==i)
+        {
+          /* Explicit case: make a new label for it. */
+          SNPRINTF (buffer, sizeof(buffer), 
+                    "_case_%d_%d",
+                    tree->values.switchVals.swNum,
+                    i);
+          addSet (&labels, newiTempLabel (buffer));
+          vch = vch->next;
+          if (vch)
+            t = (int) floatFromVal (vch);
+        }
+      else
+        {
+          /* Implicit case: use the default label. */
+          addSet (&labels, falseLabel);
+        }
+    }
+
+  /* If cond is volatile, it might change after the boundary  */
+  /* conditions are tested to an out of bounds value, causing */
+  /* a jump to a location outside of the jump table. To avoid */
+  /* this possibility, use a non-volatile copy of it instead. */
+  if (IS_OP_VOLATILE (cond))
+    {
+      operand * newcond;
+      iCode * ic;
+      
+      newcond = newiTempOperand (operandType (cond), TRUE);
+      newcond->isvolatile = 0;
+      ic = newiCode ('=', NULL, cond);
+      IC_RESULT (ic) = newcond;
+      ADDTOCHAIN (ic);
+      cond = newcond;
+    }
+
   /* first we rule out the boundary conditions */
   /* if only optimization says so */
   if (needRangeCheck)