/*-----------------------------------------------------------------------*/ static iCode * findPointerGetSet (iCode * sic, operand * op) { iCode *ic = sic; 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 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; } return NULL; }
static void visit (set **visited, iCode *ic, const int key) { symbol *lbl; while (ic && !isinSet (*visited, ic) && bitVectBitValue (ic->rlive, key)) { addSet (visited, ic); switch (ic->op) { case GOTO: ic = hTabItemWithKey (labelDef, (IC_LABEL (ic))->key); break; case RETURN: ic = hTabItemWithKey (labelDef, returnLabel->key); break; case JUMPTABLE: for (lbl = setFirstItem (IC_JTLABELS (ic)); lbl; lbl = setNextItem (IC_JTLABELS (ic))) visit (visited, hTabItemWithKey (labelDef, lbl->key), key); break; case IFX: visit (visited, hTabItemWithKey (labelDef, (IC_TRUE(ic) ? IC_TRUE (ic) : IC_FALSE (ic))->key), key); ic = ic->next; break; default: ic = ic->next; if (!POINTER_SET (ic) && IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && OP_SYMBOL_CONST (IC_RESULT (ic))->key == key) { addSet (visited, ic); return; } } } }
/** 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 == '=' && !POINTER_SET (ic)) change += packRegsForAssign (ic, ebp); } if (!change) break; } }
/*-----------------------------------------------------------------*/ void replaceSymBySym (set * sset, operand * src, operand * dest) { set *loop; eBBlock *rBlock; /* for all blocks in the set do */ for (loop = sset; loop; loop = loop->next) { iCode *ic; rBlock = loop->item; /* for all instructions in this block do */ for (ic = rBlock->sch; ic; ic = ic->next) { /* if we find usage */ if (ic->op == IFX && isOperandEqual (src, IC_COND (ic))) { bitVectUnSetBit (OP_USES (IC_COND (ic)), ic->key); IC_COND (ic) = operandFromOperand (dest); OP_USES (dest) = bitVectSetBit (OP_USES (dest), ic->key); continue; } if (isOperandEqual (IC_RIGHT (ic), src)) { bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key); IC_RIGHT (ic) = operandFromOperand (dest); IC_RIGHT (ic)->isaddr = 0; OP_USES (dest) = bitVectSetBit (OP_USES (dest), ic->key); } if (isOperandEqual (IC_LEFT (ic), src)) { bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key); if (POINTER_GET (ic) && IS_ITEMP (dest)) { IC_LEFT (ic) = operandFromOperand (dest); IC_LEFT (ic)->isaddr = 1; } else { IC_LEFT (ic) = operandFromOperand (dest); IC_LEFT (ic)->isaddr = 0; } OP_USES (dest) = bitVectSetBit (OP_USES (dest), ic->key); } /* special case for pointer sets */ if (POINTER_SET (ic) && isOperandEqual (IC_RESULT (ic), src)) { bitVectUnSetBit (OP_USES (IC_RESULT (ic)), ic->key); IC_RESULT (ic) = operandFromOperand (dest); IC_RESULT (ic)->isaddr = 1; OP_USES (dest) = bitVectSetBit (OP_USES (dest), ic->key); } } } }
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 let's start , here I use negative 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 pattern .. 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; }
/*-----------------------------------------------------------------*/ iCode * usedInRemaining (operand * op, iCode * ic) { iCode *lic = ic; if (!IS_SYMOP (op)) return 0; for (; lic; lic = lic->next) { /* if the operand is a parameter */ /* then check for calls and return */ /* true if there is a call */ /* if this is a global variable then return true */ if (lic->op == CALL || lic->op == PCALL) { if ((IS_PARM (op) && isParameterToCall (IC_ARGS (lic), op)) || isOperandGlobal (op)) return lic; } if (ic->op == SEND && isOperandEqual (IC_LEFT (lic), op)) return lic; if (SKIP_IC1 (lic)) continue; /* if ifx then check the condition */ if (lic->op == IFX && isOperandEqual (IC_COND (lic), op)) return lic; if (lic->op == JUMPTABLE && isOperandEqual (IC_JTCOND (lic), op)) return lic; if (IC_RIGHT (lic) && isOperandEqual (IC_RIGHT (lic), op)) return lic; if (IC_LEFT (lic) && isOperandEqual (IC_LEFT (lic), op)) return lic; /* for a pointer assignment usage */ if (POINTER_SET (lic) && isOperandEqual (op, IC_RESULT (lic))) return lic; else if (IC_RESULT (lic) && isOperandEqual (IC_RESULT (lic), op)) return NULL; } return NULL; }
/*------------------------------------------------------------------*/ static bool findPrevUseSym (eBBlock *ebp, iCode *ic, symbol * sym) { eBBlock * pred; iCode * uic; if (ebp->visited) { /* already visited: this branch must have been succesfull, */ /* because otherwise the search would have been aborted. */ return TRUE; } ebp->visited = 1; /* search backward in the current block */ for (uic = ic; uic; uic = uic->prev) { if (!POINTER_SET (uic) && IS_AUTOSYM (IC_RESULT (uic))) { if (IC_RESULT (uic)->key == sym->key) { /* Ok, found a definition */ return TRUE; } } /* address taken from symbol? */ if (uic->op == ADDRESS_OF && IS_AUTOSYM (IC_LEFT (uic))) { if (IC_LEFT (uic)->key == sym->key) { /* Ok, found a definition */ return TRUE; } } } /* There's no definition in this bblock, */ /* let's have a look at all predecessors. */ pred = setFirstItem (ebp->predList); if (!pred) { /* no more predecessors and nothing found yet :-( */ return FALSE; } for (; pred; pred = setNextItem (ebp->predList)) { /* recurse into all predecessors */ if (!findPrevUseSym (pred, pred->ech, sym)) { /* found nothing: abort */ return FALSE; } } /* Success! Went through all branches with no abort: */ /* all branches end with a definition */ return TRUE; }
/*-----------------------------------------------------------------*/ int usedBetweenPoints (operand * op, iCode * start, iCode * end) { iCode *lic = start; for (; lic != end; lic = lic->next) { /* if the operand is a parameter */ /* then check for calls and return */ /* true if there is a call */ if (IS_PARM (op) && (lic->op == CALL || lic->op == PCALL)) if (isParameterToCall (IC_ARGS (lic), op)) return 1; if (SKIP_IC2 (lic)) continue; /* if ifx then check the condition */ if (lic->op == IFX && IC_COND (lic)->key == op->key) return 1; if (lic->op == JUMPTABLE && IC_JTCOND (lic)->key == op->key) return 1; if (IC_RIGHT (lic) && IC_RIGHT (lic)->key == op->key) return 1; if (IC_LEFT (lic) && IC_LEFT (lic)->key == op->key) return 1; /* for a pointer assignment usage */ if (POINTER_SET (lic) && op->key == IC_RESULT (lic)->key) return 1; else if (IC_RESULT (lic) && op->key == IC_RESULT (lic)->key) return 0; } return 0; }
static int implement_lospre_assignment(const assignment_lospre a, T_t &T, G_t &G, const iCode *ic) // Assignment has to be passed as a copy (not reference), since the transformations on the tree-decomposition will invalidate it otherwise. { operand *tmpop; unsigned substituted = 0, split = 0; typedef typename boost::graph_traits<G_t>::edge_iterator edge_iter_t; typedef typename boost::graph_traits<G_t>::edge_descriptor edge_desc_t; std::set<edge_desc_t> calculation_edges; // Use descriptor, not iterator due to possible invalidation of iterators when inserting vertices or edges. edge_iter_t e, e_end; for(boost::tie(e, e_end) = boost::edges(G); e != e_end; ++e) if(!((a.global[boost::source(*e, G)] & true) && !G[boost::source(*e, G)].invalidates) && (a.global[boost::target(*e, G)] & true)) calculation_edges.insert(*e); if(!calculation_edges.size()) return(0); #ifdef DEBUG_LOSPRE std::cout << "Optimizing at " << ic->key << "\n"; std::cout.flush(); #endif tmpop = newiTempOperand (operandType (IC_RESULT (ic)), TRUE); tmpop->isvolatile = false; #ifdef DEBUG_LOSPRE std::cout << "New tmpop: " << OP_SYMBOL_CONST(tmpop)->name << " "; printTypeChain(operandType (IC_RESULT(ic)), stdout); std::cout << "\n"; #endif for(typename std::set<edge_desc_t>::iterator i = calculation_edges.begin(); i != calculation_edges.end(); ++i) { split_edge(T, G, *i, ic, tmpop); split++; } typedef typename boost::graph_traits<G_t>::vertex_iterator vertex_iter_t; vertex_iter_t v, v_end; for(boost::tie(v, v_end) = boost::vertices(G); v != v_end; ++v) { if(!G[*v].uses) continue; typename boost::graph_traits<G_t>::in_edge_iterator e = in_edges(*v, G).first; if (a.global.size() <= *v) continue; if(!((a.global[*v] & true) && !G[*v].invalidates || boost::source(*e, G) < a.global.size() && (a.global[boost::source(*e, G)] & true))) continue; #ifdef DEBUG_LOSPRE std::cout << "Substituting ic " << G[*v].ic->key << "\n"; #endif substituted++; iCode *ic = G[*v].ic; //if (IC_LEFT (ic) && IS_ITEMP (IC_LEFT (ic))) // bitVectUnSetBit (OP_SYMBOL (IC_LEFT (ic))->uses, ic->key); //if (IC_RIGHT (ic) && IS_ITEMP (IC_RIGHT (ic))) // bitVectUnSetBit (OP_SYMBOL (IC_RIGHT (ic))->uses, ic->key); IC_RIGHT(ic) = tmpop; //bitVectSetBit (OP_SYMBOL (IC_RIGHT(ic))->uses, ic->key); if (!POINTER_SET (ic)) { IC_LEFT(ic) = 0; ic->op = '='; IC_RESULT(ic) = operandFromOperand (IC_RESULT (ic)); IC_RESULT(ic)->isaddr = 0; } if(IS_OP_VOLATILE(IC_RESULT (ic))) continue; { typedef typename boost::graph_traits<G_t>::adjacency_iterator adjacency_iter_t; adjacency_iter_t c, c_end; boost::tie(c, c_end) = adjacent_vertices(*v, G); if (c != c_end) forward_lospre_assignment(G, *c, ic, a); } } if(substituted <= 0) { std::cerr << "Introduced " << OP_SYMBOL_CONST(tmpop)->name << ", but did not substitute any calculations.\n"; return (-1); } if(substituted < split) // Todo: Remove this warning when optimization for speed instead of code size is implemented! std::cout << "Introduced " << OP_SYMBOL_CONST(tmpop)->name << ", but did substitute only " << substituted << " calculations, while introducing "<< split << ".\n"; std::cout.flush(); return(1); }
static void forward_lospre_assignment(G_t &G, typename boost::graph_traits<G_t>::vertex_descriptor i, const iCode *ic, const assignment_lospre& a) { typedef typename boost::graph_traits<G_t>::adjacency_iterator adjacency_iter_t; adjacency_iter_t c, c_end; operand *tmpop = IC_RIGHT(ic); const std::pair<int, int> forward(IC_RESULT(ic)->key, IC_RIGHT(ic)->key); for(;;) { if (G[i].forward == forward) break; // Was here before. iCode *nic = G[i].ic; if (isOperandEqual(IC_RESULT(ic), IC_LEFT(nic)) && nic->op != ADDRESS_OF && (!POINTER_GET(nic) || !IS_PTR(operandType(IC_RESULT(nic))) || !IS_BITFIELD(operandType(IC_LEFT(nic))->next) || compareType(operandType(IC_LEFT(nic)), operandType(tmpop)) == 1)) { bool isaddr = IC_LEFT (nic)->isaddr; #ifdef DEBUG_LOSPRE std::cout << "Forward substituted left operand " << OP_SYMBOL_CONST(IC_LEFT(nic))->name << " at " << nic->key << "\n"; #endif //bitVectUnSetBit (OP_SYMBOL (IC_LEFT (nic))->uses, nic->key); IC_LEFT(nic) = operandFromOperand (tmpop); //bitVectSetBit (OP_SYMBOL (IC_LEFT (nic))->uses, nic->key); IC_LEFT (nic)->isaddr = isaddr; } if (isOperandEqual(IC_RESULT(ic), IC_RIGHT(nic))) { #ifdef DEBUG_LOSPRE std::cout << "Forward substituted right operand " << OP_SYMBOL_CONST(IC_RIGHT(nic))->name << " at " << nic->key << "\n"; #endif //bitVectUnSetBit (OP_SYMBOL (IC_RIGHT (nic))->uses, nic->key); IC_RIGHT(nic) = operandFromOperand (tmpop); //bitVectSetBit (OP_SYMBOL (IC_RIGHT (nic))->uses, nic->key); } if (POINTER_SET(nic) && isOperandEqual(IC_RESULT(ic), IC_RESULT(nic)) && (!IS_PTR(operandType(IC_RESULT(nic))) || !IS_BITFIELD(operandType(IC_RESULT(nic))->next) || compareType(operandType(IC_RESULT(nic)), operandType(tmpop)) == 1)) { #ifdef DEBUG_LOSPRE std::cout << "Forward substituted result operand " << OP_SYMBOL_CONST(IC_RESULT(nic))->name << " at " << nic->key << "\n"; #endif //bitVectUnSetBit (OP_SYMBOL (IC_RESULT (nic))->uses, nic->key); IC_RESULT(nic) = operandFromOperand (tmpop); IC_RESULT(nic)->isaddr = true; //bitVectSetBit (OP_SYMBOL (IC_RESULT (nic))->uses, nic->key); } if (nic->op == LABEL) // Reached label. Continue only if all edges goining here are safe. { typedef typename boost::graph_traits<G_t>::in_edge_iterator in_edge_iter_t; in_edge_iter_t e, e_end; for (boost::tie(e, e_end) = boost::in_edges(i, G); e != e_end; ++e) if (G[boost::source(*e, G)].forward != forward) break; if(e != e_end) break; } if (isOperandEqual(IC_RESULT (ic), IC_RESULT(nic)) && !POINTER_SET(nic) /*|| G[i].uses*/) break; if ((nic->op == CALL || nic->op == PCALL || POINTER_SET(nic)) && IS_TRUE_SYMOP(IC_RESULT(ic))) break; G[i].forward = forward; if (nic->op == GOTO || nic->op == IFX || nic->op == JUMPTABLE) { adjacency_iter_t c, c_end; for(boost::tie(c, c_end) = boost::adjacent_vertices(i, G); c != c_end; ++c) { if(!((a.global[i] & true) && !G[i].invalidates) && (a.global[*c] & true)) // Calculation edge continue; forward_lospre_assignment(G, *c, ic, a); } break; } boost::tie(c, c_end) = adjacent_vertices(i, G); if(c == c_end) break; if(!((a.global[i] & true) && !G[i].invalidates) && (a.global[*c] & true)) // Calculation edge break; i = *c; } }
/*-----------------------------------------------------------------*/ int killDeadCode (eBBlock ** ebbs, int count) { int change = 1; int gchange = 0; int i = 0; /* basic algorithm :- */ /* first the exclusion rules :- */ /* 1. if result is a global or volatile then skip */ /* 2. if assignment and result is a temp & isaddr then skip */ /* since this means array & pointer access, will be taken */ /* care of by alias analysis. */ /* 3. if the result is used in the remainder of the block skip */ /* 4. if this definition does not reach the end of the block */ /* i.e. the result is not present in the outExprs then KILL */ /* 5. if it reaches the end of block & is used by some success */ /* or then skip */ /* else KILL */ /* this whole process is carried on iteratively till no change */ while (1) { change = 0; /* for all blocks do */ for (i = 0; i < count; i++) { iCode *ic; /* for all instructions in the block do */ for (ic = ebbs[i]->sch; ic; ic = ic->next) { int kill, j; kill = 0; if (SKIP_IC (ic) || ic->op == IFX || ic->op == RETURN) continue; /* if the result is volatile then continue */ if (IC_RESULT (ic) && isOperandVolatile (IC_RESULT (ic), FALSE)) continue; /* if the result is a temp & isaddr then skip */ if (IC_RESULT (ic) && POINTER_SET (ic)) continue; /* if the result is used in the remainder of the */ /* block then skip */ if (usedInRemaining (IC_RESULT (ic), ic->next)) continue; /* does this definition reach the end of the block or the usage is zero then we can kill */ if (!bitVectBitValue (ebbs[i]->outDefs, ic->key)) kill = 1; /* if not we can kill it */ else { /* if this is a global variable or function parameter */ /* we cannot kill anyway */ if (isOperandGlobal (IC_RESULT (ic)) || (OP_SYMBOL (IC_RESULT (ic))->_isparm && !OP_SYMBOL (IC_RESULT (ic))->ismyparm)) continue; /* if we are sure there are no usages */ if (bitVectIsZero (OP_USES (IC_RESULT (ic)))) { kill = 1; goto kill; } /* reset visited flag */ for (j = 0; j < count; ebbs[j++]->visited = 0); /* find out if this definition is alive */ if (applyToSet (ebbs[i]->succList, isDefAlive, ic)) continue; kill = 1; } kill: /* kill this one if required */ if (kill) { change = 1; gchange++; /* eliminate this */ remiCodeFromeBBlock (ebbs[i], ic); /* now delete from defUseSet */ deleteItemIf (&ebbs[i]->outExprs, ifDiCodeIsX, ic); bitVectUnSetBit (ebbs[i]->outDefs, ic->key); /* and defset of the block */ bitVectUnSetBit (ebbs[i]->defSet, ic->key); /* for the left & right remove the usage */ if (IS_SYMOP (IC_LEFT (ic))) bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key); if (IS_SYMOP (IC_RIGHT (ic))) bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key); } } /* end of all instructions */ if (!ebbs[i]->sch && !ebbs[i]->noPath) disconBBlock (ebbs[i], ebbs, count); } /* end of for all blocks */ if (!change) break; } /* end of while(1) */ return gchange; }
/*-----------------------------------------------------------------*/ static void replaceRegEqv (eBBlock ** ebbs, int count) { int i; for (i = 0; i < count; i++) { iCode *ic; for (ic = ebbs[i]->sch; ic; ic = ic->next) { if (SKIP_IC2 (ic)) continue; if (ic->op == IFX) { if (IS_TRUE_SYMOP (IC_COND (ic)) && OP_REQV (IC_COND (ic))) IC_COND (ic) = opFromOpWithDU (OP_REQV (IC_COND (ic)), OP_SYMBOL (IC_COND (ic))->defs, OP_SYMBOL (IC_COND (ic))->uses); continue; } if (ic->op == JUMPTABLE) { if (IS_TRUE_SYMOP (IC_JTCOND (ic)) && OP_REQV (IC_JTCOND (ic))) IC_JTCOND (ic) = opFromOpWithDU (OP_REQV (IC_JTCOND (ic)), OP_SYMBOL (IC_JTCOND (ic))->defs, OP_SYMBOL (IC_JTCOND (ic))->uses); continue; } if (ic->op == RECEIVE) { if (OP_SYMBOL (IC_RESULT (ic))->addrtaken) OP_SYMBOL (IC_RESULT (ic))->isspilt = 1; } /* general case */ if (IC_RESULT (ic) && IS_TRUE_SYMOP (IC_RESULT (ic)) && OP_REQV (IC_RESULT (ic))) { if (POINTER_SET (ic)) { IC_RESULT (ic) = opFromOpWithDU (OP_REQV (IC_RESULT (ic)), OP_SYMBOL (IC_RESULT (ic))->defs, OP_SYMBOL (IC_RESULT (ic))->uses); IC_RESULT (ic)->isaddr = 1; } else IC_RESULT (ic) = opFromOpWithDU (OP_REQV (IC_RESULT (ic)), OP_SYMBOL (IC_RESULT (ic))->defs, OP_SYMBOL (IC_RESULT (ic))->uses); } if (IC_RIGHT (ic) && IS_TRUE_SYMOP (IC_RIGHT (ic)) && OP_REQV (IC_RIGHT (ic))) { IC_RIGHT (ic) = opFromOpWithDU (OP_REQV (IC_RIGHT (ic)), OP_SYMBOL (IC_RIGHT (ic))->defs, OP_SYMBOL (IC_RIGHT (ic))->uses); IC_RIGHT (ic)->isaddr = 0; } if (IC_LEFT (ic) && IS_TRUE_SYMOP (IC_LEFT (ic)) && OP_REQV (IC_LEFT (ic))) { IC_LEFT (ic) = opFromOpWithDU (OP_REQV (IC_LEFT (ic)), OP_SYMBOL (IC_LEFT (ic))->defs, OP_SYMBOL (IC_LEFT (ic))->uses); IC_LEFT (ic)->isaddr = 0; } } } }
/*-----------------------------------------------------------------*/ void separateLiveRanges (iCode *sic, ebbIndex *ebbi) { iCode *ic; set *candidates = 0; symbol *sym; // printf("separateLiveRanges()\n"); for (ic = sic; ic; ic = ic->next) { if (ic->op == IFX || ic->op == GOTO || ic->op == JUMPTABLE || !IC_RESULT (ic) || !IS_ITEMP (IC_RESULT (ic)) || bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) <= 1 || isinSet (candidates, OP_SYMBOL (IC_RESULT (ic)))) continue; addSet (&candidates, OP_SYMBOL (IC_RESULT (ic))); } if (!candidates) return; for(sym = setFirstItem (candidates); sym; sym = setNextItem (candidates)) { // printf("Looking at %s, %d definitions\n", sym->name, bitVectnBitsOn (sym->defs)); int i; set *defs = 0; for (i = 0; i < sym->defs->size; i++) if (bitVectBitValue (sym->defs, i)) { iCode *dic; if(dic = hTabItemWithKey (iCodehTab, i)) addSet (&defs, hTabItemWithKey (iCodehTab, i)); else { werror (W_INTERNAL_ERROR, __FILE__, __LINE__, "Definition not found"); return; } } do { set *visited = 0; set *newdefs = 0; int oldsize; wassert (defs); wassert (setFirstItem (defs)); // printf("Looking at def at %d now\n", ((iCode *)(setFirstItem (defs)))->key); if (!bitVectBitValue (((iCode *)(setFirstItem (defs)))->rlive, sym->key)) { werror (W_INTERNAL_ERROR, __FILE__, __LINE__, "Variable is not alive at one of its definitions"); break; } visit (&visited, setFirstItem (defs), sym->key); addSet (&newdefs, setFirstItem (defs)); do { oldsize = elementsInSet(visited); ic = setFirstItem (defs); for(ic = setNextItem (defs); ic; ic = setNextItem (defs)) { // printf("Looking at other def at %d now\n", ic->key); set *visited2 = 0; set *intersection = 0; visit (&visited2, ic, sym->key); intersection = intersectSets (visited, visited2, THROW_NONE); intersection = subtractFromSet (intersection, defs, THROW_DEST); if (intersection) { visited = unionSets (visited, visited2, THROW_DEST); addSet (&newdefs, ic); } deleteSet (&intersection); deleteSet (&visited2); } } while (oldsize < elementsInSet(visited)); defs = subtractFromSet (defs, newdefs, THROW_DEST); if (newdefs && defs) { operand *tmpop = newiTempOperand (operandType (IC_RESULT ((iCode *)(setFirstItem (newdefs)))), TRUE); // printf("Splitting %s from %s, using def at %d, op %d\n", OP_SYMBOL_CONST(tmpop)->name, sym->name, ((iCode *)(setFirstItem (newdefs)))->key, ((iCode *)(setFirstItem (newdefs)))->op); for (ic = setFirstItem (visited); ic; ic = setNextItem (visited)) { if (IC_LEFT (ic) && IS_ITEMP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic)) == sym) IC_LEFT (ic) = operandFromOperand (tmpop); if (IC_RIGHT (ic) && IS_ITEMP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic)) == sym) IC_RIGHT (ic) = operandFromOperand (tmpop); if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic)) == sym && !POINTER_SET(ic) && ic->next && !isinSet (visited, ic->next)) continue; if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic)) == sym) { bool pset = POINTER_SET(ic); IC_RESULT (ic) = operandFromOperand (tmpop); if (pset) IC_RESULT(ic)->isaddr = TRUE; } bitVectUnSetBit (sym->uses, ic->key); } } deleteSet (&newdefs); deleteSet (&visited); } while (elementsInSet(defs) > 1); deleteSet (&defs); } deleteSet (&candidates); }
/*-----------------------------------------------------------------*/ static int findNextUseSym (eBBlock *ebp, iCode *ic, symbol * sym) { int retval = 0; iCode *uic; eBBlock *succ; hTabAddItemIfNotP (&liveRanges, sym->key, sym); if (!ic) goto check_successors; /* if we check a complete block and the symbol */ /* is alive at the beginning of the block */ /* and not defined in the first instructions */ /* then a next use exists (return 1) */ if ((ic == ebp->sch) && bitVectBitValue(ic->rlive, sym->key)) { /* check if the first instruction is a def of this op */ if (ic->op == JUMPTABLE || ic->op == IFX || SKIP_IC2(ic)) return 1; if (IS_ITEMP(IC_RESULT(ic))) if (IC_RESULT(ic)->key == sym->key) return 0; return 1; } if (ebp->visited) return 0; if (ic == ebp->sch) ebp->visited = 1; /* for all remaining instructions in current block */ for (uic = ic; uic; uic = uic->next) { if (SKIP_IC2(uic)) continue; if (uic->op == JUMPTABLE) { if (IS_ITEMP(IC_JTCOND(uic)) && IC_JTCOND(uic)->key == sym->key) { markAlive(ic, uic, sym->key); return 1; } continue; } if (uic->op == IFX) { if (IS_ITEMP(IC_COND(uic)) && IC_COND(uic)->key == sym->key) { markAlive(ic, uic, sym->key); return 1; } continue; } if (IS_ITEMP (IC_LEFT (uic))) if (IC_LEFT (uic)->key == sym->key) { markAlive(ic, uic, sym->key); return 1; } if (IS_ITEMP (IC_RIGHT (uic))) if (IC_RIGHT (uic)->key == sym->key) { markAlive (ic, uic, sym->key); return 1; } if (IS_ITEMP (IC_RESULT (uic))) if (IC_RESULT (uic)->key == sym->key) { if (POINTER_SET (uic)) { markAlive (ic, uic, sym->key); return 1; } else return 0; } } /* check all successors */ check_successors: succ = setFirstItem (ebp->succList); for (; succ; succ = setNextItem (ebp->succList)) { retval += findNextUseSym (succ, succ->sch, sym); } if (retval) { if (ic) markAlive (ic, ebp->ech, sym->key); return 1; } return 0; }
/** 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. stm8_call_stack_size = 2; // Saving of register to stack temporarily. /* 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 == CALL || ic->op == PCALL) && ic->parmBytes + 5 > stm8_call_stack_size) { sym_link *dtype = operandType (IC_LEFT (ic)); sym_link *ftype = IS_FUNCPTR (dtype) ? dtype->next : dtype; /* 5 for saving all registers at call site + 2 for big return value */ stm8_call_stack_size = ic->parmBytes + 5 + 2 * (getSize (ftype->next) > 4); } 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_RESULT (ic) && POINTER_SET (ic))) 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\n", sym)); 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) { D (D_ALLOC, ("serialRegAssign: won't live long enough.\n")); continue; } if (sym->nRegs > 4 && ic->op == CALL) { spillThis (sym, TRUE); } else if (max_alloc_bytes >= sym->nRegs) { sym->for_newralloc = 1; max_alloc_bytes -= sym->nRegs; } else if (!sym->for_newralloc) { spillThis (sym, TRUE); printf ("Spilt %s due to byte limit.\n", sym->name); } } } } }
/** 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) { if (POINTER_SET (dic)) dic = NULL; 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 */ /* if assignment then check that right is not a bit */ if (ASSIGNMENT (ic) && !POINTER_SET (ic)) { 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 atleast 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 */ /* 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; } /* delete from liverange table also delete from all the points inbetween 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); } 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; }
/*-----------------------------------------------------------------*/ static void rlivePoint (eBBlock ** ebbs, int count, bool emitWarnings) { int i, key; eBBlock *succ; bitVect *alive; /* for all blocks do */ for (i = 0; i < count; i++) { iCode *ic; /* for all instructions in this block do */ for (ic = ebbs[i]->sch; ic; ic = ic->next) { if (!ic->rlive) ic->rlive = newBitVect (operandKey); if (SKIP_IC2(ic)) continue; if (ic->op == JUMPTABLE && IS_SYMOP(IC_JTCOND(ic))) { incUsed (ic, IC_JTCOND(ic)); if (!IS_AUTOSYM(IC_JTCOND(ic))) continue; findPrevUse (ebbs[i], ic, IC_JTCOND(ic), ebbs, count, emitWarnings); if (IS_ITEMP(IC_JTCOND(ic))) { unvisitBlocks(ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_JTCOND(ic)->key); findNextUse (ebbs[i], ic->next, IC_JTCOND(ic)); } continue; } if (ic->op == IFX && IS_SYMOP(IC_COND(ic))) { incUsed (ic, IC_COND(ic)); if (!IS_AUTOSYM(IC_COND(ic))) continue; findPrevUse (ebbs[i], ic, IC_COND(ic), ebbs, count, emitWarnings); if (IS_ITEMP(IC_COND(ic))) { unvisitBlocks (ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_COND(ic)->key); findNextUse (ebbs[i], ic->next, IC_COND(ic)); } continue; } if (IS_SYMOP(IC_LEFT(ic))) { incUsed (ic, IC_LEFT(ic)); if (IS_AUTOSYM(IC_LEFT(ic)) && ic->op != ADDRESS_OF) { findPrevUse (ebbs[i], ic, IC_LEFT(ic), ebbs, count, emitWarnings); if (IS_ITEMP(IC_LEFT(ic))) { unvisitBlocks(ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_LEFT(ic)->key); findNextUse (ebbs[i], ic->next, IC_LEFT(ic)); /* if this is a send extend the LR to the call */ if (ic->op == SEND) { iCode *lic; for (lic = ic; lic; lic = lic->next) { if (lic->op == CALL || lic->op == PCALL) { markAlive (ic, lic->prev, IC_LEFT (ic)->key); break; } } } } } } if (IS_SYMOP(IC_RIGHT(ic))) { incUsed (ic, IC_RIGHT(ic)); if (IS_AUTOSYM(IC_RIGHT(ic))) { findPrevUse (ebbs[i], ic, IC_RIGHT(ic), ebbs, count, emitWarnings); if (IS_ITEMP(IC_RIGHT(ic))) { unvisitBlocks(ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_RIGHT(ic)->key); findNextUse (ebbs[i], ic->next, IC_RIGHT(ic)); } } } if (POINTER_SET(ic) && IS_SYMOP(IC_RESULT(ic))) incUsed (ic, IC_RESULT(ic)); if (IS_AUTOSYM(IC_RESULT(ic))) { if (POINTER_SET(ic)) { findPrevUse (ebbs[i], ic, IC_RESULT(ic), ebbs, count, emitWarnings); } if (IS_ITEMP(IC_RESULT(ic))) { unvisitBlocks(ebbs, count); ic->rlive = bitVectSetBit (ic->rlive, IC_RESULT(ic)->key); findNextUse (ebbs[i], ic->next, IC_RESULT(ic)); /* findNextUse sometimes returns 0 here, which means that ic is dead code. Something should be done about this dead code since e.g. register allocation suffers. */ } } if (!POINTER_SET(ic) && IC_RESULT(ic)) ic->defKey = IC_RESULT(ic)->key; } /* check all symbols that are alive in the last instruction */ /* but are not alive in all successors */ succ = setFirstItem (ebbs[i]->succList); if (!succ) continue; alive = succ->sch->rlive; while ((succ = setNextItem (ebbs[i]->succList))) { if (succ->sch) alive = bitVectIntersect (alive, succ->sch->rlive); } if (ebbs[i]->ech) alive = bitVectCplAnd ( bitVectCopy (ebbs[i]->ech->rlive), alive); if(!alive) continue; for (key = 1; key < alive->size; key++) { if (!bitVectBitValue (alive, key)) continue; unvisitBlocks(ebbs, count); findNextUseSym (ebbs[i], NULL, hTabItemWithKey (liveRanges, key)); } } }
/*--------------------------------------------------------------------*/ 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; /* Ok, looks safe */ return 1; }