diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/pdk/ralloc.c | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/pdk/ralloc.c')
| -rw-r--r-- | src/pdk/ralloc.c | 747 |
1 files changed, 747 insertions, 0 deletions
diff --git a/src/pdk/ralloc.c b/src/pdk/ralloc.c new file mode 100644 index 0000000..735ae5c --- /dev/null +++ b/src/pdk/ralloc.c @@ -0,0 +1,747 @@ +#include "ralloc.h" +#include "gen.h" +#include "dbuf_string.h" + +reg_info pdk_regs[] = +{ + {REG_GPR, A_IDX, "a"}, + {REG_GPR, P_IDX, "p"}, + {REG_CND, C_IDX, "f.c"}, + {0, SP_IDX, "sp"}, +}; + +/* Flags to turn on debugging code. + */ +enum +{ + D_ALLOC = 0, +}; + +#if 1 +#define D(_a, _s) if (_a) { printf _s; fflush(stdout); } +#else +#define D(_a, _s) +#endif + +/*-----------------------------------------------------------------*/ +/* createStackSpil - create a location somewhere to spill */ +/*-----------------------------------------------------------------*/ +static symbol * +createStackSpil (symbol *sym) +{ + static int slocNum; + symbol *sloc = 0; + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "sloc%d", slocNum++); + sloc = newiTemp (dbuf_c_str (&dbuf)); + dbuf_destroy (&dbuf); + + /* set the type to the spilling symbol */ + sloc->type = copyLinkChain (sym->type); + sloc->etype = getSpec (sloc->type); + SPEC_SCLS (sloc->etype) = S_DATA; + SPEC_EXTR (sloc->etype) = 0; + SPEC_STAT (sloc->etype) = 0; + SPEC_VOLATILE(sloc->etype) = 0; + SPEC_ABSA(sloc->etype) = 0; + + allocLocal (sloc); + + sloc->isref = 1; + + /* if it is on the stack then update the stack */ + if (IN_STACK (sloc->etype)) + currFunc->stack += getSize (sloc->type); + + sym->usl.spillLoc = sloc; + sym->stackSpil = 1; + + return sym; +} + +/*-----------------------------------------------------------------*/ +/* spillThis - spils a specific operand */ +/*-----------------------------------------------------------------*/ +void +pdkSpillThis (symbol * sym) +{ + int i; + /* if this is rematerializable or has a spillLocation + we are okay, else we need to create a spillLocation + for it */ + if (!(sym->remat || sym->usl.spillLoc)) + createStackSpil (sym); + + sym->isspilt = sym->spillA = 1; + + for (i = 0; i < sym->nRegs; i++) + if (sym->regs[i]) + sym->regs[i] = 0; + + if (sym->usl.spillLoc && !sym->remat) + sym->usl.spillLoc->allocreq++; + return; +} + +/*-----------------------------------------------------------------*/ +/* regTypeNum - computes the type & number of registers required */ +/*-----------------------------------------------------------------*/ +static void +regTypeNum (void) +{ + symbol *sym; + int k; + + /* for each live range do */ + for (sym = hTabFirstItem (liveRanges, &k); sym; sym = hTabNextItem (liveRanges, &k)) + { + /* if used zero times then no registers needed. Exception: Variables larger than 2 bytes - these might need a spill location when they are return values */ + if ((sym->liveTo - sym->liveFrom) == 0 && getSize (sym->type) <= 2) + continue; + + D (D_ALLOC, ("regTypeNum: loop on sym %p\n", sym)); + + /* if the live range is a temporary */ + if (sym->isitmp) + { + /* if the type is marked as a conditional */ + if (sym->regType == REG_CND) + continue; + + /* if used in return only then we don't + need registers */ + if (sym->ruonly || sym->accuse) + { + if (IS_AGGREGATE (sym->type) || sym->isptr) + sym->type = aggrToPtr (sym->type, FALSE); + continue; + } + + /* 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 %p\n", sym)); + + if (sym->nRegs > 8) + { + fprintf (stderr, "allocated more than 8 registers for type "); + printTypeChain (sym->type, stderr); + fprintf (stderr, "\n"); + } + + /* determine the type of register required */ + /* Always general purpose */ + sym->regType = REG_GPR; + } + else + { + /* for the first run we don't provide */ + /* registers for true symbols we will */ + /* see how things go */ + D (D_ALLOC, ("regTypeNum: #2 setting num of %p to 0\n", sym)); + sym->nRegs = 0; + } + } +} + +/** Transform weird SDCC handling of writes via pointers + into something more sensible. */ +static void +transformPointerSet (eBBlock **ebbs, int count) +{ + /* for all blocks */ + for (int i = 0; i < count; i++) + { + iCode *ic; + + /* for all instructions do */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) + if (POINTER_SET (ic)) + { + IC_LEFT (ic) = IC_RESULT (ic); + IC_RESULT (ic) = 0; + ic->op = SET_VALUE_AT_ADDRESS; + } + } +} + +/** Register reduction for assignment. + */ +static int +packRegsForAssign (iCode *ic, eBBlock *ebp) +{ + iCode *dic, *sic; + + if (!IS_ITEMP (IC_RIGHT (ic)) || OP_SYMBOL (IC_RIGHT (ic))->isind || OP_LIVETO (IC_RIGHT (ic)) > ic->seq) + return 0; + + /* Avoid having multiple named address spaces in one iCode. */ + if (IS_SYMOP (IC_RESULT (ic)) && SPEC_ADDRSPACE (OP_SYMBOL (IC_RESULT (ic))->etype)) + return 0; + + /* find the definition of iTempNN scanning backwards if we find a + a use of the true symbol in before we find the definition then + we cannot */ + for (dic = ic->prev; dic; dic = dic->prev) + { + /* PENDING: Don't pack across function calls. */ + if (dic->op == CALL || dic->op == PCALL) + { + dic = NULL; + break; + } + + if (SKIP_IC2 (dic)) + continue; + + if (dic->op == IFX) + { + if (IS_SYMOP (IC_COND (dic)) && + (IC_COND (dic)->key == IC_RESULT (ic)->key || IC_COND (dic)->key == IC_RIGHT (ic)->key)) + { + dic = NULL; + break; + } + } + else + { + if (IS_TRUE_SYMOP (IC_RESULT (dic)) && IS_OP_VOLATILE (IC_RESULT (dic))) + { + dic = NULL; + break; + } + + if (IS_SYMOP (IC_RESULT (dic)) && IC_RESULT (dic)->key == IC_RIGHT (ic)->key) + { + break; + } + + if (IS_SYMOP (IC_RIGHT (dic)) && + (IC_RIGHT (dic)->key == IC_RESULT (ic)->key || IC_RIGHT (dic)->key == IC_RIGHT (ic)->key)) + { + dic = NULL; + break; + } + + if (IS_SYMOP (IC_LEFT (dic)) && + (IC_LEFT (dic)->key == IC_RESULT (ic)->key || IC_LEFT (dic)->key == IC_RIGHT (ic)->key)) + { + dic = NULL; + break; + } + + if (IS_SYMOP (IC_RESULT (dic)) && IC_RESULT (dic)->key == IC_RESULT (ic)->key) + { + dic = NULL; + break; + } + } + } + + if (!dic) + return 0; /* did not find */ + + /* Avoid having a result in a sfr for shifts. */ + if (IS_SYMOP (IC_RESULT (ic)) && IN_REGSP (SPEC_OCLS (OP_SYMBOL (IC_RESULT (ic))->etype)) && (dic->op == LEFT_OP || dic->op == RIGHT_OP)) + return 0; + + /* if assignment then check that right is not a bit */ + if (ic->op == '=') + { + sym_link *etype = operandType (IC_RESULT (dic)); + if (IS_BITFIELD (etype)) + { + /* if result is a bit too then it's ok */ + etype = operandType (IC_RESULT (ic)); + if (!IS_BITFIELD (etype)) + { + return 0; + } + } + } + + /* if the result is on stack or iaccess then it must be + the same as at least one of the operands */ + if (OP_SYMBOL (IC_RESULT (ic))->onStack || OP_SYMBOL (IC_RESULT (ic))->iaccess) + { + /* the operation has only one symbol + operator then we can pack */ + if ((IC_LEFT (dic) && !IS_SYMOP (IC_LEFT (dic))) || (IC_RIGHT (dic) && !IS_SYMOP (IC_RIGHT (dic)))) + goto pack; + + if (!((IC_LEFT (dic) && + IC_RESULT (ic)->key == IC_LEFT (dic)->key) || (IC_RIGHT (dic) && IC_RESULT (ic)->key == IC_RIGHT (dic)->key))) + return 0; + } +pack: + /* found the definition */ + + /* delete from liverange table also + delete from all the points in between and the new + one */ + for (sic = dic; sic != ic; sic = sic->next) + { + bitVectUnSetBit (sic->rlive, IC_RESULT (ic)->key); + if (IS_ITEMP (IC_RESULT (dic))) + bitVectSetBit (sic->rlive, IC_RESULT (dic)->key); + } + + /* replace the result with the result of */ + /* this assignment and remove this assignment */ + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key); + IC_RESULT (dic) = IC_RESULT (ic); + + if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq) + { + OP_SYMBOL (IC_RESULT (dic))->liveFrom = dic->seq; + } + + remiCodeFromeBBlock (ebp, ic); + // PENDING: Check vs mcs51 + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (ic))->defs, ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + return 1; +} + +/** Will reduce some registers for single use. + */ +static int +packRegsForOneuse (iCode *ic, operand **opp, eBBlock *ebp) +{ + iCode *dic; + + operand *op = *opp; + + /* if returning a literal then do nothing */ + if (!IS_ITEMP (op)) + return 0; + + /* if rematerializable do nothing */ + if (OP_SYMBOL (op)->remat) + return 0; + + /* this routine will mark the symbol as used in one + instruction use only && if the definition is local + (ie. within the basic block) && has only one definition */ + if (bitVectnBitsOn (OP_USES (op)) != 1 || bitVectnBitsOn (OP_DEFS (op)) != 1) + return 0; + + /* get the definition */ + if (!(dic = hTabItemWithKey (iCodehTab, bitVectFirstBit (OP_DEFS (op))))) + return 0; + + /* found the definition now check if it is local */ + if (dic->seq < ebp->fSeq || dic->seq > ebp->lSeq) + return 0; /* non-local */ + + /* for now handle results from assignments from globals only */ + if (!(dic->op == '=' || dic->op == CAST && SPEC_USIGN (getSpec (operandType (IC_RIGHT (dic)))) && operandSize (op) > operandSize (IC_RIGHT (dic))) + || !isOperandGlobal (IC_RIGHT (dic))) + return 0; + + if (IS_OP_VOLATILE (IC_RESULT (ic)) && IS_OP_VOLATILE (IC_RIGHT (dic))) + return 0; + + /* also make sure the intervenening instructions + don't have any thing in far space */ + for (iCode *nic = dic->next; nic && nic != ic; nic = nic->next) + { + /* if there is an intervening function call then no */ + if (nic->op == CALL || nic->op == PCALL) + return 0; + + if (nic->op == SET_VALUE_AT_ADDRESS) + return 0; + + /* if address of & the result is remat, then okay */ + if (nic->op == ADDRESS_OF && OP_SYMBOL (IC_RESULT (nic))->remat) + continue; + + if (IS_OP_VOLATILE (IC_LEFT (nic)) || + IS_OP_VOLATILE (IC_RIGHT (nic)) || + isOperandGlobal (IC_RESULT (nic))) + return 0; + } + + /* Optimize out the assignment */ + *opp = operandFromOperand (IC_RIGHT(dic)); + (*opp)->isaddr = true; + + bitVectUnSetBit (OP_SYMBOL (op)->defs, dic->key); + bitVectUnSetBit (OP_SYMBOL (op)->uses, ic->key); + + if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq) + OP_SYMBOL (IC_RESULT (dic))->liveFrom = dic->seq; + + /* delete from liverange table also + delete from all the points in between and the new + one */ + for (iCode *nic = dic; nic != ic; nic = nic->next) + bitVectUnSetBit (nic->rlive, op->key); + + remiCodeFromeBBlock (ebp, dic); + + hTabDeleteItem (&iCodehTab, dic->key, ic, DELETE_ITEM, NULL); + + return 1; +} + +/** Does some transformations to reduce register pressure. + */ +static void +packRegisters (eBBlock * ebp) +{ + iCode *ic; + int change = 0; + + D (D_ALLOC, ("packRegisters: entered.\n")); + + for(;;) + { + change = 0; + /* look for assignments of the form */ + /* iTempNN = TRueSym (someoperation) SomeOperand */ + /* .... */ + /* TrueSym := iTempNN:1 */ + for (ic = ebp->sch; ic; ic = ic->next) + { + /* find assignment of the form TrueSym := iTempNN:1 */ + if (ic->op == '=') + change += packRegsForAssign (ic, ebp); + } + if (!change) + break; + } + + for (ic = ebp->sch; ic; ic = ic->next) + { + D (D_ALLOC, ("packRegisters: looping on ic %p\n", ic)); + + /* 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 */ + if (ic->op == ADDRESS_OF && + IS_ITEMP (IC_RESULT (ic)) && bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && !IS_PARM (IC_RESULT (ic)) /* The receiving of the parameter is not accounted for in DEFS */ && + IS_TRUE_SYMOP (IC_LEFT (ic)) && !OP_SYMBOL (IC_LEFT (ic))->onStack) + { + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + + /* Safe: just propagates the remat flag */ + /* if straight assignment then carry remat flag if this is the + only definition */ + if (ic->op == '=' && IS_SYMOP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->remat && + !isOperandGlobal (IC_RESULT (ic)) && bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic))->defs) == 1 && !IS_PARM (IC_RESULT (ic)) && /* The receiving of the parameter is not accounted for in DEFS */ + !OP_SYMBOL (IC_RESULT (ic))->addrtaken) + { + OP_SYMBOL (IC_RESULT (ic))->remat = OP_SYMBOL (IC_RIGHT (ic))->remat; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = OP_SYMBOL (IC_RIGHT (ic))->rematiCode; + } + + /* if cast to a pointer & the pointer being + cast is remat, then we can remat this cast as well */ + if (ic->op == CAST && + IS_SYMOP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->remat && + !isOperandGlobal (IC_RESULT (ic)) && bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && !IS_PARM (IC_RESULT (ic)) && /* The receiving of the paramter is not accounted for in DEFS */ + !OP_SYMBOL (IC_RESULT (ic))->addrtaken) + { + sym_link *to_type = operandType (IC_LEFT (ic)); + sym_link *from_type = operandType (IC_RIGHT (ic)); + if ((IS_PTR (to_type) || IS_INT (to_type)) && IS_PTR (from_type)) + { + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + } + + /* if this is a +/- operation with a rematerizable + then mark this as rematerializable as well */ + if ((ic->op == '+' || ic->op == '-') && + (IS_SYMOP (IC_LEFT (ic)) && + IS_ITEMP (IC_RESULT (ic)) && + IS_OP_LITERAL (IC_RIGHT (ic))) && + OP_SYMBOL (IC_LEFT (ic))->remat && + (!IS_SYMOP (IC_RIGHT (ic)) || !IS_CAST_ICODE (OP_SYMBOL (IC_RIGHT (ic))->rematiCode)) && + bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1) + { + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + + /* In some cases redundant moves can be eliminated */ + if (ic->op == GET_VALUE_AT_ADDRESS || ic->op == SET_VALUE_AT_ADDRESS || + ic->op == '+' || ic->op == '-' || ic->op == UNARYMINUS || + ic->op == '|' || ic->op == '&' || ic->op == '^' || + ic->op == EQ_OP || ic->op == NE_OP || + ic->op == IFX && operandSize (IC_COND (ic)) == 1 || + ic->op == IPUSH && operandSize (IC_LEFT (ic)) == 1 || + ic->op == LEFT_OP || ic->op == RIGHT_OP) + packRegsForOneuse (ic, &(IC_LEFT (ic)), ebp); + if (ic->op == '+' || ic->op == '-' || + ic->op == '|' || ic->op == '&' || ic->op == '^' || + ic->op == EQ_OP || ic->op == NE_OP || + ic->op == LEFT_OP || ic->op == RIGHT_OP) + packRegsForOneuse (ic, &(IC_RIGHT (ic)), ebp); + + // Optimize out some unsigned upcasts. + if (ic->op == CAST && IS_ITEMP (IC_RESULT (ic)) && !IS_OP_VOLATILE (IC_RIGHT (ic)) && + bitVectnBitsOn (OP_USES (IC_RESULT (ic))) == 1 && hTabItemWithKey (iCodehTab, bitVectFirstBit (OP_USES (IC_RESULT (ic)))) == ic->next && + SPEC_USIGN (getSpec (operandType (IC_RIGHT (ic)))) && operandSize (IC_RESULT (ic)) >= operandSize (IC_RIGHT (ic)) && !IS_BOOL (operandType (IC_RESULT (ic)))) + { + iCode *use = ic->next; + operand *op = IC_RESULT (ic); + if ((use->op == LEFT_OP || use->op == '+' || use->op == '-' || use->op == UNARYMINUS || + use->op == '&' || use->op == '|' || use->op == '^') && + IC_LEFT (use)->key == op->key && (!IC_RIGHT(use) || IC_RIGHT (use)->key != op->key)) + { + bitVectUnSetBit (OP_SYMBOL (IC_RIGHT (ic))->uses, ic->key); + bitVectSetBit (OP_SYMBOL (IC_RIGHT (ic))->uses, use->key); + IC_LEFT (use) = operandFromOperand (IC_RIGHT(ic)); + remiCodeFromeBBlock (ebp, ic); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + if(ic->prev) + ic = ic->prev; + } + else if (((use->op == SET_VALUE_AT_ADDRESS && !IS_BITVAR (getSpec (operandType (IC_LEFT (use)))) && !IS_BITVAR (getSpec (operandType (IC_RIGHT (use))))) || + use->op == CAST && (SPEC_USIGN (getSpec (operandType (IC_RIGHT (use)))) || operandSize (IC_RESULT (use)) <= operandSize (IC_RIGHT (use))) || + use->op == LEFT_OP || use->op == RIGHT_OP || use->op == '+' || use->op == '-' || + use->op == '&' || use->op == '|' || use->op == '^') && + IC_RIGHT (use)->key == op->key && (!IC_LEFT(use) || IC_LEFT (use)->key != op->key)) + { + bitVectUnSetBit (OP_SYMBOL (IC_RIGHT (ic))->uses, ic->key); + bitVectSetBit (OP_SYMBOL (IC_RIGHT (ic))->uses, use->key); + IC_RIGHT (use) = operandFromOperand (IC_RIGHT(ic)); + remiCodeFromeBBlock (ebp, ic); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + if(ic->prev) + ic = ic->prev; + } + } + } +} + +/** + Mark variables for assignment by the register allocator. + */ +static void +serialRegMark (eBBlock **ebbs, int count) +{ + int i; + short int max_alloc_bytes = SHRT_MAX; // Byte limit. Set this to a low value to pass only few variables to the register allocator. This can be useful for debugging. + + D (D_ALLOC, ("serialRegMark for %s, currFunc->stack %d\n", currFunc->name, currFunc->stack)); + + /* for all blocks */ + for (i = 0; i < count; i++) + { + iCode *ic; + + if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel)) + continue; + + /* for all instructions do */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) + { + if (ic->op == IPOP) + wassert (0); + + /* if result is present && is a true symbol */ + if (IC_RESULT (ic) && ic->op != IFX && IS_TRUE_SYMOP (IC_RESULT (ic))) + OP_SYMBOL (IC_RESULT (ic))->allocreq++; + + /* some don't need registers, since there is no result. */ + if (SKIP_IC2 (ic) || + ic->op == JUMPTABLE || ic->op == IFX || ic->op == IPUSH || ic->op == IPOP || ic->op == SET_VALUE_AT_ADDRESS) + continue; + + /* now we need to allocate registers only for the result */ + if (IC_RESULT (ic)) + { + symbol *sym = OP_SYMBOL (IC_RESULT (ic)); + + D (D_ALLOC, ("serialRegAssign: in loop on result %p %s\n", sym, sym->name)); + + if (sym->isspilt && sym->usl.spillLoc) // todo: Remove once remat is supported! + { + sym->usl.spillLoc->allocreq--; + sym->isspilt = FALSE; + } + + /* Make sure any spill location is definately allocated */ + if (sym->isspilt && !sym->remat && sym->usl.spillLoc && !sym->usl.spillLoc->allocreq) + sym->usl.spillLoc->allocreq++; + + /* if it does not need or is spilt + or is already marked for the new allocator + or will not live beyond this instructions */ + if (!sym->nRegs || + sym->isspilt || sym->for_newralloc || sym->liveTo <= ic->seq && (sym->nRegs <= 2 || ic->op != CALL && ic->op != PCALL)) + { + D (D_ALLOC, ("serialRegMark: won't live long enough.\n")); + continue; + } + + if (sym->usl.spillLoc && !sym->usl.spillLoc->_isparm) // I have no idea where these spill locations come from. Sometime two symbols even have the same spill location, whic tends to mess up stack allocation. THose that come from previous iterations in this loop would be okay, but those from outside are a problem. + { + sym->usl.spillLoc = 0; + sym->isspilt = false; + } + + if (sym->nRegs > 2 && ic->op == CALL) + { + sym->for_newralloc = 0; + pdkSpillThis (sym); + } + else if (max_alloc_bytes >= sym->nRegs) + { + sym->for_newralloc = 1; + max_alloc_bytes -= sym->nRegs; + } + else if (!sym->for_newralloc) + { + pdkSpillThis (sym); + printf ("Spilt %s due to byte limit.\n", sym->name); + } + } + } + } +} + +/*------------------------------------------------------------------*/ +/* verifyRegsAssigned - make sure an iTemp is properly initialized; */ +/* it should either have registers or have been spilled. Otherwise, */ +/* there was an uninitialized variable, so just spill this to get */ +/* the operand in a valid state. */ +/*------------------------------------------------------------------*/ +static void +verifyRegsAssigned (operand * op, iCode * ic) +{ + symbol *sym; + int i; + bool completely_in_regs; + + if (!op) + return; + if (!IS_ITEMP (op)) + return; + + sym = OP_SYMBOL (op); + + if (sym->regType == REG_CND) + return; + + if (sym->isspilt && !sym->remat && sym->usl.spillLoc && !sym->usl.spillLoc->allocreq) + sym->usl.spillLoc->allocreq++; + + if (sym->isspilt) + return; + + for(i = 0, completely_in_regs = true; i < sym->nRegs; i++) + if (!sym->regs[i]) + completely_in_regs = false; + if (completely_in_regs) + return; + + pdkSpillThis (sym); +} + +void +pdkRegFix (eBBlock ** ebbs, int count) +{ + int i; + + /* Check for and fix any problems with uninitialized operands */ + for (i = 0; i < count; i++) + { + iCode *ic; + + if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel)) + continue; + + for (ic = ebbs[i]->sch; ic; ic = ic->next) + { + if (SKIP_IC2 (ic)) + continue; + + if (ic->op == IFX) + { + verifyRegsAssigned (IC_COND (ic), ic); + continue; + } + + if (ic->op == JUMPTABLE) + { + verifyRegsAssigned (IC_JTCOND (ic), ic); + continue; + } + + verifyRegsAssigned (IC_RESULT (ic), ic); + verifyRegsAssigned (IC_LEFT (ic), ic); + verifyRegsAssigned (IC_RIGHT (ic), ic); + } + } +} + +/*-----------------------------------------------------------------*/ +/* assignRegisters - assigns registers to each live range as need */ +/*-----------------------------------------------------------------*/ +void +pdk_assignRegisters (ebbIndex *ebbi) +{ + eBBlock **ebbs = ebbi->bbOrder; + int count = ebbi->count; + iCode *ic; + + pdk_init_asmops(); + + transformPointerSet (ebbs, count); + + /* change assignments this will remove some + live ranges reducing some register pressure */ + for (int i = 0; i < count; i++) + packRegisters (ebbs[i]); + + /* liveranges probably changed by register packing + so we compute them again */ + recomputeLiveRanges (ebbs, count, FALSE); + + if (options.dump_i_code) + dumpEbbsToFileExt (DUMP_PACK, ebbi); + + /* first determine for each live range the number of + registers & the type of registers required for each */ + regTypeNum (); + + /* Mark variables for assignment by the new allocator */ + serialRegMark (ebbs, count); + + /* Invoke optimal register allocator */ + ic = pdk_ralloc2_cc (ebbi); + + /* redo offsets for stacked automatic variables */ + if (currFunc) + { + redoStackOffsets (); + } + + if (options.dump_i_code) + { + dumpEbbsToFileExt (DUMP_RASSGN, ebbi); + dumpLiveRanges (DUMP_LRANGE, liveRanges); + } + + genPdkCode (ic); +} + |
