* src/SDCCast.c (decorateType): fixed previouse immature commit, added optimisation
[fw/sdcc] / src / SDCCast.c
index 990f43fed6a379a1793adb92706b29f2ab02e5b9..01411dbed977c25706b3c4da9ce598b706503277 100644 (file)
@@ -55,7 +55,10 @@ static ast *createIvalCharPtr (ast *, sym_link *, ast *);
 static ast *optimizeCompare (ast *);
 ast *optimizeRRCRLC (ast *);
 ast *optimizeSWAP (ast *);
-ast *optimizeGetHbit (ast *);
+ast *optimizeGetHbit (ast *, RESULT_TYPE);
+ast *optimizeGetAbit (ast *, RESULT_TYPE);
+ast *optimizeGetByte (ast *, RESULT_TYPE);
+ast *optimizeGetWord (ast *, RESULT_TYPE);
 ast *backPatchLabels (ast *, symbol *, symbol *);
 void PA(ast *t);
 int inInitMode = 0;
@@ -1756,6 +1759,9 @@ isConformingBody (ast * pbody, symbol * sym, ast * body)
     case '%':
     case LEFT_OP:
     case RIGHT_OP:
+    case GETABIT:
+    case GETBYTE:
+    case GETWORD:
 
       if (IS_AST_SYM_VALUE (pbody->left) &&
           isSymbolEqual (AST_SYMBOL (pbody->left), sym))
@@ -2081,7 +2087,7 @@ getResultTypeFromType (sym_link *type)
 /* addCast - adds casts to a type specified by RESULT_TYPE         */
 /*-----------------------------------------------------------------*/
 static ast *
-addCast (ast *tree, RESULT_TYPE resultType, bool upcast)
+addCast (ast *tree, RESULT_TYPE resultType, bool promote)
 {
   sym_link *newLink;
   bool upCasted = FALSE;
@@ -2089,9 +2095,22 @@ addCast (ast *tree, RESULT_TYPE resultType, bool upcast)
   switch (resultType)
     {
       case RESULT_TYPE_NONE:
-        /* char: promote to int */
-        if (!upcast ||
+        /* if thing smaller than int must be promoted to int */
+        if (!promote ||
             getSize (tree->etype) >= INTSIZE)
+          /* promotion not necessary or already an int */
+          return tree;
+        /* char and bits: promote to int */
+        newLink = newIntLink();
+        upCasted = TRUE;
+        break;
+      case RESULT_TYPE_BIT:
+        if (!promote ||
+            /* already an int */
+            bitsForType (tree->etype) >= 16 ||
+            /* bit to bit operation: don't promote, the code generators
+               hopefully know everything about promotion rules */
+            bitsForType (tree->etype) == 1)
           return tree;
         newLink = newIntLink();
         upCasted = TRUE;
@@ -2112,14 +2131,14 @@ addCast (ast *tree, RESULT_TYPE resultType, bool upcast)
           }
 #endif
         /* char: promote to int */
-        if (!upcast ||
+        if (!promote ||
             getSize (tree->etype) >= INTSIZE)
           return tree;
         newLink = newIntLink();
         upCasted = TRUE;
         break;
       case RESULT_TYPE_OTHER:
-        if (!upcast)
+        if (!promote)
           return tree;
         /* return type is long, float: promote char to int */
         if (getSize (tree->etype) >= INTSIZE)
@@ -2148,6 +2167,9 @@ resultTypePropagate (ast *tree, RESULT_TYPE resultType)
 {
   switch (tree->opval.op)
     {
+      case AND_OP:
+      case OR_OP:
+        return resultType;
       case '=':
       case '?':
       case ':':
@@ -2597,7 +2619,34 @@ decorateType (ast * tree, RESULT_TYPE resultType)
           /* see if this is a GETHBIT operation if yes
              then return that */
           {
-            ast *otree = optimizeGetHbit (tree);
+            ast *otree = optimizeGetHbit (tree, resultType);
+
+            if (otree != tree)
+              return decorateType (otree, RESULT_TYPE_NONE);
+          }
+
+          /* see if this is a GETABIT operation if yes
+             then return that */
+          {
+            ast *otree = optimizeGetAbit (tree, resultType);
+
+            if (otree != tree)
+              return decorateType (otree, RESULT_TYPE_NONE);
+          }
+
+          /* see if this is a GETBYTE operation if yes
+             then return that */
+          {
+            ast *otree = optimizeGetByte (tree, resultType);
+
+            if (otree != tree)
+              return decorateType (otree, RESULT_TYPE_NONE);
+          }
+
+          /* see if this is a GETWORD operation if yes
+             then return that */
+          {
+            ast *otree = optimizeGetWord (tree, resultType);
 
             if (otree != tree)
               return decorateType (otree, RESULT_TYPE_NONE);
@@ -3373,7 +3422,23 @@ decorateType (ast * tree, RESULT_TYPE resultType)
           TETYPE (tree) = TTYPE (tree) = tree->opval.val->type;
           return addCast (tree, resultType, TRUE);
         }
-      tree->left = addCast (tree->left, resultType, TRUE);
+
+      if (resultType == RESULT_TYPE_BIT &&
+          IS_UNSIGNED (tree->left->etype) &&
+          getSize (tree->left->etype) < INTSIZE)
+        {
+          /* promotion rules are responsible for this strange result:
+             bit -> int -> ~int -> bit
+             uchar -> int -> ~int -> bit
+          */
+          werror(W_COMPLEMENT);
+
+          /* optimize bit-result, even if we optimize a buggy source */
+          tree->type = EX_VALUE;
+          tree->opval.val = constVal ("1");
+        }
+      else
+        tree->left = addCast (tree->left, resultType, TRUE);
       LRVAL (tree) = 1;
       COPYTYPE (TTYPE (tree), TETYPE (tree), LTYPE (tree));
       return tree;
@@ -3402,7 +3467,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
           return tree;
         }
       LRVAL (tree) = 1;
-      TTYPE (tree) = TETYPE (tree) = newCharLink ();
+      TTYPE (tree) = TETYPE (tree) = (resultTypeProp == RESULT_TYPE_BIT) ? newBoolLink() :newCharLink();
       return tree;
 
       /*------------------------------------------------------------------*/
@@ -3417,7 +3482,16 @@ decorateType (ast * tree, RESULT_TYPE resultType)
       return tree;
 
     case GETHBIT:
-      TTYPE (tree) = TETYPE (tree) = newCharLink ();
+    case GETABIT:
+      TTYPE (tree) = TETYPE (tree) = (resultTypeProp == RESULT_TYPE_BIT) ? newBoolLink() :newCharLink();
+      return tree;
+
+    case GETBYTE:
+      TTYPE (tree) = TETYPE (tree) = newCharLink();
+      return tree;
+
+    case GETWORD:
+      TTYPE (tree) = TETYPE (tree) = newIntLink();
       return tree;
 
     case LEFT_OP:
@@ -3451,6 +3525,24 @@ decorateType (ast * tree, RESULT_TYPE resultType)
           return tree;
         }
 
+      /* see if this is a GETBYTE operation if yes
+         then return that */
+      {
+        ast *otree = optimizeGetByte (tree, resultType);
+
+        if (otree != tree)
+          return decorateType (otree, RESULT_TYPE_NONE);
+      }
+
+      /* see if this is a GETWORD operation if yes
+         then return that */
+      {
+        ast *otree = optimizeGetWord (tree, resultType);
+
+        if (otree != tree)
+          return decorateType (otree, RESULT_TYPE_NONE);
+      }
+
       LRVAL (tree) = RRVAL (tree) = 1;
       if (tree->opval.op == LEFT_OP)
         {
@@ -3735,7 +3827,7 @@ decorateType (ast * tree, RESULT_TYPE resultType)
           return tree;
         }
       LRVAL (tree) = RRVAL (tree) = 1;
-      TTYPE (tree) = TETYPE (tree) = newCharLink ();
+      TTYPE (tree) = TETYPE (tree) = (resultTypeProp == RESULT_TYPE_BIT) ? newBoolLink() :newCharLink();
       return tree;
 
       /*------------------------------------------------------------------*/
@@ -4867,41 +4959,202 @@ createWhile (symbol * trueLabel, symbol * continueLabel,
 }
 
 /*-----------------------------------------------------------------*/
-/* optimizeGetHbit - get highest order bit of the expression       */
+/* isShiftRightLitVal _BitAndLitVal - helper function              */
 /*-----------------------------------------------------------------*/
-ast *
-optimizeGetHbit (ast * tree)
+static ast *
+isShiftRightLitVal_BitAndLitVal (ast * tree)
 {
-  int i, j;
   /* if this is not a bit and */
   if (!IS_BITAND (tree))
-    return tree;
+    return NULL;
 
   /* will look for tree of the form
-     ( expr >> ((sizeof expr) -1) ) & 1 */
+     ( expr >> litval2) & litval1 */
   if (!IS_AST_LIT_VALUE (tree->right))
+    return NULL;
+
+  if (!IS_RIGHT_OP (tree->left))
+    return NULL;
+
+  if (!IS_AST_LIT_VALUE (tree->left->right))
+    return NULL;
+
+  return tree->left->left;
+}
+
+/*-----------------------------------------------------------------*/
+/* isBitAndPowOf2 - helper function                                */
+/*-----------------------------------------------------------------*/
+static int
+isBitAndPow2 (ast * tree)
+{
+  int p2;
+
+  /* if this is not a bit and */
+  if (!IS_BITAND (tree))
+    return -1;
+
+  /* will look for tree of the form
+     ( expr & (1 << litval) */
+  if (!IS_AST_LIT_VALUE (tree->right))
+    return -1;
+
+  if (AST_LIT_VALUE (tree->right) == 1)
+    return 0;
+  p2 = powof2 ((TYPE_UDWORD)AST_LIT_VALUE (tree->right));
+  if (!p2)
+    return -1;
+
+  return p2;
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeGetHbit - get highest order bit of the expression       */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeGetHbit (ast * tree, RESULT_TYPE resultType)
+{
+  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)) !=
+          (j = (getSize (TTYPE (expr)) * 8 - 1))))
+        expr = NULL;
+    }
+  if (!expr && (resultType == RESULT_TYPE_BIT))
+    {
+      expr = tree->left;
+      if (isBitAndPow2 (tree) != getSize (TTYPE (expr)) * 8 - 1)
+        expr = NULL;
+    }
+  if (!expr)
     return tree;
 
-  if (AST_LIT_VALUE (tree->right) != 1)
+  /* make sure the port supports GETHBIT */
+  if (port->hasExtBitOp
+      && !port->hasExtBitOp(GETHBIT, getSize (TTYPE (expr))))
     return tree;
 
-  if (!IS_RIGHT_OP (tree->left))
+  return decorateType (newNode (GETHBIT, expr, NULL), RESULT_TYPE_NONE);
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeGetAbit - get a single bit of the expression            */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeGetAbit (ast * tree, RESULT_TYPE resultType)
+{
+  ast * expr;
+  ast * count = NULL;
+
+  expr = isShiftRightLitVal_BitAndLitVal(tree);
+  if (expr)
+    {
+  if (AST_LIT_VALUE (tree->right) != 1)
+        expr = NULL;
+      count = tree->left->right;
+    }
+  if (!expr && (resultType == RESULT_TYPE_BIT))
+    {
+      int p2 = isBitAndPow2 (tree);
+      if (p2 >= 0)
+        {
+          expr = tree->left;
+          count = newAst_VALUE (valueFromLit (p2));
+        }
+    }
+  if (!expr)
     return tree;
 
-  if (!IS_AST_LIT_VALUE (tree->left->right))
+  /* make sure the port supports GETABIT */
+  if (port->hasExtBitOp
+      && !port->hasExtBitOp(GETABIT, getSize (TTYPE (expr))))
     return tree;
 
-  if ((i = (int) AST_LIT_VALUE (tree->left->right)) !=
-      (j = (getSize (TTYPE (tree->left->left)) * 8 - 1)))
+  return decorateType (newNode (GETABIT, expr, count), RESULT_TYPE_NONE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeGetByte - get a byte of the expression                  */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeGetByte (ast * tree, RESULT_TYPE resultType)
+{
+  unsigned int i = 0;
+  ast * expr;
+  ast * count = NULL;
+
+  expr = isShiftRightLitVal_BitAndLitVal(tree);
+  if (expr)
+    {
+      i = (unsigned int) AST_LIT_VALUE (tree->left->right);
+      count = tree->left->right;
+      if (AST_LIT_VALUE (tree->right) != 0xFF)
+        expr = NULL;
+    }
+  if (!expr && resultType == RESULT_TYPE_CHAR)
+    {
+      /* 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);
+          count = tree->right;
+            expr = tree->left;
+        }
+    }
+  if (!expr || (i == 0) || (i % 8) || (i >= getSize (TTYPE (expr)) * 8))
     return tree;
       
-  /* make sure the port supports GETHBIT */
+  /* make sure the port supports GETBYTE */
   if (port->hasExtBitOp
-      && !port->hasExtBitOp(GETHBIT, getSize (TTYPE (tree->left->left))))
+      && !port->hasExtBitOp(GETBYTE, getSize (TTYPE (expr))))
     return tree;
 
-  return decorateType (newNode (GETHBIT, tree->left->left, NULL), RESULT_TYPE_NONE);
+  return decorateType (newNode (GETBYTE, expr, count), RESULT_TYPE_NONE);
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeGetWord - get two bytes of the expression               */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeGetWord (ast * tree, RESULT_TYPE resultType)
+{
+  unsigned int i = 0;
+  ast * expr;
+  ast * count = NULL;
 
+  expr = isShiftRightLitVal_BitAndLitVal(tree);
+  if (expr)
+    {
+      i = (unsigned int) AST_LIT_VALUE (tree->left->right);
+      count = tree->left->right;
+      if (AST_LIT_VALUE (tree->right) != 0xFFFF)
+        expr = NULL;
+    }      
+  if (!expr && resultType == RESULT_TYPE_INT)
+    {
+      /* 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);
+          count = tree->right;
+            expr = tree->left;
+        }
+    }
+  if (!expr || (i == 0) || (i % 8) || (i >= (getSize (TTYPE (expr))-1) * 8))
+    return tree;
+      
+  /* make sure the port supports GETWORD */
+  if (port->hasExtBitOp
+      && !port->hasExtBitOp(GETWORD, getSize (TTYPE (expr))))
+    return tree;
+
+  return decorateType (newNode (GETWORD, expr, count), RESULT_TYPE_NONE);
 }
 
 /*-----------------------------------------------------------------*/
@@ -5127,7 +5380,7 @@ optimizeSWAP (ast * root)
 }
 
 /*-----------------------------------------------------------------*/
-/* optimizeCompare - otimizes compares for bit variables     */
+/* optimizeCompare - optimizes compares for bit variables          */
 /*-----------------------------------------------------------------*/
 static ast *
 optimizeCompare (ast * root)
@@ -5828,6 +6081,27 @@ void ast_print (ast * tree, FILE *outfile, int indent)
                 fprintf(outfile,")\n");
                 ast_print(tree->left,outfile,indent+2);
                 return ;
+        case GETABIT:
+                fprintf(outfile,"GETABIT (%p) type (",tree);
+                printTypeChain(tree->ftype,outfile);
+                fprintf(outfile,")\n");
+                ast_print(tree->left,outfile,indent+2);
+                ast_print(tree->right,outfile,indent+2);
+                return ;
+        case GETBYTE:
+                fprintf(outfile,"GETBYTE (%p) type (",tree);
+                printTypeChain(tree->ftype,outfile);
+                fprintf(outfile,")\n");
+                ast_print(tree->left,outfile,indent+2);
+                ast_print(tree->right,outfile,indent+2);
+                return ;
+        case GETWORD:
+                fprintf(outfile,"GETWORD (%p) type (",tree);
+                printTypeChain(tree->ftype,outfile);
+                fprintf(outfile,")\n");
+                ast_print(tree->left,outfile,indent+2);
+                ast_print(tree->right,outfile,indent+2);
+                return ;
         case LEFT_OP:
                 fprintf(outfile,"LEFT_SHIFT (%p) type (",tree);
                 printTypeChain(tree->ftype,outfile);