* Makefile.in, configure.in, configure,
[fw/sdcc] / src / SDCCptropt.c
index 24e7ccc14c18d9e1303cb546bb56d2bec9a9c1fe..b3ff931f885b0db7c837f57b8772ddd81d631838 100644 (file)
    what you give them.   Help stamp out software-hoarding!  
 -------------------------------------------------------------------------*/
 
-#include <stdio.h>
-#include <stdlib.h>
-#include "SDCCglobl.h"
-#include "SDCCast.h"
-#include "SDCCmem.h"
-#include "SDCCy.h"
-#include "SDCChasht.h"
-#include "SDCCbitv.h"
-#include "SDCCset.h"
-#include "SDCCicode.h"
-#include "SDCClabel.h"
-#include "SDCCBBlock.h"
-#include "SDCCcflow.h"
-#include "SDCCloop.h"
-#include "SDCCcse.h"
-
-
-/*-----------------------------------------------------------------*/
-/* pointerArithOpts - does some pointer arithmetic operations      */
-/*-----------------------------------------------------------------*/
- int pointerArithOpts (iCode *ic,  hTab *ptrs)
+#include "common.h"
+
+/*-----------------------------------------------------------------------*/
+/* findPointerGetSet - find the pointer get or set for a operand         */
+/*-----------------------------------------------------------------------*/
+static iCode *
+findPointerGetSet (iCode * sic, operand * op)
 {
-    operand *asym ;
-    long  cval;
-    hashtItem *htip;
-    induction *ip ;
-    int lr = 0 ;
-
-    /* the aim here is to reduce the arithmetics performed */
-    /* during repeated pointer access . for eg. there are  */
-    /* lot of places the code generated looks like this    */
-    /*  iTempNN = &[somevar]                               */
-    /*  iTempNX = iTempNN + constant-1                     */
-    /*  *(iTempNX) := somevalue                            */
-    /*  iTempNY = iTempNN + constant-2                     */
-    /*  *(iTempNY) := somevalue                            */
-    /*          we want to change this sequence to         */
-    /*  iTempNN = &[somevar]                               */
-    /*  iTempNN = iTempNN + constant-1                     */
-    /*  (*iTempNN) := someValue                            */
-    /* WHY ? this will reduce the number of definitions    */
-    /* as well as help us in register allocation           */
-    
-    /* first check if +/- */
-    if (ic->op != '+' && ic->op != '-' )
-       return 0;
+  iCode *ic = sic;
 
-    /* if the result is not an iTemp */
-    if (!IS_ITEMP(IC_RESULT(ic)))
-       return 0;
+  for (; ic; ic = ic->next)
+    {
+      if ((POINTER_SET (ic) && isOperandEqual (op, IC_RESULT (ic))) ||
+         (POINTER_GET (ic) && isOperandEqual (op, IC_LEFT (ic))))
+       return ic;
 
-    /* if +/- then check if one of them is literal */
-    if (! IS_OP_LITERAL(IC_LEFT(ic)) &&
-       ! IS_OP_LITERAL(IC_RIGHT(ic)) )
-       return 0;
+      /* if we find any other usage or definition of op null */
+      if (IC_RESULT (ic) && isOperandEqual (IC_RESULT (ic), op))
+       return NULL;
+
+      if (IC_RIGHT (ic) && isOperandEqual (IC_RIGHT (ic), op))
+       return NULL;
+
+      if (IC_LEFT (ic) && isOperandEqual (IC_LEFT (ic), op))
+       return NULL;
 
-    /* get the operand & literal value */
-    if  (IS_OP_LITERAL(IC_LEFT(ic))) {
-           cval = operandLitValue(IC_LEFT(ic));
-           asym = IC_RIGHT(ic) ;
-    } else {
-       cval = operandLitValue(IC_RIGHT(ic)) ;
-       lr++ ;
-       asym = IC_LEFT(ic);
     }
 
-    /* if this symbol does not exist the address of */
-    /* or if the symbol is the same as the result   */
-    if (asym->key == IC_RESULT(ic)->key ||
-       (htip = hTabSearch(ptrs,asym->key)) == NULL )
-       return 0;
-    
-    ip = htip->item;
+  return NULL;
+}
 
-    
-    /* if the constant value in induction is zero */
-    /* then we just change the operand            */
-    if (ip->cval == 0) {       
-       ip->asym = IC_RESULT(ic) ;
-       ip->cval = cval ; /* update the offset info */
+static int pattern1 (iCode *sic)
+{
+       /* this is what we do. look for sequences like
+
+       iTempX := _SOME_POINTER_;
+       iTempY := _SOME_POINTER_ + nn ;   nn  = sizeof (pointed to object)      sic->next
+       _SOME_POINTER_ := iTempY;                                               sic->next->next
+       either       
+       iTempZ := @[iTempX];                                                    sic->next->next->next
+       or
+       *(iTempX) := ..something..                                              sic->next->next->next
+       if we find this then transform this to
+       iTempX := _SOME_POINTER_;
+       either       
+       iTempZ := @[iTempX];
+       or 
+       *(iTempX) := ..something..
+       iTempY := _SOME_POINTER_ + nn ;   nn  = sizeof (pointed to object)
+       _SOME_POINTER_ := iTempY; */
+       
+       /* sounds simple enough so lets start , here I use -ve
+          tests all the way to return if any test fails */
+       iCode *pgs, *sh, *st;
+
+       if (!(sic->next && sic->next->next && sic->next->next->next))
+               return 0;
+       if (sic->next->op != '+' && sic->next->op != '-')
+               return 0;
+       if (!(sic->next->next->op == '=' &&
+             !POINTER_SET (sic->next->next)))
+               return 0;
+       if (!isOperandEqual (IC_LEFT (sic->next), IC_RIGHT (sic)) ||
+           !IS_OP_LITERAL (IC_RIGHT (sic->next)))
+               return 0;
+       if (operandLitValue (IC_RIGHT (sic->next)) !=
+           getSize (operandType (IC_RIGHT (sic))->next))
+               return 0;
+       if (!isOperandEqual (IC_RESULT (sic->next->next),
+                            IC_RIGHT (sic)))
+               return 0;
+       if (!isOperandEqual (IC_RESULT (sic->next), IC_RIGHT (sic->next->next)))
+               return 0;
+       if (!(pgs = findPointerGetSet (sic->next->next, IC_RESULT (sic))))
+               return 0;
+
+       /* found the patter .. now do the transformation */
+       sh = sic->next;
+       st = sic->next->next;
+
+       /* take the two out of the chain */
+       sic->next = st->next;
+       st->next->prev = sic;
+
+       /* and put them after the pointer get/set icode */
+       if ((st->next = pgs->next))
+               st->next->prev = st;
+       pgs->next = sh;
+       sh->prev = pgs;
+       return 1;
+}
+
+static int pattern2 (iCode *sic)
+{
+       /* this is what we do. look for sequences like
+
+       iTempX := _SOME_POINTER_;
+       iTempY := _SOME_POINTER_ + nn ;   nn  = sizeof (pointed to object)      sic->next
+       iTempK := iTempY;                                                       sic->next->next
+       _SOME_POINTER_ := iTempK;                                               sic->next->next->next
+       either       
+       iTempZ := @[iTempX];                                                    sic->next->next->next->next
+       or
+       *(iTempX) := ..something..                                              sic->next->next->next->next
+       if we find this then transform this to
+       iTempX := _SOME_POINTER_;
+       either       
+       iTempZ := @[iTempX];
+       or 
+       *(iTempX) := ..something..
+       iTempY := _SOME_POINTER_ + nn ;   nn  = sizeof (pointed to object)
+       iTempK := iTempY;       
+       _SOME_POINTER_ := iTempK; */
+       
+       /* sounds simple enough so lets start , here I use -ve
+          tests all the way to return if any test fails */
+       iCode *pgs, *sh, *st;
+
+       if (!(sic->next && sic->next->next && sic->next->next->next && 
+             sic->next->next->next->next))
+               return 0;
+
+       /* yes I can OR them together and make one large if... but I have
+          simple mind and like to keep things simple & readable */
+       if (!(sic->next->op == '+' || sic->next->op == '-')) return 0;
+       if (!isOperandEqual(IC_RIGHT(sic),IC_LEFT(sic->next))) return 0;
+       if (!IS_OP_LITERAL (IC_RIGHT (sic->next))) return 0;
+       if (operandLitValue (IC_RIGHT (sic->next)) !=
+           getSize (operandType (IC_RIGHT (sic))->next)) return 0;
+       if (!IS_ASSIGN_ICODE(sic->next->next)) return 0;
+       if (!isOperandEqual(IC_RIGHT(sic->next->next),IC_RESULT(sic->next))) return 0;
+       if (!IS_ASSIGN_ICODE(sic->next->next->next)) return 0;
+       if (!isOperandEqual(IC_RIGHT(sic->next->next->next),IC_RESULT(sic->next->next))) return 0;
+       if (!isOperandEqual(IC_RESULT(sic->next->next->next),IC_LEFT(sic->next))) return 0;
+       if (!(pgs = findPointerGetSet (sic->next->next->next, IC_RESULT (sic)))) return 0;
+       
+       /* found the patter .. now do the transformation */
+       sh = sic->next;
+       st = sic->next->next->next;
+
+       /* take the three out of the chain */
+       sic->next = st->next;
+       st->next->prev = sic;
+
+       /* and put them after the pointer get/set icode */
+       if ((st->next = pgs->next))
+               st->next->prev = st;
+       pgs->next = sh;
+       sh->prev = pgs;
+       return 1;
+}
+
+/*-----------------------------------------------------------------------*/
+/* ptrPostIncDecOpts - will do some pointer post increment optimizations */
+/*                     this will help register allocation amongst others */
+/*-----------------------------------------------------------------------*/
+void 
+ptrPostIncDecOpt (iCode * sic)
+{
+       if (pattern1(sic)) return ;
+       pattern2(sic);
+}
+
+/*-----------------------------------------------------------------------*/
+/* addPattern1 - transform addition to pointer of variables              */
+/*-----------------------------------------------------------------------*/
+static int addPattern1(iCode *ic)
+{
+       iCode *dic;
+       operand *tmp;
+       /* transform :
+          iTempAA = iTempBB + iTempCC
+          iTempDD = iTempAA + CONST
+          to
+          iTempAA = iTempBB + CONST
+          iTempDD = iTempAA + iTempCC
+       */
+       if (!isOperandLiteral(IC_RIGHT(ic))) return 0;
+       if ((dic=findBackwardDef(IC_LEFT(ic),ic->prev)) == NULL) return 0;
+       if (bitVectnBitsOn(OP_SYMBOL(IC_RESULT(dic))->uses) > 1) return 0;
+       if (dic->op != '+') return 0;
+       tmp = IC_RIGHT(ic);
+       IC_RIGHT(ic) = IC_RIGHT(dic);
+       IC_RIGHT(dic) = tmp;
+       return 1;
+}
+
+/*-----------------------------------------------------------------------*/
+/* ptrAddition - optimize pointer additions                              */
+/*-----------------------------------------------------------------------*/
+int ptrAddition (iCode *sic)
+{
+       if (addPattern1(sic)) return 1;
        return 0;
+}
+
+/*--------------------------------------------------------------------*/
+/* ptrBaseRematSym - find the base symbol of a remat. pointer         */
+/*--------------------------------------------------------------------*/
+symbol *
+ptrBaseRematSym (symbol *ptrsym)
+{
+  iCode * ric;
+  
+  if (!ptrsym->remat)
+    return NULL;
+  
+  ric = ptrsym->rematiCode;
+  while (ric)
+    {
+      if (ric->op == '+' || ric->op == '-')
+       ric = OP_SYMBOL (IC_LEFT (ric))->rematiCode;
+      else if (IS_CAST_ICODE (ric))
+        ric = OP_SYMBOL (IC_RIGHT (ric))->rematiCode;
+      else
+        break;
     }
-    /* we can do the substitution */
-    replaceAllSymBySym (ic->next, IC_RESULT(ic),ip->asym);
-    IC_RESULT(ic) = operandFromOperand(ip->asym);
-    
-    /* now we know that the constant value is greater than zero */
-    /* we have to do some arithmetic here : if the offset is greater */
-    /* than what we want then rechange it to subtraction        */
-    if ( ip->cval > cval) {
-       ic->op = '-' ;
-       if (lr) {
-           IC_LEFT(ic) = operandFromOperand(ip->asym);
-           IC_RIGHT(ic) = operandFromLit(ip->cval - cval);
-       }
-       else {
-           IC_RIGHT(ic) = operandFromOperand(ip->asym);
-           IC_LEFT(ic) = operandFromLit(ip->cval - cval);
-       }
-    } else {
-       if (lr) {
-           IC_LEFT(ic) = operandFromOperand(ip->asym);
-           IC_RIGHT(ic) = operandFromLit(cval - ip->cval);
-       }
-       else {
-           IC_RIGHT(ic) = operandFromOperand (ip->asym);
-           IC_LEFT(ic) = operandFromLit(cval - ip->cval);
+  
+  if (ric && IS_SYMOP (IC_LEFT (ric)))
+    return OP_SYMBOL (IC_LEFT (ric));
+  else
+    return NULL;
+}
+
+
+/*--------------------------------------------------------------------*/
+/* ptrPseudoSymSafe - check to see if the conversion of the result of */
+/*   a pointerGet of a rematerializable pointer to a pseudo symbol is */
+/*   safe. Returns true if safe, or false if hazards were detected.   */
+/*--------------------------------------------------------------------*/
+int
+ptrPseudoSymSafe (symbol *sym, iCode *dic)
+{
+  symbol * ptrsym;
+  symbol * basesym;
+  iCode * ric;
+  iCode * ic;
+  int ptrsymDclType;
+  //int isGlobal;
+  
+  assert(POINTER_GET (dic));
+
+  /* Can't if spills to this symbol are prohibited */
+  if (sym->noSpilLoc)
+    return 0;
+  
+  /* Get the pointer */
+  if (!IS_SYMOP (IC_LEFT (dic)))
+    return 0;
+  ptrsym = OP_SYMBOL (IC_LEFT (dic));
+  
+  /* Must be a rematerializable pointer */
+  if (!ptrsym->remat)
+    return 0;
+  
+  /* The pointer type must be uncasted */
+  if (IS_CAST_ICODE (ptrsym->rematiCode))
+    return 0;
+  
+  /* The symbol's live range must not preceed its definition */
+  if (dic->seq > sym->liveFrom)
+    return 0;
+        
+  /* Ok, this is a good candidate for a pseudo symbol.      */
+  /* However, we must check for two hazards:                */
+  /*   1) The symbol's live range must not include a CALL   */
+  /*      or PCALL iCode.                                   */
+  /*   2) The symbol's live range must not include any      */
+  /*      writes to the variable the pointer rematerializes */
+  /*      within (to avoid aliasing problems)               */
+  
+  /* Find the base symbol the rematerialization is based on */
+  ric = ptrsym->rematiCode;
+  while (ric->op == '+' || ric->op == '-')
+    ric = OP_SYMBOL (IC_LEFT (ric))->rematiCode;
+  if (IS_CAST_ICODE(ric))
+    return 0;
+  basesym = OP_SYMBOL (IC_LEFT (ric));
+
+  //isGlobal = !basesym->islocal && !basesym->ismyparm;
+  ptrsymDclType = aggrToPtrDclType (ptrsym->type, FALSE);
+
+  ic = dic->next;
+  while (ic && ic->seq <= sym->liveTo)
+    {
+      if (!(SKIP_IC3 (ic) || ic->op == IFX))
+        {
+         /* Check for hazard #1 */
+         if ((ic->op == CALL || ic->op == PCALL) /* && isGlobal */ )
+           {
+             if (ic->seq <= sym->liveTo)
+               return 0;
+           }
+         /* Check for hazard #2 */
+         else if (POINTER_SET (ic))
+           {
+             symbol * ptrsym2 = OP_SYMBOL (IC_RESULT (ic));
+         
+             if (ptrsym2->remat)
+               {
+                 /* Must not be the same base symbol */
+                 if (basesym == ptrBaseRematSym (ptrsym2))
+                   return 0;
+               }
+             else
+               {
+                 int ptrsym2DclType = aggrToPtrDclType (ptrsym2->type, FALSE);
+
+                 /* Pointer must have no memory space in common */
+                 if (ptrsym2DclType == ptrsymDclType
+                     || ptrsym2DclType == GPOINTER
+                     || ptrsymDclType == GPOINTER)
+                   return 0;
+               }
+           }
+         else if (IC_RESULT (ic))
+           {
+             symbol * rsym = OP_SYMBOL (IC_RESULT (ic));
+         
+             /* Make sure there is no conflict with another pseudo symbol */
+             if (rsym->psbase == basesym)
+               return 0;
+             if (rsym->isspilt && rsym->usl.spillLoc)
+               rsym = rsym->usl.spillLoc;
+             if (rsym->psbase == basesym)
+               return 0;
+           }
        }
+       
+      if (ic->seq == sym->liveTo)
+        break;
+      ic = ic->next;
     }
+
+  /* If the live range went past the end of the defining basic */
+  /* block, then a full analysis is too complicated to attempt */
+  /* here. To be safe, we must assume the worst.               */
+  if (!ic)
+    return 0;
     
-    ip->cval = cval ;
-    return 1;
+  /* Ok, looks safe */
+  return 1;
 }
 
-/*-----------------------------------------------------------------*/
-/* ptrAopts - pointer arithmetic optimizations for a basic block   */
-/*-----------------------------------------------------------------*/
-void ptrAopts (eBBlock **ebbs, int count)
+/*--------------------------------------------------------------------*/
+/* ptrPseudoSymConvert - convert the result of a pointerGet to a      */
+/*   pseudo symbol. The pointer must be rematerializable.             */
+/*--------------------------------------------------------------------*/
+void
+ptrPseudoSymConvert (symbol *sym, iCode *dic, char *name)
 {
-    int i;
-
-    hTab *pointers ; 
-
-    /* for each basic block do */
-    for (i = 0 ; i < count ; i++ ) {
-       iCode *ic;
-
-       setToNull((void **) &pointers);
-       /* iterate thru intructions in the basic block */
-       for (ic = ebbs[i]->sch ; ic ; ic = ic->next ) {
-
-           if (SKIP_IC(ic) ||ic->op == IFX)
-               continue ;
-           
-           if (pointers)
-               pointerArithOpts(ic,pointers);
-
-           if (!POINTER_SET(ic) && IC_RESULT(ic))
-               /* delete from pointer access */
-               hTabDeleteItem (&pointers, IC_RESULT(ic)->key,NULL,DELETE_CHAIN,NULL);
-
-               /* set up for pointers */
-           if ((ic->op == ADDRESS_OF  || ADD_SUBTRACT_ITEMP(ic)) &&
-               IS_ITEMP(IC_RESULT(ic)) ) {
-               operand *sym ;
-               operand *asym ;
-               long cval    ;
-               
-               if ( ic->op == ADDRESS_OF){           
-                   sym = IC_RESULT(ic);
-                   asym = NULL ;
-                   cval = 0;
-               } else {
-                   sym = IC_LEFT(ic);
-                   asym = IC_RESULT(ic);
-                   cval = operandLitValue(IC_RIGHT(ic));
-               }
-               
-               /* put it in the pointer set */                 
-           }   
-       }
+  symbol *psym = newSymbol (name, 1);
+  psym->psbase = ptrBaseRematSym (OP_SYMBOL (IC_LEFT (dic)));
+  psym->type = sym->type;
+  psym->etype = psym->psbase->etype;
 
-    }
+  strcpy (psym->rname, psym->name);
+  sym->isspilt = 1;
+  sym->usl.spillLoc = psym;
+#if 0 // an alternative fix for bug #480076
+  /* now this is a useless assignment to itself */
+  remiCodeFromeBBlock (ebbs, dic);
+#else
+  /* now this really is an assignment to itself, make it so;
+     it will be optimized out later */
+  dic->op='=';
+  ReplaceOpWithCheaperOp(&IC_RIGHT(dic), IC_RESULT(dic));
+  IC_LEFT(dic)=NULL;
+#endif
 }