* src/SDCCicode.c (geniCodeAdd),
[fw/sdcc] / src / SDCCast.c
index f1cc4b7828d35ad5e003e75d104e5f045b8d6284..0a289dbede28214a505a5711773b8c63afc9bbe9 100644 (file)
@@ -52,6 +52,7 @@ static ast *createIval (ast *, sym_link *, initList *, ast *);
 static ast *createIvalCharPtr (ast *, sym_link *, ast *);
 static ast *optimizeCompare (ast *);
 ast *optimizeRRCRLC (ast *);
+ast *optimizeSWAP (ast *);
 ast *optimizeGetHbit (ast *);
 ast *backPatchLabels (ast *, symbol *, symbol *);
 void PA(ast *t);
@@ -272,6 +273,52 @@ ast *removeIncDecOps (ast * tree) {
  return tree;
 }
 
+/*-----------------------------------------------------------------*/
+/* removePreIncDecOps: remove for side effects in *_ASSIGN's       */
+/*                  "*++s += 3" -> "*++s = *++s + 3"               */
+/*-----------------------------------------------------------------*/
+ast *removePreIncDecOps (ast * tree) {
+
+  // traverse the tree and remove pre-inc/dec ops
+
+  if (!tree)
+    return NULL;
+
+  if (tree->type == EX_OP &&
+      (tree->opval.op == INC_OP || tree->opval.op == DEC_OP)) {
+    if (tree->right)
+      tree=tree->right;
+  }
+
+  tree->left=removePreIncDecOps(tree->left);
+  tree->right=removePreIncDecOps(tree->right);
+
+ return tree;
+}
+
+/*-----------------------------------------------------------------*/
+/* removePostIncDecOps: remove for side effects in *_ASSIGN's      */
+/*                  "*s++ += 3" -> "*s++ = *s++ + 3"               */
+/*-----------------------------------------------------------------*/
+ast *removePostIncDecOps (ast * tree) {
+
+  // traverse the tree and remove pre-inc/dec ops
+
+  if (!tree)
+    return NULL;
+
+  if (tree->type == EX_OP &&
+      (tree->opval.op == INC_OP || tree->opval.op == DEC_OP)) {
+    if (tree->left)
+      tree=tree->left;
+  }
+
+  tree->left=removePostIncDecOps(tree->left);
+  tree->right=removePostIncDecOps(tree->right);
+
+ return tree;
+}
+
 /*-----------------------------------------------------------------*/
 /* hasSEFcalls - returns TRUE if tree has a function call          */
 /*-----------------------------------------------------------------*/
@@ -938,8 +985,9 @@ 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);
 
-      while (*s)
+      for (i=0;i<size;i++)
        {
          rast = newNode (NULLOP,
                          rast,
@@ -947,15 +995,8 @@ createIvalCharPtr (ast * sym, sym_link * type, ast * iexpr)
                                   newNode ('[', sym,
                                   newAst_VALUE (valueFromLit ((float) i))),
                                   newAst_VALUE (valueFromLit (*s))));
-         i++;
          s++;
        }
-      rast = newNode (NULLOP,
-                     rast,
-                     newNode ('=',
-                              newNode ('[', sym,
-                                  newAst_VALUE (valueFromLit ((float) i))),
-                              newAst_VALUE (valueFromLit (*s))));
 
       // now WE don't need iexpr's symbol anymore
       freeStringSymbol(AST_SYMBOL(iexpr));
@@ -1147,12 +1188,14 @@ stringToSymbol (value * val)
   static int charLbl = 0;
   symbol *sym;
   set *sp;
+  int size;
 
   // have we heard this before?
   for (sp=statsg->syms; sp; sp=sp->next) {
     sym=sp->item;
-    if (sym->isstrlit && 
-       !strcmp(SPEC_CVAL(sym->etype).v_char, SPEC_CVAL(val->etype).v_char)) {
+    size = getSize (sym->type);
+    if (sym->isstrlit && size == getSize (val->type) &&
+       !memcmp(SPEC_CVAL(sym->etype).v_char, SPEC_CVAL(val->etype).v_char, size)) {
       // yes, this is old news. Don't publish it again.
       sym->isstrlit++; // but raise the usage count
       return symbolVal(sym);
@@ -1596,7 +1639,7 @@ isConformingBody (ast * pbody, symbol * sym, ast * body)
       return TRUE;
 
 /*------------------------------------------------------------------*/
-    case INC_OP:               /* incerement operator unary so left only */
+    case INC_OP:
     case DEC_OP:
 
       /* sure we are not sym is not modified */
@@ -1664,6 +1707,7 @@ isConformingBody (ast * pbody, symbol * sym, ast * body)
     case RRC:
     case RLC:
     case GETHBIT:
+    case SWAP:
       if (IS_AST_SYM_VALUE (pbody->left) &&
          isSymbolEqual (AST_SYMBOL (pbody->left), sym))
        return FALSE;
@@ -1682,6 +1726,14 @@ isConformingBody (ast * pbody, symbol * sym, ast * body)
     case '?':
     case ':':
     case SIZEOF:               /* evaluate wihout code generation */
+      
+      if (IS_AST_SYM_VALUE (pbody->left) &&
+         isSymbolEqual (AST_SYMBOL (pbody->left), sym))
+       return FALSE;
+
+      if (IS_AST_SYM_VALUE (pbody->right) &&
+         isSymbolEqual (AST_SYMBOL (pbody->right), sym))
+       return FALSE;
 
       return isConformingBody (pbody->left, sym, body) &&
        isConformingBody (pbody->right, sym, body);
@@ -2158,6 +2210,7 @@ decorateType (ast * tree)
       /* adjust the storage class */
       switch (DCL_TYPE(tree->left->ftype)) {
       case POINTER:
+               SPEC_SCLS(TETYPE(tree)) = S_DATA; 
        break;
       case FPOINTER:
                SPEC_SCLS(TETYPE(tree)) = S_XDATA; 
@@ -2166,6 +2219,7 @@ decorateType (ast * tree)
                SPEC_SCLS(TETYPE(tree)) = S_CODE; 
        break;
       case GPOINTER:
+       SPEC_SCLS (TETYPE (tree)) = 0;
        break;
       case PPOINTER:
                SPEC_SCLS(TETYPE(tree)) = S_XSTACK; 
@@ -2177,11 +2231,17 @@ decorateType (ast * tree)
                SPEC_SCLS(TETYPE(tree)) = S_EEPROM;
        break;
       case UPOINTER:
+       SPEC_SCLS (TETYPE (tree)) = 0;
+       break;
       case ARRAY:
       case FUNCTION:
        break;
       }
       
+      /* This breaks with extern declarations, bitfields, and perhaps other */
+      /* cases (gcse). Let's leave this optimization disabled for now and   */
+      /* ponder if there's a safe way to do this. -- EEP                    */
+      #if 0
       if (IS_ADDRESS_OF_OP (tree->left) && IS_AST_SYM_VALUE(tree->left->left)
           && SPEC_ABSA (AST_SYMBOL (tree->left->left)->etype))
         {
@@ -2214,14 +2274,15 @@ decorateType (ast * tree)
             tree->left = NULL;
             tree->right = NULL;
         }
-
+      #endif
+      
       return tree;
 
       /*------------------------------------------------------------------*/
       /*----------------------------*/
       /*  ++/-- operation           */
       /*----------------------------*/
-    case INC_OP:               /* increment operator unary so left only */
+    case INC_OP:
     case DEC_OP:
       {
        sym_link *ltc = (tree->right ? RTYPE (tree) : LTYPE (tree));
@@ -2323,7 +2384,7 @@ decorateType (ast * tree)
          goto errorTreeReturn;
        }
 
-      if (SPEC_SCLS (tree->left->etype) == S_REGISTER)
+      if (LETYPE(tree) && SPEC_SCLS (tree->left->etype) == S_REGISTER)
        {
          werror (E_ILLEGAL_ADDR, "address of register variable");
          goto errorTreeReturn;
@@ -2346,7 +2407,9 @@ decorateType (ast * tree)
          werror (E_LVALUE_REQUIRED, "address of");
          goto errorTreeReturn;
        }
-      if (SPEC_SCLS (tree->left->etype) == S_CODE)
+      if (!LETYPE (tree))
+        DCL_TYPE (p) = POINTER;
+      else if (SPEC_SCLS (tree->left->etype) == S_CODE)
        DCL_TYPE (p) = CPOINTER;
       else if (SPEC_SCLS (tree->left->etype) == S_XDATA)
        DCL_TYPE (p) = FPOINTER;
@@ -2400,6 +2463,11 @@ decorateType (ast * tree)
        ast *wtree = optimizeRRCRLC (tree);
        if (wtree != tree)
          return decorateType (wtree);
+       
+       wtree = optimizeSWAP (tree);
+       if (wtree != tree)
+         return decorateType (wtree);
+        
        // fall through
       }
 
@@ -2606,6 +2674,36 @@ decorateType (ast * tree)
             }
           TTYPE (tree) = copyLinkChain (LTYPE (tree)->next);
          TETYPE (tree) = getSpec (TTYPE (tree));
+         /* adjust the storage class */
+         switch (DCL_TYPE(tree->left->ftype)) {
+           case POINTER:
+             SPEC_SCLS(TETYPE(tree)) = S_DATA;
+             break;
+           case FPOINTER:
+             SPEC_SCLS(TETYPE(tree)) = S_XDATA; 
+             break;
+           case CPOINTER:
+             SPEC_SCLS(TETYPE(tree)) = S_CODE; 
+             break;
+           case GPOINTER:
+             SPEC_SCLS (TETYPE (tree)) = 0;
+             break;
+           case PPOINTER:
+             SPEC_SCLS(TETYPE(tree)) = S_XSTACK; 
+             break;
+           case IPOINTER:
+             SPEC_SCLS(TETYPE(tree)) = S_IDATA;
+             break;
+           case EEPPOINTER:
+             SPEC_SCLS(TETYPE(tree)) = S_EEPROM;
+             break;
+           case UPOINTER:
+             SPEC_SCLS (TETYPE (tree)) = 0;
+              break;
+           case ARRAY:
+           case FUNCTION:
+             break;
+         }
          return tree;
        }
 
@@ -2678,7 +2776,7 @@ decorateType (ast * tree)
       /* if unary plus */
       if (!tree->right)
        {
-         if (!IS_INTEGRAL (LTYPE (tree)))
+         if (!IS_ARITHMETIC (LTYPE (tree)))
            {
              werror (E_UNARY_OP, '+');
              goto errorTreeReturn;
@@ -3000,6 +3098,7 @@ decorateType (ast * tree)
       /*----------------------------*/
     case RRC:
     case RLC:
+    case SWAP:
       TTYPE (tree) = LTYPE (tree);
       TETYPE (tree) = LETYPE (tree);
       return tree;
@@ -3054,14 +3153,9 @@ decorateType (ast * tree)
          }
        }
       LRVAL (tree) = RRVAL (tree) = 1;
-      if (IS_LITERAL (LTYPE (tree)) && !IS_LITERAL (RTYPE (tree)))
-       {
-         COPYTYPE (TTYPE (tree), TETYPE (tree), RTYPE (tree));
-       }
-      else
-       {
-         COPYTYPE (TTYPE (tree), TETYPE (tree), LTYPE (tree));
-       }
+      TTYPE (tree) = TETYPE (tree) = copyLinkChain (LTYPE (tree));
+      if (IS_LITERAL (TTYPE (tree)))
+        SPEC_SCLS (TTYPE (tree)) &= ~S_LITERAL;
       return tree;
 
       /*------------------------------------------------------------------*/
@@ -3155,7 +3249,7 @@ decorateType (ast * tree)
          tree->opval.val = valCastLiteral (
            LTYPE (tree),
            element->offset
-            + floatFromVal (valFromType (RETYPE (tree->right->left->left)))
+            + floatFromVal (valFromType (RTYPE (tree->right->left->left)))
           );
 
          TTYPE (tree) = tree->opval.val->type;
@@ -3191,7 +3285,7 @@ decorateType (ast * tree)
           sym->cdef = 1;
           sym->isref = 1;
           SPEC_STAT (sym->etype) = 1;
-          SPEC_ADDR(sym->etype) = floatFromVal (valFromType (RETYPE (tree)));
+          SPEC_ADDR(sym->etype) = floatFromVal (valFromType (RTYPE (tree)));
           SPEC_ABSA(sym->etype) = 1;
           addSym (SymbolTab, sym, sym->name, 0, 0, 0);
           allocGlobal (sym);
@@ -3209,7 +3303,7 @@ decorateType (ast * tree)
          tree->type = EX_VALUE;
          tree->opval.val =
          valCastLiteral (LTYPE (tree),
-                         floatFromVal (valFromType (RETYPE (tree))));
+                         floatFromVal (valFromType (RTYPE (tree))));
          TTYPE (tree) = tree->opval.val->type;
          tree->left = NULL;
          tree->right = NULL;
@@ -3254,8 +3348,8 @@ decorateType (ast * tree)
          IS_LITERAL (LTYPE (tree)))
        {
          tree->type = EX_VALUE;
-         tree->opval.val = valLogicAndOr (valFromType (LETYPE (tree)),
-                                          valFromType (RETYPE (tree)),
+         tree->opval.val = valLogicAndOr (valFromType (LTYPE (tree)),
+                                          valFromType (RTYPE (tree)),
                                           tree->opval.op);
          tree->right = tree->left = NULL;
          TETYPE (tree) = getSpec (TTYPE (tree) =
@@ -3296,7 +3390,7 @@ decorateType (ast * tree)
          if (compareType (LTYPE (tree), RTYPE (tree)) == 0)
            {
              werror (E_COMPARE_OP);
-             fprintf (stderr, "comparring type ");
+             fprintf (stderr, "comparing type ");
              printTypeChain (LTYPE (tree), stderr);
              fprintf (stderr, "to type ");
              printTypeChain (RTYPE (tree), stderr);
@@ -3494,11 +3588,11 @@ decorateType (ast * tree)
       TETYPE (tree) = getSpec (TTYPE (tree) = LTYPE (tree));
 
       if (!tree->initMode && IS_CONSTANT (LTYPE (tree)))
-       werror (E_CODE_WRITE, *tree->opval.op==MUL_ASSIGN ? "*=" : "/=");
+       werror (E_CODE_WRITE, tree->opval.op==MUL_ASSIGN ? "*=" : "/=");
 
       if (LRVAL (tree))
        {
-         werror (E_LVALUE_REQUIRED, *tree->opval.op==MUL_ASSIGN ? "*=" : "/=");
+         werror (E_LVALUE_REQUIRED, tree->opval.op==MUL_ASSIGN ? "*=" : "/=");
          goto errorTreeReturn;
        }
       LLVAL (tree) = 1;
@@ -4343,6 +4437,11 @@ optimizeGetHbit (ast * tree)
   if ((i = (int) AST_LIT_VALUE (tree->left->right)) !=
       (j = (getSize (TTYPE (tree->left->left)) * 8 - 1)))
     return tree;
+      
+  /* make sure the port supports GETHBIT */
+  if (port->hasExtBitOp
+      && !port->hasExtBitOp(GETHBIT, getSize (TTYPE (tree->left->left))))
+    return tree;
 
   return decorateType (newNode (GETHBIT, tree->left->left, NULL));
 
@@ -4395,6 +4494,11 @@ optimizeRRCRLC (ast * root)
          (getSize (TTYPE (root->left->left)) * 8 - 1))
        goto tryNext0;
 
+      /* make sure the port supports RLC */
+      if (port->hasExtBitOp
+          && !port->hasExtBitOp(RLC, getSize (TTYPE (root->left->left))))
+        return root;
+
       /* whew got the first case : create the AST */
       return newNode (RLC, root->left->left, NULL);
     }
@@ -4425,6 +4529,11 @@ tryNext0:
          (getSize (TTYPE (root->left->left)) * 8 - 1))
        goto tryNext1;
 
+      /* make sure the port supports RLC */
+      if (port->hasExtBitOp
+          && !port->hasExtBitOp(RLC, getSize (TTYPE (root->left->left))))
+        return root;
+
       /* whew got the first case : create the AST */
       return newNode (RLC, root->left->left, NULL);
 
@@ -4456,6 +4565,11 @@ tryNext1:
          (getSize (TTYPE (root->left->left)) * 8 - 1))
        goto tryNext2;
 
+      /* make sure the port supports RRC */
+      if (port->hasExtBitOp
+          && !port->hasExtBitOp(RRC, getSize (TTYPE (root->left->left))))
+        return root;
+
       /* whew got the first case : create the AST */
       return newNode (RRC, root->left->left, NULL);
 
@@ -4486,6 +4600,11 @@ tryNext2:
          (getSize (TTYPE (root->left->left)) * 8 - 1))
        return root;
 
+      /* make sure the port supports RRC */
+      if (port->hasExtBitOp
+          && !port->hasExtBitOp(RRC, getSize (TTYPE (root->left->left))))
+        return root;
+
       /* whew got the first case : create the AST */
       return newNode (RRC, root->left->left, NULL);
 
@@ -4495,6 +4614,61 @@ tryNext2:
   return root;
 }
 
+/*-----------------------------------------------------------------*/
+/* optimizeSWAP :- optimize for nibble/byte/word swaps             */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeSWAP (ast * root)
+{
+  /* will look for trees of the form
+     (?expr << 4) | (?expr >> 4) or
+     (?expr >> 4) | (?expr << 4) will make that
+     into a SWAP : operation ..
+     note : by 4 I mean (number of bits required to hold the
+     variable /2 ) */
+  /* if the root operations is not a | operation the not */
+  if (!IS_BITOR (root))
+    return root;
+
+  /* (?expr << 4) | (?expr >> 4) */
+  if ((IS_LEFT_OP (root->left) && IS_RIGHT_OP (root->right))
+      || (IS_RIGHT_OP (root->left) && IS_LEFT_OP (root->right)))
+    {
+
+      if (!SPEC_USIGN (TETYPE (root->left->left)))
+       return root;
+
+      if (!IS_AST_LIT_VALUE (root->left->right) ||
+         !IS_AST_LIT_VALUE (root->right->right))
+       return root;
+
+      /* make sure it is the same expression */
+      if (!isAstEqual (root->left->left,
+                      root->right->left))
+       return root;
+
+      if (AST_LIT_VALUE (root->left->right) !=
+         (getSize (TTYPE (root->left->left)) * 4))
+       return root;
+
+      if (AST_LIT_VALUE (root->right->right) !=
+         (getSize (TTYPE (root->left->left)) * 4))
+       return root;
+
+      /* make sure the port supports SWAP */
+      if (port->hasExtBitOp
+          && !port->hasExtBitOp(SWAP, getSize (TTYPE (root->left->left))))
+        return root;
+
+      /* found it : create the AST */
+      return newNode (SWAP, root->left->left, NULL);
+    }
+
+
+  /* not found return root */
+  return root;
+}
+
 /*-----------------------------------------------------------------*/
 /* optimizeCompare - otimizes compares for bit variables     */
 /*-----------------------------------------------------------------*/
@@ -4985,18 +5159,28 @@ void ast_print (ast * tree, FILE *outfile, int indent)
                /*----------------------------*/
                /*  ++/-- operation           */
                /*----------------------------*/
-       case INC_OP:            /* incerement operator unary so left only */
+       case INC_OP:
+               if (tree->left)
+                 fprintf(outfile,"post-");
+               else
+                 fprintf(outfile,"pre-");
                fprintf(outfile,"INC_OP (%p) type (",tree);
                printTypeChain(tree->ftype,outfile);
                fprintf(outfile,")\n");
-               ast_print(tree->left,outfile,indent+2);
+               ast_print(tree->left,outfile,indent+2); /* postincrement case */
+               ast_print(tree->right,outfile,indent+2); /* preincrement case */
                return ;
 
        case DEC_OP:
+               if (tree->left)
+                 fprintf(outfile,"post-");
+               else
+                 fprintf(outfile,"pre-");
                fprintf(outfile,"DEC_OP (%p) type (",tree);
                printTypeChain(tree->ftype,outfile);
                fprintf(outfile,")\n");
-               ast_print(tree->left,outfile,indent+2);
+               ast_print(tree->left,outfile,indent+2); /* postdecrement case */
+               ast_print(tree->right,outfile,indent+2); /* predecrement case */
                return ;
 
                /*------------------------------------------------------------------*/
@@ -5169,6 +5353,12 @@ void ast_print (ast * tree, FILE *outfile, int indent)
                fprintf(outfile,")\n");
                ast_print(tree->left,outfile,indent+2);
                return ;
+       case SWAP:
+               fprintf(outfile,"SWAP (%p) type (",tree);
+               printTypeChain(tree->ftype,outfile);
+               fprintf(outfile,")\n");
+               ast_print(tree->left,outfile,indent+2);
+               return ;
        case GETHBIT:
                fprintf(outfile,"GETHBIT (%p) type (",tree);
                printTypeChain(tree->ftype,outfile);
@@ -5495,6 +5685,9 @@ void ast_print (ast * tree, FILE *outfile, int indent)
                fprintf(outfile,"FOR LOOP BODY \n");
                ast_print(tree->left,outfile,indent+2);
                return ;
+       case CRITICAL:
+               fprintf(outfile,"CRITICAL (%p) \n",tree);
+               ast_print(tree->left,outfile,indent+2);
        default:
            return ;
        }
@@ -5504,3 +5697,29 @@ void PA(ast *t)
 {
        ast_print(t,stdout,0);
 }
+
+
+
+/*-----------------------------------------------------------------*/
+/* astErrors : returns non-zero if errors present in tree          */
+/*-----------------------------------------------------------------*/
+int astErrors(ast *t)
+{
+  int errors=0;
+  
+  if (t)
+    {
+      if (t->isError)
+        errors++;
+  
+      if (t->type == EX_VALUE
+          && t->opval.val->sym
+          && t->opval.val->sym->undefined)
+        errors++;
+
+      errors += astErrors(t->left);
+      errors += astErrors(t->right);
+    }
+    
+  return errors;
+}