* src/SDCCast.c (resolveSymbols): added reentrancy check for parameters
[fw/sdcc] / src / SDCCast.c
index 5103dc5d9123ffdba30e0a9ee59c8a6b685cdcdd..97581fee14dd9027cef9b8f717dc3f4eef0d7aae 100644 (file)
@@ -31,6 +31,11 @@ set *astList = NULL;
 set *operKeyReset = NULL;
 ast *staticAutos = NULL;
 int labelKey = 1;
+static struct {
+  int count;            /* number of inline functions inserted */
+  symbol * retsym;      /* variable for inlined function return value */
+  symbol * retlab;      /* label ending inlined function (virtual return) */
+} inlineState;
 
 #define LRVAL(x) x->left->rvalue
 #define RRVAL(x) x->right->rvalue
@@ -386,6 +391,9 @@ ast * createRMW (ast *target, unsigned op, ast *operand)
         tempvar1 = replaceAstWithTemporary(&(target->left));
       if (hasSEFcalls(target->right))
         tempvar2 = replaceAstWithTemporary(&(target->right));
+    } else if ((target->opval.op == INC_OP) || (target->opval.op == DEC_OP)) {
+      /* illegal pre/post-increment/decrement */
+      werrorfl (target->filename, target->lineno, E_LVALUE_REQUIRED, "=");
     } else {
       /* we would have to handle '.', but it is not generated any more */
       wassertl(target->opval.op != '.', "obsolete opcode in tree");
@@ -561,7 +569,7 @@ resolveSymbols (ast * tree)
 
       symbol *csym = findSymWithLevel (SymbolTab, tree->opval.val->sym);
 
-      /* if found in the symbol table & they r not the same */
+      /* if found in the symbol table & they are not the same */
       if (csym && tree->opval.val->sym != csym)
         {
           tree->opval.val->sym = csym;
@@ -570,8 +578,8 @@ resolveSymbols (ast * tree)
         }
 
       /* if not found in the symbol table */
-      /* mark it as undefined assume it is */
-      /* an integer in data space         */
+      /* mark it as undefined & assume it */
+      /* is an integer in data space      */
       if (!csym && !tree->opval.val->sym->implicit)
         {
 
@@ -775,15 +783,15 @@ processParms (ast *func,
   else
     functype = func->ftype;
 
-  /* if the function is being called via a pointer &   */
-  /* it has not been defined reentrant then we cannot */
-  /* have parameters                                   */
+  /* if the function is being called via a pointer &  */
+  /* it has not been defined reentrant then we cannot */
+  /* have parameters                                  */
   /* PIC16 port can... */
   if (!TARGET_IS_PIC16)
     {
       if (func->type != EX_VALUE && !IFFUNC_ISREENT (functype) && !options.stackAuto)
         {
-          werror (W_NONRENT_ARGS);
+          werror (E_NONRENT_ARGS);
           fatalError++;
           return 1;
         }
@@ -922,6 +930,18 @@ processParms (ast *func,
   (*actParm)->etype = getSpec ((*actParm)->ftype = copyLinkChain ((*actParm)->ftype));
   SPEC_REGPARM ((*actParm)->etype) = SPEC_REGPARM (defParm->etype);
   SPEC_ARGREG  ((*actParm)->etype) = SPEC_ARGREG (defParm->etype);
+
+  /* if the function is being called via a pointer &  */
+  /* this parameter is not passed in registers        */
+  /* then the function must be defined reentrant      */
+  if (IS_FUNCPTR (func->ftype) && !SPEC_REGPARM ((*actParm)->etype) &&
+      !IFFUNC_ISREENT (functype) && !options.stackAuto)
+    {
+      werror (E_NONRENT_ARGS);
+      fatalError++;
+      return 1;
+    }
+
   (*parmNumber)++;
   return 0;
 }
@@ -1099,8 +1119,7 @@ createIvalCharPtr (ast * sym, sym_link * type, ast * iexpr, ast *rootVal)
                         && IS_ARRAY (iexpr->ftype)))
     return newNode ('=', sym, iexpr);
 
-  /* left side is an array so we have to assign each */
-  /* element                                         */
+  /* left side is an array so we have to assign each element */
   if ((IS_LITERAL (iexpr->etype) ||
        SPEC_SCLS (iexpr->etype) == S_CODE)
       && IS_ARRAY (iexpr->ftype))
@@ -1220,7 +1239,7 @@ ast * initAggregates (symbol * sym, initList * ival, ast * wid) {
 
 /*-----------------------------------------------------------------*/
 /* gatherAutoInit - creates assignment expressions for initial     */
-/*    values                 */
+/*                  values                                         */
 /*-----------------------------------------------------------------*/
 static ast *
 gatherAutoInit (symbol * autoChain)
@@ -1528,13 +1547,13 @@ constExprValue (ast * cexpr, int check)
           cexpr->opval.op == CAST &&
           IS_LITERAL (cexpr->right->ftype))
         {
-        return valCastLiteral (cexpr->ftype,
-                               floatFromVal (cexpr->right->opval.val));
+          return valCastLiteral (cexpr->ftype,
+                                 floatFromVal (cexpr->right->opval.val));
         }
 
       if (IS_AST_VALUE (cexpr))
         {
-        return cexpr->opval.val;
+          return cexpr->opval.val;
         }
 
       if (check)
@@ -1548,7 +1567,7 @@ constExprValue (ast * cexpr, int check)
     {
       return cexpr->opval.val;
     }
-   return NULL;
+  return NULL;
 }
 
 /*-----------------------------------------------------------------*/
@@ -1567,7 +1586,6 @@ isLabelInAst (symbol * label, ast * tree)
 
   return isLabelInAst (label, tree->right) &&
     isLabelInAst (label, tree->left);
-
 }
 
 /*-----------------------------------------------------------------*/
@@ -1680,7 +1698,7 @@ isLoopCountable (ast * initExpr, ast * condExpr, ast * loopExpr,
           if (IS_AST_SYM_VALUE (loopExpr->left) &&
               isSymbolEqual (*sym, AST_SYMBOL (loopExpr->left)) &&
               IS_AST_LIT_VALUE (loopExpr->right) &&
-              (int) AST_LIT_VALUE (loopExpr->right) != 1)
+              AST_ULONG_VALUE (loopExpr->right) != 1)
             return TRUE;
         }
     }
@@ -2184,8 +2202,7 @@ getResultTypeFromType (sym_link *type)
     }
   if (IS_CHAR (type))
     return RESULT_TYPE_CHAR;
-  if (   IS_INT (type)
-      && !IS_LONG (type))
+  if (IS_INT (type) && !IS_LONG (type))
     return RESULT_TYPE_INT;
   return RESULT_TYPE_OTHER;
 }
@@ -2276,17 +2293,22 @@ resultTypePropagate (ast *tree, RESULT_TYPE resultType)
     {
       case AND_OP:
       case OR_OP:
-        return resultType;
+      case '!':
       case '=':
       case '?':
       case ':':
       case '|':
       case '^':
       case '~':
+      case LEFT_OP:
+      case LABEL:
+        return resultType;
       case '*':
       case '+':
       case '-':
-      case LABEL:
+        if ((IS_AST_VALUE (tree->left)  && !IS_INTEGRAL (tree->left->opval.val->etype)) ||
+            (IS_AST_VALUE (tree->right) && !IS_INTEGRAL (tree->right->opval.val->etype)))
+          return RESULT_TYPE_NONE;
         return resultType;
       case '&':
         if (!tree->right)
@@ -2530,7 +2552,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
        upon tree->opval.op, if resultType can be propagated */
     resultTypeProp = resultTypePropagate (tree, resultType);
 
-    if (tree->opval.op == '?')
+    if ((tree->opval.op == '?') && (resultTypeProp != RESULT_TYPE_BIT))
       dtl = decorateType (tree->left, RESULT_TYPE_IFX);
     else
       dtl = decorateType (tree->left, resultTypeProp);
@@ -2565,6 +2587,12 @@ decorateType (ast * tree, RESULT_TYPE resultType)
              there is resultType available */
           dtr = tree->right;
           break;
+        case SIZEOF:
+          /* don't allocate string if it is a sizeof argument */
+          ++noAlloc;
+          dtr = decorateType (tree->right, resultTypeProp);
+          --noAlloc;
+          break;
         default:
           dtr = decorateType (tree->right, resultTypeProp);
           break;
@@ -2613,7 +2641,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
 
       if (IS_LITERAL (RTYPE (tree)))
         {
-          int arrayIndex = (int) floatFromVal (valFromType (RETYPE (tree)));
+          int arrayIndex = (int) ulFromVal (valFromType (RETYPE (tree)));
           int arraySize = DCL_ELEM (LTYPE (tree));
           if (arraySize && arrayIndex >= arraySize)
             {
@@ -3088,7 +3116,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       /* rearrange the tree */
       if (IS_LITERAL (RTYPE (tree))
           /* avoid infinite loop */
-          && (TYPE_TARGET_ULONG) floatFromVal (tree->right->opval.val) != 1)
+          && (TYPE_TARGET_ULONG) ulFromVal (tree->right->opval.val) != 1)
         {
           ast *parent;
           ast *litTree = searchLitOp (tree, &parent, "/");
@@ -3262,8 +3290,8 @@ decorateType (ast * tree, RESULT_TYPE resultType)
         }
 
       LRVAL (tree) = RRVAL (tree) = 1;
-      tree->left  = addCast (tree->left,  resultType, FALSE);
-      tree->right = addCast (tree->right, resultType, FALSE);
+      tree->left  = addCast (tree->left,  resultTypeProp, FALSE);
+      tree->right = addCast (tree->right, resultTypeProp, FALSE);
       TETYPE (tree) = getSpec (TTYPE (tree) =
                                    computeType (LTYPE (tree),
                                                 RTYPE (tree),
@@ -3332,8 +3360,8 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
         {
           tree->type = EX_VALUE;
-          tree->left  = addCast (tree->left,  resultType, TRUE);
-          tree->right = addCast (tree->right, resultType, TRUE);
+          tree->left  = addCast (tree->left,  resultTypeProp, TRUE);
+          tree->right = addCast (tree->right, resultTypeProp, TRUE);
           tree->opval.val = valPlus (valFromType (LETYPE (tree)),
                                      valFromType (RETYPE (tree)));
           tree->right = tree->left = NULL;
@@ -3403,8 +3431,8 @@ decorateType (ast * tree, RESULT_TYPE resultType)
                                  LTYPE (tree));
       else
         {
-          tree->left  = addCast (tree->left,  resultType, TRUE);
-          tree->right = addCast (tree->right, resultType, TRUE);
+          tree->left  = addCast (tree->left,  resultTypeProp, TRUE);
+          tree->right = addCast (tree->right, resultTypeProp, TRUE);
           TETYPE (tree) = getSpec (TTYPE (tree) =
                                      computeType (LTYPE (tree),
                                                   RTYPE (tree),
@@ -3438,7 +3466,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
               TETYPE (tree) = TTYPE (tree) = tree->opval.val->type;
               return tree;
             }
-          tree->left  = addCast (tree->left, resultType, TRUE);
+          tree->left  = addCast (tree->left, resultTypeProp, TRUE);
           TETYPE (tree) = getSpec (TTYPE (tree) =
                                      computeType (LTYPE (tree),
                                                   NULL,
@@ -3482,8 +3510,8 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
         {
           tree->type = EX_VALUE;
-          tree->left  = addCast (tree->left,  resultType, TRUE);
-          tree->right = addCast (tree->right, resultType, TRUE);
+          tree->left  = addCast (tree->left,  resultTypeProp, TRUE);
+          tree->right = addCast (tree->right, resultTypeProp, TRUE);
           tree->opval.val = valMinus (valFromType (LETYPE (tree)),
                                       valFromType (RETYPE (tree)));
           tree->right = tree->left = NULL;
@@ -3515,8 +3543,8 @@ decorateType (ast * tree, RESULT_TYPE resultType)
                                  LTYPE (tree));
       else
         {
-          tree->left  = addCast (tree->left,  resultType, TRUE);
-          tree->right = addCast (tree->right, resultType, TRUE);
+          tree->left  = addCast (tree->left,  resultTypeProp, TRUE);
+          tree->right = addCast (tree->right, resultTypeProp, TRUE);
 
           TETYPE (tree) = getSpec (TTYPE (tree) =
                                      computeType (LTYPE (tree),
@@ -3532,7 +3560,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       /* rearrange the tree */
       if (IS_LITERAL (RTYPE (tree))
           /* avoid infinite loop */
-          && (TYPE_TARGET_ULONG) floatFromVal (tree->right->opval.val) != 0)
+          && (TYPE_TARGET_ULONG) ulFromVal (tree->right->opval.val) != 0)
         {
           ast *litTree, *litParent;
           litTree = searchLitOp (tree, &litParent, "+-");
@@ -3597,7 +3625,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
           tree->opval.val = valComplement (valFromType (LETYPE (tree)));
           tree->left = NULL;
           TETYPE (tree) = TTYPE (tree) = tree->opval.val->type;
-          return addCast (tree, resultType, TRUE);
+          return addCast (tree, resultTypeProp, TRUE);
         }
 
       if (resultType == RESULT_TYPE_BIT &&
@@ -3615,7 +3643,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
           tree->opval.val = constVal ("1");
         }
       else
-        tree->left = addCast (tree->left, resultType, TRUE);
+        tree->left = addCast (tree->left, resultTypeProp, TRUE);
       LRVAL (tree) = 1;
       COPYTYPE (TTYPE (tree), TETYPE (tree), LTYPE (tree));
       return tree;
@@ -3635,8 +3663,13 @@ decorateType (ast * tree, RESULT_TYPE resultType)
         }
 
       /* if left is another '!' */
-      if (tree->left->opval.op == '!')
+      if (IS_AST_NOT_OPER (tree->left))
         {
+          if ((resultType == RESULT_TYPE_IFX) || (resultType == RESULT_TYPE_BIT))
+            {
+              /* replace double '!!X' by 'X' */
+              return tree->left->left;
+            }
           /* remove double '!!X' by 'X ? 1 : 0' */
           tree->opval.op = '?';
           tree->left  = tree->left->left;
@@ -3700,7 +3733,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
 
       /* make smaller type only if it's a LEFT_OP */
       if (tree->opval.op == LEFT_OP)
-        tree->left = addCast (tree->left, resultType, TRUE);
+        tree->left = addCast (tree->left, resultTypeProp, TRUE);
 
       /* if they are both literal then */
       /* rewrite the tree */
@@ -3754,7 +3787,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       /* if only the right side is a literal & we are
          shifting more than size of the left operand then zero */
       if (IS_LITERAL (RTYPE (tree)) &&
-          ((TYPE_TARGET_ULONG) floatFromVal (valFromType (RETYPE (tree)))) >=
+          ((TYPE_TARGET_ULONG) ulFromVal (valFromType (RETYPE (tree)))) >=
           (getSize (TETYPE (tree)) * 8))
         {
           if (tree->opval.op==LEFT_OP ||
@@ -3825,7 +3858,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
                       TTYPE (tree) = tree->opval.val->type;
                       tree->values.literalFromCast = 1;
               } else if (IS_GENPTR(LTYPE(tree)) && !IS_PTR(RTYPE(tree)) &&
-                         ((int)floatFromVal(valFromType(RETYPE(tree)))) !=0 ) /* special case of NULL */  {
+                         ((int) ulFromVal(valFromType(RETYPE(tree)))) !=0 ) /* special case of NULL */  {
                       sym_link *rest = LTYPE(tree)->next;
                       werrorfl (tree->filename, tree->lineno, W_LITERAL_GENERIC);
                       TTYPE(tree) = newLink(DECLARATOR);
@@ -4119,9 +4152,9 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       if (tree->opval.op == '>' &&
           SPEC_USIGN(LETYPE(tree)) &&
           IS_LITERAL(RTYPE(tree))  &&
-          ((int) floatFromVal (valFromType (RETYPE (tree)))) == 0)
+          ((int) ulFromVal (valFromType (RETYPE (tree)))) == 0)
         {
-          if (resultType == RESULT_TYPE_IFX)
+          if ((resultType == RESULT_TYPE_IFX) || (resultType == RESULT_TYPE_BIT))
             {
               /* the parent is an ifx: */
               /* if (unsigned value) */
@@ -4143,7 +4176,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       if (IS_LITERAL(RTYPE(tree))  &&
           floatFromVal (valFromType (RETYPE (tree))) == 0 &&
           tree->opval.op == EQ_OP &&
-          resultType == RESULT_TYPE_IFX)
+          (resultType == RESULT_TYPE_IFX || resultType == RESULT_TYPE_BIT))
         {
           tree->opval.op = '!';
           tree->right = NULL;
@@ -4178,14 +4211,14 @@ decorateType (ast * tree, RESULT_TYPE resultType)
           if (IS_LITERAL (RTYPE (tree)) && IS_UNSIGNED (RTYPE (tree)) &&
               /* the value range of a 'unsigned char' is 0...255;
                  if the actual value is < 128 it can be changed to signed */
-              (int) floatFromVal (valFromType (RETYPE (tree))) < 128)
+              (int) ulFromVal (valFromType (RETYPE (tree))) < 128)
             {
               /* now we've got 2 'signed char'! */
               SPEC_USIGN (RETYPE (tree)) = 0;
             }
                    /* same test for the left operand: */
           else if (IS_LITERAL (LTYPE (tree)) && IS_UNSIGNED (LTYPE (tree)) &&
-              (int) floatFromVal (valFromType (LETYPE (tree))) < 128)
+              (int) ulFromVal (valFromType (LETYPE (tree))) < 128)
             {
               SPEC_USIGN (LETYPE (tree)) = 0;
             }
@@ -4198,7 +4231,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
         }
 
       LRVAL (tree) = RRVAL (tree) = 1;
-      TTYPE (tree) = TETYPE (tree) = newBoolLink ();
+      TTYPE (tree) = TETYPE (tree) = (resultType == RESULT_TYPE_BIT) ? newBoolLink() :newCharLink();
 
       /* condition transformations */
       {
@@ -4253,6 +4286,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       /* change the type to a integer */
       {
         int size = getSize (tree->right->ftype);
+
         SNPRINTF(buffer, sizeof(buffer), "%d", size);
         if (!size && !IS_VOID(tree->right->ftype))
           werrorfl (tree->filename, tree->lineno, E_SIZEOF_INCOMPLETE_TYPE);
@@ -4262,6 +4296,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       tree->right = tree->left = NULL;
       TETYPE (tree) = getSpec (TTYPE (tree) =
                                tree->opval.val->type);
+
       return tree;
 
       /*------------------------------------------------------------------*/
@@ -4350,21 +4385,55 @@ decorateType (ast * tree, RESULT_TYPE resultType)
     case '?':
       /* the type is value of the colon operator (on the right) */
       assert (IS_COLON_OP (tree->right));
-      /* if already known then replace the tree : optimizer will do it
-         but faster to do it here */
+
+      /* If already known then replace the tree : optimizer will do it
+         but faster to do it here. If done before decorating tree->right
+         this can save generating unused const strings. */
       if (IS_LITERAL (LTYPE (tree)))
         {
-          if (((int) floatFromVal (valFromType (LETYPE (tree)))) != 0)
+          if (((int) ulFromVal (valFromType (LETYPE (tree)))) != 0)
             return decorateType (tree->right->left, resultTypeProp);
           else
             return decorateType (tree->right->right, resultTypeProp);
         }
-      else
+
+      tree->right = decorateType (tree->right,  resultTypeProp);
+
+      if (IS_AST_LIT_VALUE (tree->right->left) && IS_AST_LIT_VALUE (tree->right->right) &&
+          ((resultType == RESULT_TYPE_IFX) || (resultType == RESULT_TYPE_BIT)))
         {
-          tree->right = decorateType (tree->right, resultTypeProp);
-          TTYPE (tree) = RTYPE (tree);
-          TETYPE (tree) = getSpec (TTYPE (tree));
+          double valTrue = AST_FLOAT_VALUE (tree->right->left);
+          double valFalse = AST_FLOAT_VALUE (tree->right->right);
+
+          if ((valTrue != 0) && (valFalse == 0))
+            {
+              /* assign cond to result */
+              tree->left->decorated = 0;
+              return decorateType (tree->left, resultTypeProp);
+            }
+          else if ((valTrue == 0) && (valFalse != 0))
+            {
+              /* assign !cond to result */
+              tree->opval.op = '!';
+              tree->decorated = 0;
+              tree->right = NULL;
+              return decorateType (tree, resultTypeProp);
+            }
+          else
+            {
+              /* they have the same boolean value, make them equal */
+              tree->right->left = tree->right->right;
+            }
+        }
+
+      /* if they are equal then replace the tree */
+      if (isAstEqual (tree->right->left, tree->right->right))
+        {
+          return tree->right->left;
         }
+
+      TTYPE (tree) = RTYPE (tree);
+      TETYPE (tree) = getSpec (TTYPE (tree));
       return tree;
 
     case ':':
@@ -4977,8 +5046,8 @@ createCase (ast * swStat, ast * caseVal, ast * stmnt)
     {
       /* also order the cases according to value */
       value *pval = NULL;
-      int cVal = (int) floatFromVal (caseVal->opval.val);
-      while (val && (int) floatFromVal (val) < cVal)
+      int cVal = (int) ulFromVal (caseVal->opval.val);
+      while (val && (int) ulFromVal (val) < cVal)
         {
           pval = val;
           val = val->next;
@@ -4989,7 +5058,7 @@ createCase (ast * swStat, ast * caseVal, ast * stmnt)
         {
           pval->next = caseVal->opval.val;
         }
-      else if ((int) floatFromVal (val) == cVal)
+      else if ((int) ulFromVal (val) == cVal)
         {
           werrorfl (caseVal->filename, caseVal->lineno, E_DUPLICATE_LABEL,
                     "case");
@@ -5016,7 +5085,7 @@ createCase (ast * swStat, ast * caseVal, ast * stmnt)
   SNPRINTF(caseLbl, sizeof(caseLbl),
            "_case_%d_%d",
            swStat->values.switchVals.swNum,
-           (int) floatFromVal (caseVal->opval.val));
+           (int) ulFromVal (caseVal->opval.val));
 
   rexpr = createLabel (newSymbol (caseLbl, 0), stmnt);
   rexpr->lineno = 0;
@@ -5320,7 +5389,7 @@ isBitAndPow2 (ast * tree)
   if (!IS_AST_LIT_VALUE (tree->right))
     return -1;
 
-  return powof2 ((TYPE_TARGET_ULONG)AST_LIT_VALUE (tree->right));
+  return powof2 (AST_ULONG_VALUE (tree->right));
 }
 
 /*-----------------------------------------------------------------*/
@@ -5329,14 +5398,14 @@ isBitAndPow2 (ast * tree)
 ast *
 optimizeGetHbit (ast * tree, RESULT_TYPE resultType)
 {
-  int i, j;
+  unsigned int i, j;
   ast * expr;
 
   expr = isShiftRightLitVal_BitAndLitVal(tree);
   if (expr)
     {
-      if ((AST_LIT_VALUE (tree->right) != 1) ||
-          ((i = (int) AST_LIT_VALUE (tree->left->right)) !=
+      if ((AST_ULONG_VALUE (tree->right) != 1) ||
+          ((i = AST_ULONG_VALUE (tree->left->right)) !=
           (j = (getSize (TTYPE (expr)) * 8 - 1))))
         expr = NULL;
     }
@@ -5369,7 +5438,7 @@ optimizeGetAbit (ast * tree, RESULT_TYPE resultType)
   expr = isShiftRightLitVal_BitAndLitVal(tree);
   if (expr)
     {
-  if (AST_LIT_VALUE (tree->right) != 1)
+  if (AST_ULONG_VALUE (tree->right) != 1)
         expr = NULL;
       count = tree->left->right;
     }
@@ -5407,9 +5476,9 @@ optimizeGetByte (ast * tree, RESULT_TYPE resultType)
   expr = isShiftRightLitVal_BitAndLitVal(tree);
   if (expr)
     {
-      i = (unsigned int) AST_LIT_VALUE (tree->left->right);
+      i = AST_ULONG_VALUE (tree->left->right);
       count = tree->left->right;
-      if (AST_LIT_VALUE (tree->right) != 0xFF)
+      if (AST_ULONG_VALUE (tree->right) != 0xFF)
         expr = NULL;
     }
   if (!expr && resultType == RESULT_TYPE_CHAR)
@@ -5417,7 +5486,7 @@ optimizeGetByte (ast * tree, RESULT_TYPE resultType)
       /* if this is a right shift over a multiple of 8 */
       if (IS_RIGHT_OP (tree) && IS_AST_LIT_VALUE (tree->right))
         {
-          i = (unsigned int) AST_LIT_VALUE (tree->right);
+          i = AST_ULONG_VALUE (tree->right);
           count = tree->right;
             expr = tree->left;
         }
@@ -5446,9 +5515,9 @@ optimizeGetWord (ast * tree, RESULT_TYPE resultType)
   expr = isShiftRightLitVal_BitAndLitVal(tree);
   if (expr)
     {
-      i = (unsigned int) AST_LIT_VALUE (tree->left->right);
+      i = AST_ULONG_VALUE (tree->left->right);
       count = tree->left->right;
-      if (AST_LIT_VALUE (tree->right) != 0xFFFF)
+      if (AST_ULONG_VALUE (tree->right) != 0xFFFF)
         expr = NULL;
     }
   if (!expr && resultType == RESULT_TYPE_INT)
@@ -5456,7 +5525,7 @@ optimizeGetWord (ast * tree, RESULT_TYPE resultType)
       /* if this is a right shift over a multiple of 8 */
       if (IS_RIGHT_OP (tree) && IS_AST_LIT_VALUE (tree->right))
         {
-          i = (unsigned int) AST_LIT_VALUE (tree->right);
+          i = AST_ULONG_VALUE (tree->right);
           count = tree->right;
             expr = tree->left;
         }
@@ -5512,10 +5581,10 @@ optimizeRRCRLC (ast * root)
                        root->right->left))
         goto tryNext0;
 
-      if (AST_LIT_VALUE (root->left->right) != 1)
+      if (AST_ULONG_VALUE (root->left->right) != 1)
         goto tryNext0;
 
-      if (AST_LIT_VALUE (root->right->right) !=
+      if (AST_ULONG_VALUE (root->right->right) !=
           (getSize (TTYPE (root->left->left)) * 8 - 1))
         goto tryNext0;
 
@@ -5547,10 +5616,10 @@ tryNext0:
                        root->right->left))
         goto tryNext1;
 
-      if (AST_LIT_VALUE (root->right->right) != 1)
+      if (AST_ULONG_VALUE (root->right->right) != 1)
         goto tryNext1;
 
-      if (AST_LIT_VALUE (root->left->right) !=
+      if (AST_ULONG_VALUE (root->left->right) !=
           (getSize (TTYPE (root->left->left)) * 8 - 1))
         goto tryNext1;
 
@@ -5583,10 +5652,10 @@ tryNext1:
                        root->right->left))
         goto tryNext2;
 
-      if (AST_LIT_VALUE (root->left->right) != 1)
+      if (AST_ULONG_VALUE (root->left->right) != 1)
         goto tryNext2;
 
-      if (AST_LIT_VALUE (root->right->right) !=
+      if (AST_ULONG_VALUE (root->right->right) !=
           (getSize (TTYPE (root->left->left)) * 8 - 1))
         goto tryNext2;
 
@@ -5618,10 +5687,10 @@ tryNext2:
                        root->right->left))
         return root;
 
-      if (AST_LIT_VALUE (root->right->right) != 1)
+      if (AST_ULONG_VALUE (root->right->right) != 1)
         return root;
 
-      if (AST_LIT_VALUE (root->left->right) !=
+      if (AST_ULONG_VALUE (root->left->right) !=
           (getSize (TTYPE (root->left->left)) * 8 - 1))
         return root;
 
@@ -5672,11 +5741,11 @@ optimizeSWAP (ast * root)
                        root->right->left))
         return root;
 
-      if (AST_LIT_VALUE (root->left->right) !=
+      if (AST_ULONG_VALUE (root->left->right) !=
           (getSize (TTYPE (root->left->left)) * 4))
         return root;
 
-      if (AST_LIT_VALUE (root->right->right) !=
+      if (AST_ULONG_VALUE (root->right->right) !=
           (getSize (TTYPE (root->left->left)) * 4))
         return root;
 
@@ -5745,8 +5814,8 @@ optimizeCompare (ast * root)
             root->right->opval.val : NULL);
 
   /* if left is a BITVAR in BITSPACE */
-  /* and right is a LITERAL then opt- */
-  /* imize else do nothing       */
+  /* and right is a LITERAL then     */
+  /* optimize else do nothing        */
   if (vleft && vright &&
       IS_BITVAR (vleft->etype) &&
       IN_BITSPACE (SPEC_OCLS (vleft->etype)) &&
@@ -5754,7 +5823,7 @@ optimizeCompare (ast * root)
     {
 
       /* if right side > 1 then comparison may never succeed */
-      if ((litValue = (int) floatFromVal (vright)) > 1)
+      if ((litValue = (int) ulFromVal (vright)) > 1)
         {
           werror (W_BAD_COMPARE);
           goto noOptimize;
@@ -5815,6 +5884,7 @@ optimizeCompare (ast * root)
 noOptimize:
   return root;
 }
+
 /*-----------------------------------------------------------------*/
 /* addSymToBlock : adds the symbol to the first block we find      */
 /*-----------------------------------------------------------------*/
@@ -5869,6 +5939,430 @@ DEFSETFUNC (resetParmKey)
   return 1;
 }
 
+
+
+/*------------------------------------------------------------------*/
+/* fixupInlineLabel - change a label in an inlined function so that */
+/*                    it is always unique no matter how many times  */
+/*                    the function is inlined.                      */
+/*------------------------------------------------------------------*/
+static void
+fixupInlineLabel (symbol * sym)
+{
+  char name[SDCC_NAME_MAX + 1];
+  
+  SNPRINTF(name, sizeof(name), "%s_%d", sym->name, inlineState.count);
+  strcpy (sym->name, name);
+}
+
+
+/*------------------------------------------------------------------*/
+/* copyAstLoc - copy location information (file, line, block, etc.) */
+/*              from one ast node to another                        */
+/*------------------------------------------------------------------*/
+static void
+copyAstLoc (ast * dest, ast * src)
+{
+  dest->lineno = src->lineno;
+  dest->filename = src->filename;
+  dest->level = src->level;
+  dest->block = src->block;
+  dest->seqPoint = src->seqPoint;
+  
+}
+
+
+/*-----------------------------------------------------------------*/
+/* fixupInline - perform various fixups on an inline function tree */
+/*               to take into account that it is no longer a       */
+/*               stand-alone function.                             */
+/*-----------------------------------------------------------------*/
+static void
+fixupInline (ast * tree, int level)
+{
+  tree->block = currBlockno;
+
+  if (IS_AST_OP (tree) && (tree->opval.op == BLOCK))
+    {
+      symbol * decls;
+
+      currBlockno++;
+      level++;
+
+      /* Add any declared variables back into the symbol table */
+      decls = tree->values.sym;
+      while (decls)
+        {
+          decls->level = level;
+          decls->block = currBlockno;
+          addSym (SymbolTab, decls, decls->name, decls->level, decls->block, 0);
+          decls = decls->next;
+        }
+    }
+
+  tree->level = level;
+
+  /* Update symbols */
+  if (IS_AST_VALUE (tree) &&
+      tree->opval.val->sym)
+    {
+      symbol * sym = tree->opval.val->sym;
+
+      sym->level = level;
+      sym->block = currBlockno;
+
+      sym->reqv = NULL;
+      SYM_SPIL_LOC (sym) = NULL;
+      sym->key = 0;
+
+      /* If the symbol is a label, we need to renumber it */
+      if (sym->islbl)
+        fixupInlineLabel (sym);
+    }
+
+  /* Update IFX target labels */
+  if (tree->type == EX_OP && tree->opval.op == IFX)
+    {
+      if (tree->trueLabel)
+        fixupInlineLabel (tree->trueLabel);
+      if (tree->falseLabel)
+        fixupInlineLabel (tree->falseLabel);
+    }
+
+  /* Replace RETURN with optional assignment and a GOTO to the end */
+  /* of the inlined function */
+  if (tree->type == EX_OP && tree->opval.op == RETURN)
+    {
+      ast * assignTree = NULL;
+      ast * gotoTree;
+
+      if (inlineState.retsym && tree->right)
+        {
+          assignTree = newNode ('=',
+                                newAst_VALUE (symbolVal (inlineState.retsym)),
+                                tree->right);
+          copyAstLoc (assignTree, tree);
+        }
+
+      gotoTree = newNode (GOTO,
+                          newAst_VALUE (symbolVal (inlineState.retlab)),
+                          NULL);
+      copyAstLoc (gotoTree, tree);
+
+      tree->opval.op = NULLOP;
+      tree->left = assignTree;
+      tree->right = gotoTree;
+    }
+
+   /* Update any children */
+   if (tree->left)
+      fixupInline (tree->left, level);
+   if (tree->right)
+      fixupInline (tree->right, level);
+
+  if (IS_AST_OP (tree) && (tree->opval.op == LABEL))
+    {
+      symbol * label = tree->left->opval.val->sym;
+
+      label->key = labelKey++;
+      /* Add this label back into the symbol table */
+      addSym (LabelTab, label, label->name, label->level, 0, 0);
+    }
+
+
+  if (IS_AST_OP (tree) && (tree->opval.op == BLOCK))
+    {
+      level--;
+    }
+}
+
+/*-----------------------------------------------------------------*/
+/* inlineAddDecl - add a variable declaration to an ast block. It  */
+/*                 is also added to the symbol table if addSymTab  */
+/*                 is nonzero.                                     */
+/*-----------------------------------------------------------------*/
+static void
+inlineAddDecl (symbol * sym, ast * block, int addSymTab)
+{
+  sym->reqv = NULL;
+  SYM_SPIL_LOC (sym) = NULL;
+  sym->key = 0;
+  if (block != NULL)
+    {
+      symbol **decl = &(block->values.sym);
+
+      sym->level = block->level;
+      sym->block = block->block;
+
+      while (*decl)
+        {
+          if (strcmp ((*decl)->name, sym->name) == 0)
+            return;
+          decl = &( (*decl)->next );
+        }
+
+      *decl = sym;
+
+      if (addSymTab)
+        addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 0);
+
+    }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* inlineTempVar - create a temporary variable for inlining        */
+/*-----------------------------------------------------------------*/
+static symbol *
+inlineTempVar (sym_link * type, int level)
+{
+  symbol * sym;
+
+  sym = newSymbol (genSymName(level), level );
+  sym->type = copyLinkChain (type);
+  sym->etype = getSpec(sym->type);
+  SPEC_SCLS (sym->etype) = S_AUTO;
+  SPEC_OCLS (sym->etype) = NULL;
+  SPEC_EXTR (sym->etype) = 0;
+  SPEC_STAT (sym->etype) = 0;
+  if IS_SPEC (sym->type)
+    SPEC_VOLATILE (sym->type) = 0;
+  else
+    DCL_PTR_VOLATILE (sym->type) = 0;
+  SPEC_ABSA (sym->etype) = 0;
+
+  return sym;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* inlineFindParmRecurse - recursive function for inlineFindParm   */
+/*-----------------------------------------------------------------*/
+static ast *
+inlineFindParmRecurse (ast * parms, int *index)
+{
+  if (!parms)
+    return NULL;
+
+  if (parms->type == EX_OP && parms->opval.op == PARAM)
+  {
+    ast * p;
+
+    p=inlineFindParmRecurse (parms->left, index);
+    if (p)
+      return p;
+    p=inlineFindParmRecurse (parms->right, index);
+    if (p)
+      return p;
+  }
+  if (!*index)
+    return parms;
+  (*index)--;
+  return NULL;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* inlineFindParm - search an ast tree of parameters to find one   */
+/*                  at a particular index (0=first parameter).     */
+/*                  Returns NULL if not found.                     */
+/*-----------------------------------------------------------------*/
+static ast *
+inlineFindParm (ast * parms, int index)
+{
+  return inlineFindParmRecurse (parms, &index);
+}
+
+/*-----------------------------------------------------------------*/
+/* inlineFindMaxBlockno - find maximum block number in an ast tree */
+/*-----------------------------------------------------------------*/
+static int
+inlineFindMaxBlockno (ast * tree, int maxBlockno)
+{
+  int tempBlockno;
+
+  if (!tree)
+    return maxBlockno;
+
+  tempBlockno = inlineFindMaxBlockno (tree->left, maxBlockno);
+  if (tempBlockno > maxBlockno)
+    maxBlockno = tempBlockno;
+
+  tempBlockno = inlineFindMaxBlockno (tree->right, maxBlockno);
+  if (tempBlockno > maxBlockno)
+    maxBlockno = tempBlockno;
+
+  if (tree->block > maxBlockno)
+    maxBlockno = tree->block;
+  return maxBlockno;
+}
+
+
+
+
+/*-----------------------------------------------------------------*/
+/* expandInlineFuncs - replace calls to inline functions with the  */
+/*                     function itself                             */
+/*-----------------------------------------------------------------*/
+static void
+expandInlineFuncs (ast * tree, ast * block)
+{
+  if (IS_AST_OP (tree) && (tree->opval.op == CALL) && tree->left
+      && IS_AST_VALUE (tree->left) && tree->left->opval.val->sym)
+    {
+      symbol * func = tree->left->opval.val->sym;
+      symbol * csym;
+
+      /* The symbol is probably not bound yet, so find the real one */
+      csym = findSymWithLevel (SymbolTab, func);
+      if (csym)
+        func = csym;
+
+      /* Is this an inline function that we can inline? */
+      if (IFFUNC_ISINLINE (func->type) && func->funcTree)
+        {
+          symbol * retsym = NULL;
+          symbol * retlab;
+          ast * inlinetree;
+          ast * inlinetree2;
+          ast * temptree;
+          value * args;
+          int argIndex;
+
+          /* Generate a label for the inlined function to branch to */
+          /* in case it contains a return statement */
+          retlab = newSymbol (genSymName(tree->level+1), tree->level+1 );
+          retlab->isitmp = 1;
+          retlab->islbl = 1;
+          inlineState.retlab = retlab;
+
+          /* Build the subtree for the inlined function in the form: */
+          /* { //inlinetree block                                    */
+          /*   { //inlinetree2 block                                 */
+          /*     inline_function_code;                               */
+          /*     retlab:                                             */
+          /*   }                                                     */
+          /* }                                                       */
+          temptree = newNode (LABEL, newAst_VALUE (symbolVal (retlab)), NULL);
+          copyAstLoc (temptree, tree);
+          temptree = newNode (NULLOP, copyAst (func->funcTree), temptree);
+          copyAstLoc (temptree, tree);
+          temptree = newNode (BLOCK, NULL, temptree);
+          copyAstLoc (temptree, tree);
+          inlinetree2 = temptree;
+          inlinetree = newNode (BLOCK, NULL, inlinetree2);
+          copyAstLoc (inlinetree, tree);
+
+          /* To pass parameters to the inlined function, we need some  */
+          /* intermediate variables. This avoids scoping problems      */
+          /* when the parameter declaration names are used differently */
+          /* during the function call. For example, a function         */
+          /* declared as func(int x, int y) but called as func(y,x).   */
+          /* { //inlinetree block                                      */
+          /*   type1 temparg1;                                         */
+          /*   ...                                                     */
+          /*   typen tempargn;                                         */
+          /*   temparg1 = argument1;                                   */
+          /*   ...                                                     */
+          /*   tempargn = argumentn;                                   */
+          /*   { //inlinetree2 block                                   */
+          /*     type1 param1;                                         */
+          /*     ...                                                   */
+          /*     typen paramn;                                         */
+          /*     param1 = temparg1;                                    */
+          /*     ...                                                   */
+          /*     paramn = tempargn;                                    */
+          /*     inline_function_code;                                 */
+          /*     retlab:                                               */
+          /*   }                                                       */
+          /* }                                                         */
+          args = FUNC_ARGS (func->type);
+          argIndex = 0;
+          while (args)
+            {
+              symbol * temparg;
+              ast * passedarg;
+              ast * assigntree;
+              symbol * parm = copySymbol (args->sym);
+
+              temparg = inlineTempVar (args->sym->type, tree->level+1);
+              inlineAddDecl (temparg, inlinetree, FALSE);
+
+              passedarg = inlineFindParm (tree->right, argIndex);
+              assigntree = newNode ('=',
+                                    newAst_VALUE (symbolVal (temparg)),
+                                    passedarg);
+              inlinetree->right = newNode (NULLOP,
+                                           assigntree,
+                                           inlinetree->right);
+
+              inlineAddDecl (parm, inlinetree2, FALSE);
+              parm->_isparm = 0;
+
+              assigntree = newNode ('=',
+                                    newAst_VALUE (symbolVal (parm)),
+                                    newAst_VALUE (symbolVal (temparg)));
+              inlinetree2->right = newNode (NULLOP,
+                                           assigntree,
+                                           inlinetree2->right);
+
+
+              args = args->next;
+              argIndex++;
+            }
+
+          /* Handle the return type */
+          if (!IS_VOID (func->type->next))
+            {
+              /* Create a temporary symbol to hold the return value and   */
+              /* join it with the inlined function using the comma        */
+              /* operator. The fixupInline function will take care of     */
+              /* changing return statements into assignments to retsym.   */
+              /* (parameter passing and return label omitted for clarity) */
+              /* rettype retsym;                                          */
+              /* ...                                                      */
+              /* {{inline_function_code}}, retsym                         */
+
+              retsym = inlineTempVar (func->type->next, tree->level);
+              inlineAddDecl (retsym, block, TRUE);
+
+              tree->opval.op = ',';
+              tree->left = inlinetree;
+              tree->right = newAst_VALUE (symbolVal (retsym));
+            }
+          else
+            {
+              tree->opval.op = NULLOP;
+              tree->left = NULL;
+              tree->right = inlinetree;
+            }
+          inlineState.retsym = retsym;
+
+          /* Renumber the various internal counters on the inlined   */
+          /* function's tree nodes and symbols. Add the inlined      */
+          /* function's local variables to the appropriate scope(s). */
+          /* Convert inlined return statements to an assignment to   */
+          /* retsym (if needed) and a goto retlab.                   */
+          fixupInline (inlinetree, inlinetree->level);
+          inlineState.count++;
+        }
+
+    }
+
+  /* Recursively continue to search for functions to inline. */
+  if (IS_AST_OP (tree))
+    {
+      if (tree->opval.op == BLOCK)
+        block = tree;
+
+      if (tree->left)
+        expandInlineFuncs (tree->left, block);
+      if (tree->right)
+        expandInlineFuncs (tree->right, block);
+    }
+}
+
+
 /*-----------------------------------------------------------------*/
 /* createFunction - This is the key node that calls the iCode for  */
 /*                  generating the code for a function. Note code  */
@@ -5883,6 +6377,7 @@ createFunction (symbol * name, ast * body)
   int stack = 0;
   sym_link *fetype;
   iCode *piCode = NULL;
+  int savedBlockno;
 
   if (getenv("SDCC_DEBUG_FUNCTION_POINTERS"))
     fprintf (stderr, "SDCCast.c:createFunction(%s)\n", name->name);
@@ -5938,6 +6433,15 @@ createFunction (symbol * name, ast * body)
   if (IFFUNC_ISREENT (name->type))
     reentrant++;
 
+  inlineState.count = 0;
+  savedBlockno = currBlockno;
+  currBlockno = inlineFindMaxBlockno (body, 0);
+  expandInlineFuncs (body, NULL);
+  currBlockno = savedBlockno;
+
+  if (FUNC_ISINLINE (name->type))
+    name->funcTree = copyAst (body);
+
   allocParms (FUNC_ARGS(name->type));   /* allocate the parameters */
 
   /* do processing for parameters that are passed in registers */
@@ -5968,23 +6472,30 @@ createFunction (symbol * name, ast * body)
   ex = newNode (FUNCTION, ex, body);
   ex->values.args = FUNC_ARGS(name->type);
   ex->decorated=1;
-  if (options.dump_tree) PA(ex);
+  if (options.dump_tree)
+    PA(ex);
   if (fatalError)
-    {
-      werror (E_FUNC_NO_CODE, name->name);
-      goto skipall;
-    }
+    goto skipall;
+
+  /* Do not generate code for inline functions unless extern also. */
+#if 0
+  if (FUNC_ISINLINE (name->type) && !IS_EXTERN (fetype))
+    goto skipall;
+#else
+  /* Temporary hack: always generate code for static inline functions. */
+  /* Ideally static inline functions should only be generated if needed. */
+  if (FUNC_ISINLINE (name->type) && !IS_EXTERN (fetype) && !IS_STATIC (fetype))
+    goto skipall;
+#endif
 
   /* create the node & generate intermediate code */
   GcurMemmap = code;
   codeOutBuf = &code->oBuf;
   piCode = iCodeFromAst (ex);
+  name->generated = 1;
 
   if (fatalError)
-    {
-      werror (E_FUNC_NO_CODE, name->name);
-      goto skipall;
-    }
+    goto skipall;
 
   eBBlockFromiCode (piCode);
 
@@ -6114,10 +6625,10 @@ void ast_print (ast * tree, FILE *outfile, int indent)
     if (IS_LITERAL (tree->opval.val->etype)) {
       fprintf(outfile,"CONSTANT (%p) value = ", tree);
       if (SPEC_USIGN (tree->opval.val->etype))
-        fprintf(outfile,"%u", (TYPE_TARGET_ULONG) floatFromVal(tree->opval.val));
+        fprintf(outfile,"%u", (TYPE_TARGET_ULONG) ulFromVal(tree->opval.val));
       else
-        fprintf(outfile,"%d", (TYPE_TARGET_LONG) floatFromVal(tree->opval.val));
-      fprintf(outfile,", 0x%x, %f", (TYPE_TARGET_ULONG) floatFromVal(tree->opval.val),
+        fprintf(outfile,"%d", (TYPE_TARGET_LONG) ulFromVal(tree->opval.val));
+      fprintf(outfile,", 0x%x, %f", (TYPE_TARGET_ULONG) ulFromVal(tree->opval.val),
         floatFromVal(tree->opval.val));
     } else if (tree->opval.val->sym) {
       /* if the undefined flag is set then give error message */
@@ -6682,9 +7193,9 @@ void ast_print (ast * tree, FILE *outfile, int indent)
       for (val = tree->values.switchVals.swVals; val ; val = val->next) {
         INDENT(indent+2,outfile);
         fprintf(outfile,"CASE 0x%x GOTO _case_%d_%d\n",
-          (int) floatFromVal(val),
+          (int) ulFromVal(val),
           tree->values.switchVals.swNum,
-          (int) floatFromVal(val));
+          (int) ulFromVal(val));
       }
       ast_print(tree->right,outfile,indent);
     }