* src/SDCCast.c (decorateType): try to optimize literals before promotion
[fw/sdcc] / src / SDCCast.c
index d82a071942e6a1615652bc0b8433f36489bc0703..2c98465f9ce11408aba62e76da3b3120b8b88eff 100644 (file)
@@ -50,8 +50,8 @@ int labelKey = 1;
 int noLineno = 0;
 int noAlloc = 0;
 symbol *currFunc=NULL;
-static ast *createIval (ast *, sym_link *, initList *, ast *);
-static ast *createIvalCharPtr (ast *, sym_link *, ast *);
+static ast *createIval (ast *, sym_link *, initList *, ast *, ast *);
+static ast *createIvalCharPtr (ast *, sym_link *, ast *, ast *);
 static ast *optimizeCompare (ast *);
 ast *optimizeRRCRLC (ast *);
 ast *optimizeSWAP (ast *);
@@ -864,7 +864,7 @@ createIvalType (ast * sym, sym_link * type, initList * ilist)
 /* createIvalStruct - generates initial value for structures       */
 /*-----------------------------------------------------------------*/
 static ast *
-createIvalStruct (ast * sym, sym_link * type, initList * ilist)
+createIvalStruct (ast * sym, sym_link * type, initList * ilist, ast *rootValue)
 {
   ast *rast = NULL;
   ast *lAst;
@@ -888,7 +888,10 @@ createIvalStruct (ast * sym, sym_link * type, initList * ilist)
       sflds->implicit = 1;
       lAst = newNode (PTR_OP, newNode ('&', sym, NULL), newAst_VALUE (symbolVal (sflds)));
       lAst = decorateType (resolveSymbols (lAst), RESULT_TYPE_NONE);
-      rast = decorateType (resolveSymbols (createIval (lAst, sflds->type, iloop, rast)), RESULT_TYPE_NONE);
+      rast = decorateType (resolveSymbols (createIval (lAst, sflds->type,
+                                                       iloop, rast, rootValue)),
+                           RESULT_TYPE_NONE);
+
     }
 
   if (iloop) {
@@ -905,7 +908,7 @@ createIvalStruct (ast * sym, sym_link * type, initList * ilist)
 /* createIvalArray - generates code for array initialization       */
 /*-----------------------------------------------------------------*/
 static ast *
-createIvalArray (ast * sym, sym_link * type, initList * ilist)
+createIvalArray (ast * sym, sym_link * type, initList * ilist, ast *rootValue)
 {
   ast *rast = NULL;
   initList *iloop;
@@ -918,84 +921,88 @@ createIvalArray (ast * sym, sym_link * type, initList * ilist)
   if (IS_CHAR (type->next))
     if ((rast = createIvalCharPtr (sym,
                                    type,
-                        decorateType (resolveSymbols (list2expr (ilist)), RESULT_TYPE_NONE))))
+                        decorateType (resolveSymbols (list2expr (ilist)), RESULT_TYPE_NONE),
+                                   rootValue)))
 
       return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
 
-    /* not the special case             */
-    if (ilist->type != INIT_DEEP)
-    {
-        werror (E_INIT_STRUCT, "");
-        return NULL;
-    }
+  /* not the special case             */
+  if (ilist->type != INIT_DEEP)
+  {
+      werror (E_INIT_STRUCT, "");
+      return NULL;
+  }
 
-    iloop = ilist->init.deep;
-    lcnt = DCL_ELEM (type);
+  iloop = ilist->init.deep;
+  lcnt = DCL_ELEM (type);
 
-    if (port->arrayInitializerSuppported && convertIListToConstList(ilist, &literalL))
-    {
-        ast *aSym;
+  if (port->arrayInitializerSuppported && convertIListToConstList(ilist, &literalL))
+  {
+      ast *aSym;
 
-        aSym = decorateType (resolveSymbols(sym), RESULT_TYPE_NONE);
-        
-        rast = newNode(ARRAYINIT, aSym, NULL);
-        rast->values.constlist = literalL;
-        
-        // Make sure size is set to length of initializer list.
-        while (iloop)
-        {
-            size++;
-            iloop = iloop->next;
-        }
-        
-        if (lcnt && size > lcnt)
-        {
-            // Array size was specified, and we have more initializers than needed.
-            char *name=sym->opval.val->sym->name;
-            int lineno=sym->opval.val->sym->lineDef;
-            char *filename=sym->opval.val->sym->fileDef;
-            
-            werrorfl (filename, lineno, W_EXCESS_INITIALIZERS, "array", name);
-        }
-    }
-    else
-    {
-        for (;;)
-        {
-            ast *aSym;
-            
-            aSym = newNode ('[', sym, newAst_VALUE (valueFromLit ((float) (size++))));
-            aSym = decorateType (resolveSymbols (aSym), RESULT_TYPE_NONE);
-            rast = createIval (aSym, type->next, iloop, rast);
-            iloop = (iloop ? iloop->next : NULL);
-            if (!iloop)
-            {
-                break;
-            }
-            
-            /* no of elements given and we    */
-            /* have generated for all of them */
-            if (!--lcnt) 
-            {
-                // is this a better way? at least it won't crash
-                char *name = (IS_AST_SYM_VALUE(sym)) ? AST_SYMBOL(sym)->name : "";
-                int lineno = iloop->lineno;
-                char *filename = iloop->filename;
-                werrorfl (filename, lineno, W_EXCESS_INITIALIZERS, "array", name);
-                
-                break;
-            }
-        }
-    }
+      aSym = decorateType (resolveSymbols(sym), RESULT_TYPE_NONE);
+      
+      rast = newNode(ARRAYINIT, aSym, NULL);
+      rast->values.constlist = literalL;
+      
+      // Make sure size is set to length of initializer list.
+      while (iloop)
+      {
+          size++;
+          iloop = iloop->next;
+      }
+      
+      if (lcnt && size > lcnt)
+      {
+          // Array size was specified, and we have more initializers than needed.
+          char *name=sym->opval.val->sym->name;
+          int lineno=sym->opval.val->sym->lineDef;
+          char *filename=sym->opval.val->sym->fileDef;
+          
+          werrorfl (filename, lineno, W_EXCESS_INITIALIZERS, "array", name);
+      }
+  }
+  else
+  {
+      for (;;)
+      {
+          ast *aSym;
+          
+          aSym = newNode ('[', sym, newAst_VALUE (valueFromLit ((float) (size++))));
+          aSym = decorateType (resolveSymbols (aSym), RESULT_TYPE_NONE);
+          rast = createIval (aSym, type->next, iloop, rast, rootValue);
+          iloop = (iloop ? iloop->next : NULL);
+          if (!iloop)
+          {
+              break;
+          }
+          
+          /* no of elements given and we    */
+          /* have generated for all of them */
+          if (!--lcnt) 
+          {
+              // is this a better way? at least it won't crash
+              char *name = (IS_AST_SYM_VALUE(sym)) ? AST_SYMBOL(sym)->name : "";
+              int lineno = iloop->lineno;
+              char *filename = iloop->filename;
+              werrorfl (filename, lineno, W_EXCESS_INITIALIZERS, "array", name);
+              
+              break;
+          }
+      }
+  }
 
-    /* if we have not been given a size  */
-    if (!DCL_ELEM (type))
+  /* if we have not been given a size  */
+  if (!DCL_ELEM (type))
     {
-        /* but this still updates the typedef instead of the instance ! see bug 770487 */
+      /* check, if it's a flexible array */
+      if (IS_STRUCT (AST_VALUE (rootValue)->type))
+        AST_SYMBOL(rootValue)->flexArrayLength = size * getSize (type->next);
+      else
         DCL_ELEM (type) = size;
     }
 
-    return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
+  return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
 }
 
 
@@ -1003,9 +1010,10 @@ createIvalArray (ast * sym, sym_link * type, initList * ilist)
 /* createIvalCharPtr - generates initial values for char pointers  */
 /*-----------------------------------------------------------------*/
 static ast *
-createIvalCharPtr (ast * sym, sym_link * type, ast * iexpr)
+createIvalCharPtr (ast * sym, sym_link * type, ast * iexpr, ast *rootVal)
 {
   ast *rast = NULL;
+  unsigned size = 0;
 
   /* if this is a pointer & right is a literal array then */
   /* just assignment will do                              */
@@ -1024,10 +1032,10 @@ createIvalCharPtr (ast * sym, sym_link * type, ast * iexpr)
       /* to the array element */
       char *s = SPEC_CVAL (iexpr->etype).v_char;
       int i = 0;
-      int size = getSize (iexpr->ftype);
       int symsize = getSize (type);
-      
-      if (size>symsize)
+
+      size = getSize (iexpr->ftype);
+      if (symsize && size>symsize)
         {
           if (size>(symsize+1))
             {
@@ -1053,6 +1061,16 @@ createIvalCharPtr (ast * sym, sym_link * type, ast * iexpr)
       // now WE don't need iexpr's symbol anymore
       freeStringSymbol(AST_SYMBOL(iexpr));
 
+      /* if we have not been given a size  */
+      if (!DCL_ELEM (type))
+        {
+          /* check, if it's a flexible array */
+          if (IS_STRUCT (AST_VALUE (rootVal)->type))
+            AST_SYMBOL(rootVal)->flexArrayLength = size * getSize (type->next);
+          else
+            DCL_ELEM (type) = size;
+        }
+
       return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
     }
 
@@ -1063,7 +1081,7 @@ createIvalCharPtr (ast * sym, sym_link * type, ast * iexpr)
 /* createIvalPtr - generates initial value for pointers            */
 /*-----------------------------------------------------------------*/
 static ast *
-createIvalPtr (ast * sym, sym_link * type, initList * ilist)
+createIvalPtr (ast * sym, sym_link * type, initList * ilist, ast *rootVal)
 {
   ast *rast;
   ast *iexpr;
@@ -1076,7 +1094,7 @@ createIvalPtr (ast * sym, sym_link * type, initList * ilist)
 
   /* if character pointer */
   if (IS_CHAR (type->next))
-    if ((rast = createIvalCharPtr (sym, type, iexpr)))
+    if ((rast = createIvalCharPtr (sym, type, iexpr, rootVal)))
       return rast;
 
   return newNode ('=', sym, iexpr);
@@ -1086,7 +1104,7 @@ createIvalPtr (ast * sym, sym_link * type, initList * ilist)
 /* createIval - generates code for initial value                   */
 /*-----------------------------------------------------------------*/
 static ast *
-createIval (ast * sym, sym_link * type, initList * ilist, ast * wid)
+createIval (ast * sym, sym_link * type, initList * ilist, ast * wid, ast *rootValue)
 {
   ast *rast = NULL;
 
@@ -1095,15 +1113,15 @@ createIval (ast * sym, sym_link * type, initList * ilist, ast * wid)
 
   /* if structure then    */
   if (IS_STRUCT (type))
-    rast = createIvalStruct (sym, type, ilist);
+    rast = createIvalStruct (sym, type, ilist, rootValue);
   else
     /* if this is a pointer */
   if (IS_PTR (type))
-    rast = createIvalPtr (sym, type, ilist);
+    rast = createIvalPtr (sym, type, ilist, rootValue);
   else
     /* if this is an array   */
   if (IS_ARRAY (type))
-    rast = createIvalArray (sym, type, ilist);
+    rast = createIvalArray (sym, type, ilist, rootValue);
   else
     /* if type is SPECIFIER */
   if (IS_SPEC (type))
@@ -1119,7 +1137,8 @@ createIval (ast * sym, sym_link * type, initList * ilist, ast * wid)
 /* initAggregates - initialises aggregate variables with initv     */
 /*-----------------------------------------------------------------*/
 ast * initAggregates (symbol * sym, initList * ival, ast * wid) {
-  return createIval (newAst_VALUE (symbolVal (sym)), sym->type, ival, wid);
+  ast *newAst = newAst_VALUE (symbolVal (sym));
+  return createIval (newAst, sym->type, ival, wid, newAst);
 }
 
 /*-----------------------------------------------------------------*/
@@ -3933,6 +3952,37 @@ decorateType (ast * tree, RESULT_TYPE resultType)
                                    tree->opval.val->type);
           return tree;
         }
+      /* if one is 'signed char ' and the other one is 'unsigned char' */
+      /* it's necessary to promote to int */
+      if (IS_CHAR (RTYPE (tree)) && IS_CHAR (LTYPE (tree)) &&
+          (IS_UNSIGNED (RTYPE (tree)) != IS_UNSIGNED (LTYPE (tree))))
+        {
+          /* Literals are 'optimized' to 'unsigned char'. Try to figure out,
+             if it's possible to use a 'signed char' */
+
+              /* is left a 'unsigned char'? */
+          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)
+            {
+              /* 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)
+            {
+              SPEC_USIGN (LETYPE (tree)) = 0;
+            }
+          else
+            {
+              werror (W_CMP_SU_CHAR);
+              tree->left  = addCast (tree->left , RESULT_TYPE_INT, TRUE);
+              tree->right = addCast (tree->right, RESULT_TYPE_INT, TRUE);
+            }
+        }
+
       LRVAL (tree) = RRVAL (tree) = 1;
       TTYPE (tree) = TETYPE (tree) = newCharLink ();
       return tree;