Yet another reg alloc bug uncovered by ds390
[fw/sdcc] / src / z80 / ralloc.c
index 93f4e37b068130e82a0db9d8b821813d7d77a205..fc224eb42d34f840931c8bfaa93b3e8e1b256523 100644 (file)
@@ -7,8 +7,9 @@
     hardware.  It allocates based on usage and how long the varible
     lives into registers or temporary memory on the stack.
 
-    On the Z80 hl, ix, iy, and a are reserved for the code generator,
-    leaving bc and de for allocation.  The extra register pressure
+    On the Z80 hl and ix and a are reserved for the code generator,
+    leaving bc and de for allocation.  iy is unusable due to currently
+    as it's only adressable as a pair.  The extra register pressure
     from reserving hl is made up for by how much easier the sub
     operations become.  You could swap hl for iy if the undocumented
     iyl/iyh instructions are available.
 enum {
     DISABLE_PACK_ACC   = 0,
     DISABLE_PACK_ASSIGN        = 0,
-    LIMITED_PACK_ACC   = 1
+    DISABLE_PACK_ONE_USE = 0,
+    DISABLE_PACK_HL    = 0,
+    LIMITED_PACK_ACC   = 1,
 };
 
-#define D_ALLOC                1
+enum {
+    D_ALLOC            = 0,
+    D_ALLOC2           = 0
+};
 
-#if 0
+#if 1
 #define D(_a, _s)      if (_a)  { printf _s; fflush(stdout); }
 #else
 #define D(_a, _s)
@@ -132,7 +138,7 @@ static regs *allocReg (short type)
            if (currFunc)
                currFunc->regsUsed = 
                    bitVectSetBit(currFunc->regsUsed,i);
-           D(D_ALLOC, ("allocReg: alloced %zr\n", &regsZ80[i]));
+           D(D_ALLOC, ("allocReg: alloced %p\n", &regsZ80[i]));
            return &regsZ80[i];
        }
     }
@@ -161,7 +167,7 @@ static void freeReg (regs *reg)
 {
     wassert(!reg->isFree);
     reg->isFree = 1;
-    D(D_ALLOC, ("freeReg: freed %zr\n", reg));
+    D(D_ALLOC, ("freeReg: freed %p\n", reg));
 }
 
 
@@ -393,7 +399,7 @@ symbol *createStackSpil (symbol *sym)
 {
     symbol *sloc= NULL;
 
-    D(D_ALLOC, ("createStackSpil: for sym %zs\n", sym));
+    D(D_ALLOC, ("createStackSpil: for sym %p\n", sym));
 
     /* first go try and find a free one that is already 
        existing on the stack */
@@ -483,7 +489,7 @@ static void spillThis (symbol *sym)
 {
     int i;
 
-    D(D_ALLOC, ("spillThis: spilling %zs\n", sym));
+    D(D_ALLOC, ("spillThis: spilling %p\n", sym));
 
     /* if this is rematerializable or has a spillLocation
        we are okay, else we need to create a spillLocation
@@ -520,7 +526,7 @@ symbol *selectSpil (iCode *ic, eBBlock *ebp, symbol *forSym)
     set *selectS ;
     symbol *sym;
 
-    D(D_ALLOC, ("selectSpil: finding spill for ic %zi\n", ic));
+    D(D_ALLOC, ("selectSpil: finding spill for ic %p\n", ic));
     /* get the spillable live ranges */
     lrcs = computeSpillable (ic);
 
@@ -563,11 +569,13 @@ symbol *selectSpil (iCode *ic, eBBlock *ebp, symbol *forSym)
           used in the remainder of the block */
        if (!blockSpil && (selectS = liveRangesWith(lrcs,notUsedInRemaining,ebp,ic))) {
            sym = leastUsedLR (selectS);
-           if (!sym->remat) {
-               sym->remainSpil = 1;
-               blockSpil++;
+           if (sym != ForSym) {
+               if (!sym->remat) {
+                   sym->remainSpil = 1;
+                   blockSpil++;
+               }
+               return sym;
            }
-           return sym;
        }
     }
     /* find live ranges with spillocation && not used as pointers */
@@ -615,7 +623,7 @@ bool spilSomething (iCode *ic, eBBlock *ebp, symbol *forSym)
     symbol *ssym;
     int i ;
 
-    D(D_ALLOC, ("spilSomething: spilling on ic %zi\n", ic));
+    D(D_ALLOC, ("spilSomething: spilling on ic %p\n", ic));
 
     /* get something we can spil */
     ssym = selectSpil(ic,ebp,forSym);
@@ -681,7 +689,7 @@ regs *getRegGpr (iCode *ic, eBBlock *ebp,symbol *sym)
 {
     regs *reg;
 
-    D(D_ALLOC, ("getRegGpr: on ic %zi\n"));
+    D(D_ALLOC, ("getRegGpr: on ic %p\n", ic));
  tryAgain:
     /* try for gpr type */
     if ((reg = allocReg(REG_GPR))) {
@@ -753,7 +761,7 @@ static void deassignLRs (iCode *ic, eBBlock *ebp)
            !OP_SYMBOL(IC_LEFT(ic->prev))->isspilt) 
            psym = OP_SYMBOL(IC_LEFT(ic->prev));
 
-       D(D_ALLOC, ("deassignLRs: in loop on sym %zs", sym));
+       D(D_ALLOC, ("deassignLRs: in loop on sym %p nregs %u\n", sym, sym->nRegs));
 
        if (sym->nRegs) {
            int i = 0;
@@ -783,7 +791,7 @@ static void deassignLRs (iCode *ic, eBBlock *ebp)
                ((nfreeRegsType(result->regType) +
                  sym->nRegs) >= result->nRegs)
                ) {
-               for (i = 0 ; i < max(sym->nRegs,result->nRegs) ; i++) {
+               for (i = 0 ; i < result->nRegs ; i++) {
                    if (i < sym->nRegs )
                        result->regs[i] = sym->regs[i] ;
                    else
@@ -822,7 +830,7 @@ static void reassignLR (operand *op)
     symbol *sym = OP_SYMBOL(op);
     int i;
 
-    D(D_ALLOC, ("reassingLR: on sym %zs\n", sym));
+    D(D_ALLOC, ("reassingLR: on sym %p\n", sym));
 
     /* not spilt any more */     
     sym->isspilt = sym->blockSpil  = sym->remainSpil = 0;
@@ -858,7 +866,7 @@ static void positionRegs (symbol *result, symbol *opsym, int lineno)
     int count = min(result->nRegs,opsym->nRegs);
     int i , j = 0, shared = 0;
 
-    D(D_ALLOC, ("positionRegs: on result %zs opsum %zs line %u\n", result, opsym, lineno));
+    D(D_ALLOC, ("positionRegs: on result %p opsum %p line %u\n", result, opsym, lineno));
 
     /* if the result has been spilt then cannot share */
     if (opsym->isspilt)
@@ -901,11 +909,11 @@ bool tryAllocatingRegPair(symbol *sym)
                currFunc->regsUsed = 
                    bitVectSetBit(currFunc->regsUsed,i+1);
            }
-           D(D_ALLOC, ("tryAllocRegPair: succeded for sym %zs\n", sym));
+           D(D_ALLOC, ("tryAllocRegPair: succeded for sym %p\n", sym));
            return TRUE;
        }
     }
-    D(D_ALLOC, ("tryAllocRegPair: failed on sym %zs\n", sym));
+    D(D_ALLOC, ("tryAllocRegPair: failed on sym %p\n", sym));
     return FALSE;
 }
 
@@ -962,7 +970,7 @@ static void serialRegAssign (eBBlock **ebbs, int count)
                int willCS ;
                int j;
 
-               D(D_ALLOC, ("serialRegAssign: in loop on result %zs\n", sym));
+               D(D_ALLOC, ("serialRegAssign: in loop on result %p\n", sym));
 
                /* if it does not need or is spilt 
                   or is already assigned to registers
@@ -1029,6 +1037,7 @@ static void serialRegAssign (eBBlock **ebbs, int count)
                        /* if the allocation falied which means
                           this was spilt then break */
                        if (!sym->regs[j]) {
+                           D(D_ALLOC, ("Couldnt alloc (spill)\n"))
                            break;
                        }
                    }
@@ -1041,7 +1050,7 @@ static void serialRegAssign (eBBlock **ebbs, int count)
                                     OP_SYMBOL(IC_LEFT(ic)),ic->lineno);
                /* do the same for the right operand */
                if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic)) &&
-                   OP_SYMBOL(IC_RIGHT(ic))->nRegs && ic->op != '=')
+                   OP_SYMBOL(IC_RIGHT(ic))->nRegs)
                        positionRegs(OP_SYMBOL(IC_RESULT(ic)),
                                     OP_SYMBOL(IC_RIGHT(ic)),ic->lineno);
                
@@ -1222,7 +1231,7 @@ static void regTypeNum (void)
        if ((sym->liveTo - sym->liveFrom) == 0)
            continue ;
 
-       D(D_ALLOC, ("regTypeNum: loop on sym %zs\n", sym));
+       D(D_ALLOC, ("regTypeNum: loop on sym %p\n", sym));
        
        /* if the live range is a temporary */
        if (sym->isitmp) {
@@ -1240,11 +1249,13 @@ static void regTypeNum (void)
            }
 
            /* if not then we require registers */
+           D(D_ALLOC, ("regTypeNum: isagg %u nRegs %u type %p\n", IS_AGGREGATE(sym->type) || sym->isptr, sym->nRegs, sym->type));
            sym->nRegs = ((IS_AGGREGATE(sym->type) || sym->isptr ) ?
                          getSize(sym->type = aggrToPtr(sym->type,FALSE)) :
                          getSize(sym->type));
+           D(D_ALLOC, ("regTypeNum: setting nRegs of %s (%p) to %u\n", sym->name, sym, sym->nRegs));
 
-           D(D_ALLOC, ("regTypeNum: setup to assign regs sym %zs\n", sym));
+           D(D_ALLOC, ("regTypeNum: setup to assign regs sym %p\n", sym));
 
            if (sym->nRegs > 4) {
                fprintf(stderr,"allocated more than 4 or 0 registers for type ");
@@ -1255,11 +1266,13 @@ static void regTypeNum (void)
            /* Always general purpose */
            sym->regType = REG_GPR ;
            
-       } else 
+       } else {
            /* for the first run we don't provide */
            /* registers for true symbols we will */
            /* see how things go                  */
-           sym->nRegs = 0 ;    
+           D(D_ALLOC, ("regTypeNum: #2 setting num of %p to 0\n", sym)); 
+           sym->nRegs = 0;
+       }
     }
     
 }
@@ -1293,7 +1306,7 @@ static int packRegsForAssign (iCode *ic,eBBlock *ebp)
 {
     iCode *dic, *sic;
 
-    D(D_ALLOC, ("packRegsForAssing: running on ic %zi\n", ic));
+    D(D_ALLOC, ("packRegsForAssing: running on ic %p\n", ic));
     
     if (
        /*      !IS_TRUE_SYMOP(IC_RESULT(ic)) ||*/
@@ -1396,7 +1409,6 @@ pack:
         
     remiCodeFromeBBlock(ebp,ic);
     return 1;
-    
 }
 
 /** Scanning backwards looks for first assig found.
@@ -1479,7 +1491,7 @@ static int packRegsForSupport (iCode *ic, eBBlock *ebp)
     /* for the left & right operand :- look to see if the
        left was assigned a true symbol in far space in that
        case replace them */
-    D(D_ALLOC, ("packRegsForSupport: running on ic %zi\n", ic));
+    D(D_ALLOC, ("packRegsForSupport: running on ic %p\n", ic));
 
     if (IS_ITEMP(IC_LEFT(ic)) && 
        OP_SYMBOL(IC_LEFT(ic))->liveTo <= ic->seq) {
@@ -1536,7 +1548,7 @@ static iCode *packRegsForOneuse (iCode *ic, operand *op , eBBlock *ebp)
     bitVect *uses ;
     iCode *dic, *sic;
 
-    D(D_ALLOC, ("packRegsForOneUse: running on ic %zi\n", ic));
+    D(D_ALLOC, ("packRegsForOneUse: running on ic %p\n", ic));
 
     /* if returning a literal then do nothing */
     if (!IS_SYMOP(op))
@@ -1782,7 +1794,7 @@ static void packRegsForAccUse (iCode *ic)
     /* if one of them is a literal then we can */
     if ((IC_LEFT(uic) && IS_OP_LITERAL(IC_LEFT(uic))) ||
        (IC_RIGHT(uic) && IS_OP_LITERAL(IC_RIGHT(uic)))) {
-       OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+       goto accuse;
        return ;
     }
 
@@ -1798,7 +1810,39 @@ static void packRegsForAccUse (iCode *ic)
        goto accuse ;
     return ;
  accuse:
-    OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+    OP_SYMBOL(IC_RESULT(ic))->accuse = ACCUSE_A;
+}
+
+static void packRegsForHLUse (iCode *ic)
+{
+    iCode *uic;
+
+    if (IS_GB)
+       return;
+
+    /* has only one definition */
+    if (bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) > 1)
+       return ;
+
+    /* has only one use */
+    if (bitVectnBitsOn(OP_USES(IC_RESULT(ic))) > 1)
+       return ;
+
+    /* and the usage immediately follows this iCode */
+    if (!(uic = hTabItemWithKey(iCodehTab,
+                               bitVectFirstBit(OP_USES(IC_RESULT(ic))))))
+       return ;
+
+    if (ic->next != uic)
+       return ;
+
+    if (ic->op == ADDRESS_OF && uic->op == IPUSH)
+       goto hluse;
+    if (ic->op == CALL && IC_LEFT(ic)->parmBytes == 0 && (uic->op == '-' || uic->op == '+'))
+       goto hluse;
+    return;
+ hluse:
+    OP_SYMBOL(IC_RESULT(ic))->accuse = ACCUSE_HL;
 }
 
 bool opPreservesA(iCode *ic, iCode *uic)
@@ -1857,9 +1901,39 @@ bool opPreservesA(iCode *ic, iCode *uic)
     return FALSE;
 }
 
+static void joinPushes(iCode *ic)
+{
+#if 0
+    if (ic->op == IPUSH &&
+       isOperandLiteral(IC_LEFT(ic)) &&
+       getSize(operandType(IC_LEFT(ic))) == 1 &&
+       ic->next->op == IPUSH &&
+       isOperandLiteral(IC_LEFT(ic->next)) &&
+       getSize(operandType(IC_LEFT(ic->next))) == 1) {
+       /* This is a bit tricky as michaelh doesnt know what he's doing.
+        */
+       /* First upgrade the size of (first) to int */
+       SPEC_NOUN(operandType(IC_LEFT(ic))) = V_INT;
+       SPEC_SHORT(operandType(IC_LEFT(ic))) = 0;
+
+       floatFromVal(AOP
+       /* Now get and join the values */
+       value * val = aop->aopu.aop_lit;
+       /* if it is a float then it gets tricky */
+       /* otherwise it is fairly simple */
+       if (!IS_FLOAT(val->type)) {
+           unsigned long v = floatFromVal(val);
+
+       floatFrom
+       printf("Size %u\n", getSize(operandType(IC_LEFT(ic))));
+       ic->next = ic->next->next;
+    }
+#endif
+}
+
 /** Pack registers for acc use.
     When the result of this operation is small and short lived it may
-    be able to be stored in the accumelator.
+    be able to be stored in the accumulator.
 
     Note that the 'A preserving' list is currently emperical :)e
  */
@@ -1867,7 +1941,7 @@ static void packRegsForAccUse2(iCode *ic)
 {
     iCode *uic;
 
-    D(D_ALLOC, ("packRegsForAccUse2: running on ic %zi\n", ic));
+    D(D_ALLOC, ("packRegsForAccUse2: running on ic %p\n", ic));
 
     /* Filter out all but those 'good' commands */
     if (
@@ -1942,7 +2016,7 @@ static void packRegsForAccUse2(iCode *ic)
                return;
            }
        } while (!bitVectIsZero(uses));
-       OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+       OP_SYMBOL(IC_RESULT(ic))->accuse = ACCUSE_A;
        return;
     }
 
@@ -2028,7 +2102,7 @@ static void packRegsForAccUse2(iCode *ic)
     /* if one of them is a literal then we can */
     if ((IC_LEFT(uic) && IS_OP_LITERAL(IC_LEFT(uic))) ||
        (IC_RIGHT(uic) && IS_OP_LITERAL(IC_RIGHT(uic)))) {
-       OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+       goto accuse;
        return ;
     }
 
@@ -2045,7 +2119,7 @@ static void packRegsForAccUse2(iCode *ic)
     return ;
  accuse:
     printf("acc ok!\n");
-    OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+    OP_SYMBOL(IC_RESULT(ic))->accuse = ACCUSE_A;
 }
 
 /** Does some transformations to reduce register pressure.
@@ -2076,8 +2150,7 @@ static void packRegisters (eBBlock *ebp)
        /* Safe: address of a true sym is always constant. */
        /* if this is an itemp & result of a address of a true sym 
           then mark this as rematerialisable   */
-
-       D(D_ALLOC, ("packRegisters: looping on ic %zi\n", ic));
+       D(D_ALLOC, ("packRegisters: looping on ic %p\n", ic));
     
        if (ic->op == ADDRESS_OF && 
            IS_ITEMP(IC_RESULT(ic)) &&
@@ -2141,24 +2214,32 @@ static void packRegisters (eBBlock *ebp)
               !isOperandInFarSpace(IC_RIGHT(ic)) && */
            !OP_SYMBOL(IC_RESULT(ic))->remat   &&
            !IS_OP_RUONLY(IC_RIGHT(ic))        &&
-           getSize(aggrToPtr(operandType(IC_RESULT(ic)),FALSE)) > 1 )
+           getSize(aggrToPtr(operandType(IC_RESULT(ic)),FALSE)) > 1 ) {
            
            packRegsForOneuse (ic,IC_RESULT(ic),ebp);
+       }
        
        /* if pointer get */
-       if (POINTER_GET(ic)                    &&
+       if (!DISABLE_PACK_ONE_USE &&
+           POINTER_GET(ic)                    &&
            /* MLH: dont have far space
               !isOperandInFarSpace(IC_RESULT(ic))&& */
            !OP_SYMBOL(IC_LEFT(ic))->remat     &&
            !IS_OP_RUONLY(IC_RESULT(ic))         &&
-           getSize(aggrToPtr(operandType(IC_LEFT(ic)),FALSE)) > 1 )
+           getSize(aggrToPtr(operandType(IC_LEFT(ic)),FALSE)) > 1 ) {
+
            packRegsForOneuse (ic,IC_LEFT(ic),ebp);
+       }
        /* pack registers for accumulator use, when the result of an
           arithmetic or bit wise operation has only one use, that use is
           immediately following the defintion and the using iCode has
           only one operand or has two operands but one is literal & the
           result of that operation is not on stack then we can leave the
           result of this operation in acc:b combination */
+
+       if (!DISABLE_PACK_HL && IS_ITEMP(IC_RESULT(ic))) {
+           packRegsForHLUse(ic);
+       }
 #if 0
        if ((IS_ARITHMETIC_OP(ic) 
             || IS_BITWISE_OP(ic)
@@ -2169,9 +2250,11 @@ static void packRegisters (eBBlock *ebp)
            packRegsForAccUse (ic);
 #else
        if (!DISABLE_PACK_ACC && IS_ITEMP(IC_RESULT(ic)) &&
-           getSize(operandType(IC_RESULT(ic))) == 1)
+           getSize(operandType(IC_RESULT(ic))) == 1) {
            packRegsForAccUse2(ic);
+       }
 #endif
+       joinPushes(ic);
     }
 }