// Find the first Assignment with loc on the LHS Assignment * StatementList::findOnLeft(Exp *loc) const { for (const auto &s : slist) { auto as = (Assignment *)s; Exp *left = as->getLeft(); if (*left == *loc) return as; if (left->isLocal()) { auto l = (Location *)left; Exp *e = l->getProc()->expFromSymbol(((Const *)l->getSubExp1())->getStr()); if (e && ((*e == *loc) || (e->isSubscript() && *e->getSubExp1() == *loc))) { return as; } } } return nullptr; }
// Find the first Assignment with loc on the LHS Assignment* StatementList::findOnLeft(Exp* loc) { if (slist.size() == 0) return NULL; for (iterator it = slist.begin(); it != slist.end(); it++) { Exp *left = ((Assignment*)*it)->getLeft(); if (*left == *loc) return (Assignment*)*it; if (left->isLocal()) { Location *l = (Location*)left; Exp *e = l->getProc()->expFromSymbol(((Const*)l->getSubExp1())->getStr()); if (e && ((*e == *loc) || (e->isSubscript() && *e->getSubExp1() == *loc))) { return (Assignment*)*it; } } } return NULL; }
bool DataFlow::renameBlockVars(UserProc* proc, int n, bool clearStacks /* = false */ ) { if (++progress > 200) { std::cerr << 'r' << std::flush; progress = 0; } bool changed = false; // Need to clear the Stacks of old, renamed locations like m[esp-4] (these will be deleted, and will cause compare // failures in the Stacks, so it can't be correctly ordered and hence balanced etc, and will lead to segfaults) if (clearStacks) Stacks.clear(); // For each statement S in block n BasicBlock::rtlit rit; StatementList::iterator sit; PBB bb = BBs[n]; Statement* S; for (S = bb->getFirstStmt(rit, sit); S; S = bb->getNextStmt(rit, sit)) { // if S is not a phi function (per Appel) /* if (!S->isPhi()) */ { // For each use of some variable x in S (not just assignments) LocationSet locs; if (S->isPhi()) { PhiAssign* pa = (PhiAssign*)S; Exp* phiLeft = pa->getLeft(); if (phiLeft->isMemOf() || phiLeft->isRegOf()) phiLeft->getSubExp1()->addUsedLocs(locs); // A phi statement may use a location defined in a childless call, in which case its use collector // needs updating PhiAssign::iterator pp; for (pp = pa->begin(); pp != pa->end(); ++pp) { Statement* def = pp->def; if (def && def->isCall()) ((CallStatement*)def)->useBeforeDefine(phiLeft->clone()); } } else { // Not a phi assignment S->addUsedLocs(locs); } LocationSet::iterator xx; for (xx = locs.begin(); xx != locs.end(); xx++) { Exp* x = *xx; // Don't rename memOfs that are not renamable according to the current policy if (!canRename(x, proc)) continue; Statement* def = NULL; if (x->isSubscript()) { // Already subscripted? // No renaming required, but redo the usage analysis, in case this is a new return, and also because // we may have just removed all call livenesses // Update use information in calls, and in the proc (for parameters) Exp* base = ((RefExp*)x)->getSubExp1(); def = ((RefExp*)x)->getDef(); if (def && def->isCall()) { // Calls have UseCollectors for locations that are used before definition at the call ((CallStatement*)def)->useBeforeDefine(base->clone()); continue; } // Update use collector in the proc (for parameters) if (def == NULL) proc->useBeforeDefine(base->clone()); continue; // Don't re-rename the renamed variable } // Else x is not subscripted yet if (STACKS_EMPTY(x)) { if (!Stacks[defineAll].empty()) def = Stacks[defineAll].top(); else { // If the both stacks are empty, use a NULL definition. This will be changed into a pointer // to an implicit definition at the start of type analysis, but not until all the m[...] // have stopped changing their expressions (complicates implicit assignments considerably). def = NULL; // Update the collector at the start of the UserProc proc->useBeforeDefine(x->clone()); } } else def = Stacks[x].top(); if (def && def->isCall()) // Calls have UseCollectors for locations that are used before definition at the call ((CallStatement*)def)->useBeforeDefine(x->clone()); // Replace the use of x with x{def} in S changed = true; if (S->isPhi()) { Exp* phiLeft = ((PhiAssign*)S)->getLeft(); phiLeft->setSubExp1(phiLeft->getSubExp1()->expSubscriptVar(x, def /*, this*/)); } else { S->subscriptVar(x, def /*, this */); } } } // MVE: Check for Call and Return Statements; these have DefCollector objects that need to be updated // Do before the below, so CallStatements have not yet processed their defines if (S->isCall() || S->isReturn()) { DefCollector* col; if (S->isCall()) col = ((CallStatement*)S)->getDefCollector(); else col = ((ReturnStatement*)S)->getCollector(); col->updateDefs(Stacks, proc); } // For each definition of some variable a in S LocationSet defs; S->getDefinitions(defs); LocationSet::iterator dd; for (dd = defs.begin(); dd != defs.end(); dd++) { Exp* a = *dd; // Don't consider a if it cannot be renamed bool suitable = canRename(a, proc); if (suitable) { // Push i onto Stacks[a] // Note: we clone a because otherwise it could be an expression that gets deleted through various // modifications. This is necessary because we do several passes of this algorithm to sort out the // memory expressions Stacks[a->clone()].push(S); // Replace definition of a with definition of a_i in S (we don't do this) } // FIXME: MVE: do we need this awful hack? if (a->getOper() == opLocal) { Exp *a1 = S->getProc()->expFromSymbol(((Const*)a->getSubExp1())->getStr()); assert(a1); a = a1; // Stacks already has a definition for a (as just the bare local) if (suitable) { Stacks[a->clone()].push(S); } } } // Special processing for define-alls (presently, only childless calls). // But note that only everythings at the current memory level are defined! if (S->isCall() && ((CallStatement*)S)->isChildless() && !Boomerang::get()->assumeABI) { // S is a childless call (and we're not assuming ABI compliance) Stacks[defineAll]; // Ensure that there is an entry for defineAll std::map<Exp*, std::stack<Statement*>, lessExpStar>::iterator dd; for (dd = Stacks.begin(); dd != Stacks.end(); ++dd) { // if (dd->first->isMemDepth(memDepth)) dd->second.push(S); // Add a definition for all vars } } } // For each successor Y of block n std::vector<PBB>& outEdges = bb->getOutEdges(); unsigned numSucc = outEdges.size(); for (unsigned succ = 0; succ < numSucc; succ++) { PBB Ybb = outEdges[succ]; // Suppose n is the jth predecessor of Y int j = Ybb->whichPred(bb); // For each phi-function in Y Statement* S; for (S = Ybb->getFirstStmt(rit, sit); S; S = Ybb->getNextStmt(rit, sit)) { PhiAssign* pa = dynamic_cast<PhiAssign*>(S); // if S is not a phi function, then quit the loop (no more phi's) // Wrong: do not quit the loop: there's an optimisation that turns a PhiAssign into an ordinary Assign. // So continue, not break. if (!pa) continue; // Suppose the jth operand of the phi is a // For now, just get the LHS Exp* a = pa->getLeft(); // Only consider variables that can be renamed if (!canRename(a, proc)) continue; Statement* def; if (STACKS_EMPTY(a)) def = NULL; // No reaching definition else def = Stacks[a].top(); // "Replace jth operand with a_i" pa->putAt(j, def, a); } } // For each child X of n // Note: linear search! unsigned numBB = proc->getCFG()->getNumBBs(); for (unsigned X=0; X < numBB; X++) { if (idom[X] == n) renameBlockVars(proc, X); } // For each statement S in block n // NOTE: Because of the need to pop childless calls from the Stacks, it is important in my algorithm to process the // statments in the BB *backwards*. (It is not important in Appel's algorithm, since he always pushes a definition // for every variable defined on the Stacks). BasicBlock::rtlrit rrit; StatementList::reverse_iterator srit; for (S = bb->getLastStmt(rrit, srit); S; S = bb->getPrevStmt(rrit, srit)) { // For each definition of some variable a in S LocationSet defs; S->getDefinitions(defs); LocationSet::iterator dd; for (dd = defs.begin(); dd != defs.end(); dd++) { if (canRename(*dd, proc)) { // if ((*dd)->getMemDepth() == memDepth) std::map<Exp*, std::stack<Statement*>, lessExpStar>::iterator ss = Stacks.find(*dd); if (ss == Stacks.end()) { std::cerr << "Tried to pop " << *dd << " from Stacks; does not exist\n"; assert(0); } ss->second.pop(); } } // Pop all defs due to childless calls if (S->isCall() && ((CallStatement*)S)->isChildless()) { std::map<Exp*, std::stack<Statement*>, lessExpStar>::iterator sss; for (sss = Stacks.begin(); sss != Stacks.end(); ++sss) { if (!sss->second.empty() && sss->second.top() == S) { sss->second.pop(); } } } } return changed; }