// Substitute s into all members of the set void LocationSet::substitute(Assign& a) { Exp* lhs = a.getLeft(); if (lhs == NULL) return; Exp* rhs = a.getRight(); if (rhs == NULL) return; // ? Will this ever happen? std::set<Exp*, lessExpStar>::iterator it; // Note: it's important not to change the pointer in the set of pointers to expressions, without removing and // inserting again. Otherwise, the set becomes out of order, and operations such as set comparison fail! // To avoid any funny behaviour when iterating the loop, we use the following two sets LocationSet removeSet; // These will be removed after the loop LocationSet removeAndDelete; // These will be removed then deleted LocationSet insertSet; // These will be inserted after the loop bool change; for (it = lset.begin(); it != lset.end(); it++) { Exp* loc = *it; Exp* replace; if (loc->search(lhs, replace)) { if (rhs->isTerminal()) { // This is no longer a location of interest (e.g. %pc) removeSet.insert(loc); continue; } loc = loc->clone()->searchReplaceAll(lhs, rhs, change); if (change) { loc = loc->simplifyArith(); loc = loc->simplify(); // If the result is no longer a register or memory (e.g. // r[28]-4), then delete this expression and insert any // components it uses (in the example, just r[28]) if (!loc->isRegOf() && !loc->isMemOf()) { // Note: can't delete the expression yet, because the // act of insertion into the remove set requires silent // calls to the compare function removeAndDelete.insert(*it); loc->addUsedLocs(insertSet); continue; } // Else we just want to replace it // Regardless of whether the top level expression pointer has // changed, remove and insert it from the set of pointers removeSet.insert(*it); // Note: remove the unmodified ptr insertSet.insert(loc); } } } makeDiff(removeSet); // Remove the items to be removed makeDiff(removeAndDelete); // These are to be removed as well makeUnion(insertSet); // Insert the items to be added // Now delete the expressions that are no longer needed std::set<Exp*, lessExpStar>::iterator dd; for (dd = removeAndDelete.lset.begin(); dd != removeAndDelete.lset.end(); dd++) delete *dd; // Plug that memory leak }
Exp *ExpTransformer::applyAllTo(Exp *p, bool &bMod) { for (std::list<Exp*>::iterator it = cache.begin(); it != cache.end(); it++) if (*(*it)->getSubExp1() == *p) return (*it)->getSubExp2()->clone(); Exp *e = p->clone(); Exp *subs[3]; subs[0] = e->getSubExp1(); subs[1] = e->getSubExp2(); subs[2] = e->getSubExp3(); for (int i = 0; i < 3; i++) if (subs[i]) { bool mod = false; subs[i] = applyAllTo(subs[i], mod); if (mod && i == 0) e->setSubExp1(subs[i]); if (mod && i == 1) e->setSubExp2(subs[i]); if (mod && i == 2) e->setSubExp3(subs[i]); bMod |= mod; // if (mod) i--; } #if 0 LOG << "applyAllTo called on " << e << "\n"; #endif bool mod; //do { mod = false; for (std::list<ExpTransformer *>::iterator it = transformers.begin(); it != transformers.end(); it++) { e = (*it)->applyTo(e, mod); bMod |= mod; } //} while (mod); cache.push_back(new Binary(opEquals, p->clone(), e->clone())); return e; }
Exp *GenericExpTransformer::applyFuncs(Exp *rhs) { Exp *call, *callw = new Binary(opFlagCall, new Const((char *)"memberAtOffset"), new Terminal(opWild)); if (rhs->search(callw, call)) { assert(call->getSubExp2()->getOper() == opList); Exp *p1 = applyFuncs(call->getSubExp2()->getSubExp1()); Exp *p2 = applyFuncs(call->getSubExp2()->getSubExp2()->getSubExp1()); assert(p1->getOper() == opTypeVal); assert(p2->getOper() == opIntConst); #if 0 Type *ty = p1->getType(); assert(ty && ty->resolvesToCompound()); #else Type *ty = NULL; // Note: will cause a segfault #endif // probably need to make this func take bits in future int offset = ((Const *)p2)->getInt() * 8; const char *member = ty->asCompound()->getNameAtOffset(offset); Exp *result = new Const((char *)member); bool change; rhs = rhs->searchReplace(callw->clone(), result->clone(), change); assert(change); #if 0 LOG << "replaced " << call << " with " << result << "\n"; #endif } callw = new Binary(opFlagCall, new Const((char *)"offsetToMember"), new Terminal(opWild)); if (rhs->search(callw, call)) { assert(call->getSubExp2()->getOper() == opList); Exp *p1 = applyFuncs(call->getSubExp2()->getSubExp1()); Exp *p2 = applyFuncs(call->getSubExp2()->getSubExp2()->getSubExp1()); assert(p1->getOper() == opTypeVal); assert(p2->getOper() == opStrConst); #if 0 // ADHOC TA Type *ty = p1->getType(); assert(ty && ty->resolvesToCompound()); #else Type *ty = NULL; // Note: will cause a segfault #endif char *member = ((Const *)p2)->getStr(); int offset = ty->asCompound()->getOffsetTo(member) / 8; Exp *result = new Const(offset); bool change; rhs = rhs->searchReplace(callw->clone(), result->clone(), change); assert(change); #if 0 LOG << "replaced " << call << " with " << result << "\n"; #endif } callw = new Binary(opFlagCall, new Const((char *)"plus"), new Terminal(opWild)); if (rhs->search(callw, call)) { assert(call->getSubExp2()->getOper() == opList); Exp *p1 = applyFuncs(call->getSubExp2()->getSubExp1()); Exp *p2 = applyFuncs(call->getSubExp2()->getSubExp2()->getSubExp1()); assert(p1->getOper() == opIntConst); assert(p2->getOper() == opIntConst); int a = ((Const *)p1)->getInt(); int b = ((Const *)p2)->getInt(); Exp *result = new Const(a + b); bool change; rhs = rhs->searchReplace(callw->clone(), result->clone(), change); assert(change); #if 0 LOG << "replaced " << call << " with " << result << "\n"; #endif } callw = new Binary(opFlagCall, new Const((char *)"neg"), new Terminal(opWild)); if (rhs->search(callw, call)) { Exp *p1 = applyFuncs(call->getSubExp2()); assert(p1->getOper() == opIntConst); int a = ((Const *)p1)->getInt(); Exp *result = new Const(-a); bool change; rhs = rhs->searchReplace(callw->clone(), result->clone(), change); assert(change); #if 0 LOG << "replaced " << call << " with " << result << "\n"; #endif } return rhs; }
bool GenericExpTransformer::checkCond(Exp *cond, Exp *bindings) { switch (cond->getOper()) { case opAnd: return checkCond(cond->getSubExp1(), bindings) && checkCond(cond->getSubExp2(), bindings); case opEquals: { Exp *lhs = cond->getSubExp1(), *rhs = cond->getSubExp2(); for (Exp *l = bindings; l->getOper() != opNil; l = l->getSubExp2()) { Exp *e = l->getSubExp1(); bool change = false; lhs = lhs->searchReplaceAll(e->getSubExp1()->clone(), e->getSubExp2()->clone(), change); #if 0 if (change) LOG << "replaced " << e->getSubExp1() << " with " << e->getSubExp2() << "\n"; #endif change = false; rhs = rhs->searchReplaceAll(e->getSubExp1()->clone(), e->getSubExp2()->clone(), change); #if 0 if (change) LOG << "replaced " << e->getSubExp1() << " with " << e->getSubExp2() << "\n"; #endif } if (lhs->getOper() == opTypeOf) { #if 0 // ADHOC TA Type *ty = lhs->getSubExp1()->getType(); #else Type *ty = NULL; #endif if (ty == NULL) { #if 0 if (VERBOSE) LOG << "no type for typeof " << lhs << "\n"; #endif return false; } lhs = new TypeVal(ty); #if 0 LOG << "got typeval: " << lhs << "\n"; #endif } if (lhs->getOper() == opKindOf) { OPER op = lhs->getSubExp1()->getOper(); lhs = new Const(operStrings[op]); } rhs = applyFuncs(rhs); #if 0 LOG << "check equals in cond: " << lhs << " == " << rhs << "\n"; #endif if (lhs->getOper() == opVar) { Exp *le; for (le = bindings; le->getOper() != opNil && le->getSubExp2()->getOper() != opNil; le = le->getSubExp2()) ; assert(le->getOper() != opNil); le->setSubExp2(new Binary(opList, new Binary(opEquals, lhs->clone(), rhs->clone()), new Terminal(opNil))); #if 0 LOG << "bindings now: " << bindings << "\n"; #endif return true; } if (*lhs == *rhs) return true; #if 0 // ADHOC TA if (lhs->getOper() == opTypeVal && rhs->getOper() == opTypeVal && lhs->getType()->resolvesToCompound() && rhs->getType()->isCompound()) return true; #endif Exp *new_bindings = lhs->match(rhs); if (new_bindings == NULL) return false; #if 0 LOG << "matched lhs with rhs, bindings: " << new_bindings << "\n"; #endif Exp *le; for (le = bindings; le->getOper() != opNil && le->getSubExp2()->getOper() != opNil; le = le->getSubExp2()) ; assert(le->getOper() != opNil); le->setSubExp2(new_bindings); #if 0 LOG << "bindings now: " << bindings << "\n"; #endif return true; } default: LOG << "don't know how to handle oper " << operStrings[cond->getOper()] << " in cond.\n"; } return false; }
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; }
bool DataFlow::placePhiFunctions(UserProc* proc) { // First free some memory no longer needed dfnum.resize(0); semi.resize(0); ancestor.resize(0); samedom.resize(0); vertex.resize(0); parent.resize(0); best.resize(0); bucket.resize(0); defsites.clear(); // Clear defsites map, defallsites.clear(); A_orig.clear(); // and A_orig, defStmts.clear(); // and the map from variable to defining Stmt bool change = false; // Set the sizes of needed vectors unsigned numBB = indices.size(); Cfg* cfg = proc->getCFG(); assert(numBB == cfg->getNumBBs()); A_orig.resize(numBB); // We need to create A_orig[n] for all n, the array of sets of locations defined at BB n // Recreate each call because propagation and other changes make old data invalid unsigned n; for (n=0; n < numBB; n++) { BasicBlock::rtlit rit; StatementList::iterator sit; PBB bb = BBs[n]; for (Statement* s = bb->getFirstStmt(rit, sit); s; s = bb->getNextStmt(rit, sit)) { LocationSet ls; LocationSet::iterator it; s->getDefinitions(ls); if (s->isCall() && ((CallStatement*)s)->isChildless()) // If this is a childless call defallsites.insert(n); // then this block defines every variable for (it = ls.begin(); it != ls.end(); it++) { if (canRename(*it, proc)) { A_orig[n].insert((*it)->clone()); defStmts[*it] = s; } } } } // For each node n for (n=0; n < numBB; n++) { // For each variable a in A_orig[n] std::set<Exp*, lessExpStar>& s = A_orig[n]; std::set<Exp*, lessExpStar>::iterator aa; for (aa = s.begin(); aa != s.end(); aa++) { Exp* a = *aa; defsites[a].insert(n); } } // For each variable a (in defsites, i.e. defined anywhere) std::map<Exp*, std::set<int>, lessExpStar>::iterator mm; for (mm = defsites.begin(); mm != defsites.end(); mm++) { Exp* a = (*mm).first; // *mm is pair<Exp*, set<int>> // Special processing for define-alls // for each n in defallsites std::set<int>::iterator da; for (da = defallsites.begin(); da != defallsites.end(); ++da) defsites[a].insert(*da); // W <- defsites[a]; std::set<int> W = defsites[a]; // set copy // While W not empty while (W.size()) { // Remove some node n from W int n = *W.begin(); // Copy first element W.erase(W.begin()); // Remove first element // for each y in DF[n] std::set<int>::iterator yy; std::set<int>& DFn = DF[n]; for (yy = DFn.begin(); yy != DFn.end(); yy++) { int y = *yy; // if y not element of A_phi[a] std::set<int>& s = A_phi[a]; if (s.find(y) == s.end()) { // Insert trivial phi function for a at top of block y: a := phi() change = true; Statement* as = new PhiAssign(a->clone()); PBB Ybb = BBs[y]; Ybb->prependStmt(as, proc); // A_phi[a] <- A_phi[a] U {y} s.insert(y); // if a !elementof A_orig[y] if (A_orig[y].find(a) == A_orig[y].end()) { // W <- W U {y} W.insert(y); } } } } } return change; } // end placePhiFunctions
void BlockSyntaxNode::addSuccessors(SyntaxNode *root, std::vector<SyntaxNode *> &successors) { for (unsigned i = 0; i < statements.size(); i++) { if (statements[i]->isBlock()) { //BlockSyntaxNode *b = (BlockSyntaxNode*)statements[i]; // can move previous statements into this block if (i > 0) { std::cerr << "successor: move previous statement into block" << std::endl; SyntaxNode *n = root->clone(); n->setDepth(root->getDepth() + 1); BlockSyntaxNode *b1 = (BlockSyntaxNode *)this->clone(); BlockSyntaxNode *nb = (BlockSyntaxNode *)b1->getStatement(i); b1 = (BlockSyntaxNode *)b1->replace(statements[i - 1], NULL); nb->prependStatement(statements[i - 1]->clone()); n = n->replace(this, b1); successors.push_back(n); //PRINT_BEFORE_AFTER } } else { if (statements.size() != 1) { // can replace statement with a block containing that statement std::cerr << "successor: replace statement with a block containing the statement" << std::endl; BlockSyntaxNode *b = new BlockSyntaxNode(); b->addStatement(statements[i]->clone()); SyntaxNode *n = root->clone(); n->setDepth(root->getDepth() + 1); n = n->replace(statements[i], b); successors.push_back(n); //PRINT_BEFORE_AFTER } } // "jump over" style of if-then if (i < statements.size() - 2 && statements[i]->isBranch()) { SyntaxNode *b = statements[i]; if (b->getOutEdge(root, 0) == statements[i + 2] && (statements[i + 1]->getOutEdge(root, 0) == statements[i + 2] || statements[i + 1]->endsWithGoto())) { std::cerr << "successor: jump over style if then" << std::endl; BlockSyntaxNode *b1 = (BlockSyntaxNode *)this->clone(); b1 = (BlockSyntaxNode *)b1->replace(statements[i + 1], NULL); IfThenSyntaxNode *nif = new IfThenSyntaxNode(); Exp *cond = b->getBB()->getCond(); cond = new Unary(opLNot, cond->clone()); cond = cond->simplify(); nif->setCond(cond); nif->setThen(statements[i + 1]->clone()); nif->setBB(b->getBB()); b1->setStatement(i, nif); SyntaxNode *n = root->clone(); n->setDepth(root->getDepth() + 1); n = n->replace(this, b1); successors.push_back(n); //PRINT_BEFORE_AFTER } } // if then else if (i < statements.size() - 2 && statements[i]->isBranch()) { SyntaxNode *tThen = statements[i]->getOutEdge(root, 0); SyntaxNode *tElse = statements[i]->getOutEdge(root, 1); assert(tThen && tElse); if (((tThen == statements[i + 2] && tElse == statements[i + 1]) || (tThen == statements[i + 1] && tElse == statements[i + 2])) && tThen->getNumOutEdges() == 1 && tElse->getNumOutEdges() == 1) { SyntaxNode *else_out = tElse->getOutEdge(root, 0); SyntaxNode *then_out = tThen->getOutEdge(root, 0); if (else_out == then_out) { std::cerr << "successor: if then else" << std::endl; SyntaxNode *n = root->clone(); n->setDepth(root->getDepth() + 1); n = n->replace(tThen, NULL); n = n->replace(tElse, NULL); IfThenElseSyntaxNode *nif = new IfThenElseSyntaxNode(); nif->setCond(statements[i]->getBB()->getCond()->clone()); nif->setBB(statements[i]->getBB()); nif->setThen(tThen->clone()); nif->setElse(tElse->clone()); n = n->replace(statements[i], nif); successors.push_back(n); //PRINT_BEFORE_AFTER } } } // pretested loop if (i < statements.size() - 2 && statements[i]->isBranch()) { SyntaxNode *tBody = statements[i]->getOutEdge(root, 0); SyntaxNode *tFollow = statements[i]->getOutEdge(root, 1); assert(tBody && tFollow); if (tBody == statements[i + 1] && tFollow == statements[i + 2] && tBody->getNumOutEdges() == 1 && tBody->getOutEdge(root, 0) == statements[i]) { std::cerr << "successor: pretested loop" << std::endl; SyntaxNode *n = root->clone(); n->setDepth(root->getDepth() + 1); n = n->replace(tBody, NULL); PretestedLoopSyntaxNode *nloop = new PretestedLoopSyntaxNode(); nloop->setCond(statements[i]->getBB()->getCond()->clone()); nloop->setBB(statements[i]->getBB()); nloop->setBody(tBody->clone()); n = n->replace(statements[i], nloop); successors.push_back(n); //PRINT_BEFORE_AFTER } } // posttested loop if (i > 0 && i < statements.size() - 1 && statements[i]->isBranch()) { SyntaxNode *tBody = statements[i]->getOutEdge(root, 0); SyntaxNode *tFollow = statements[i]->getOutEdge(root, 1); assert(tBody && tFollow); if (tBody == statements[i - 1] && tFollow == statements[i + 1] && tBody->getNumOutEdges() == 1 && tBody->getOutEdge(root, 0) == statements[i]) { std::cerr << "successor: posttested loop" << std::endl; SyntaxNode *n = root->clone(); n->setDepth(root->getDepth() + 1); n = n->replace(tBody, NULL); PostTestedLoopSyntaxNode *nloop = new PostTestedLoopSyntaxNode(); nloop->setCond(statements[i]->getBB()->getCond()->clone()); nloop->setBB(statements[i]->getBB()); nloop->setBody(tBody->clone()); n = n->replace(statements[i], nloop); successors.push_back(n); //PRINT_BEFORE_AFTER } } // infinite loop if (statements[i]->getNumOutEdges() == 1 && statements[i]->getOutEdge(root, 0) == statements[i]) { std::cerr << "successor: infinite loop" << std::endl; SyntaxNode *n = root->clone(); n->setDepth(root->getDepth() + 1); InfiniteLoopSyntaxNode *nloop = new InfiniteLoopSyntaxNode(); nloop->setBody(statements[i]->clone()); n = n->replace(statements[i], nloop); successors.push_back(n); PRINT_BEFORE_AFTER } statements[i]->addSuccessors(root, successors); }
std::list<Statement *> *RTLInstDict::transformPostVars(std::list<Statement *> *rts, bool optimise) { std::list<Statement *>::iterator rt; // Map from var (could be any expression really) to details std::map<Exp *, transPost, lessExpStar> vars; int tmpcount = 1; // For making temp names unique // Exp *matchParam(1, idParam); // ? Was never used anyway #ifdef DEBUG_POSTVAR std::cout << "Transforming from:\n"; for (Exp_CIT p = rts->begin(); p != rts->end(); p++) { std::cout << setw(8) << " "; (*p)->print(std::cout); std::cout << "\n"; } #endif // First pass: Scan for post-variables and usages of their referents for (rt = rts->begin(); rt != rts->end(); rt++) { // ss appears to be a list of expressions to be searched // It is either the LHS and RHS of an assignment, or it's the parameters of a flag call Binary *ss; if ((*rt)->isAssign()) { Exp *lhs = ((Assign *)*rt)->getLeft(); Exp *rhs = ((Assign *)*rt)->getRight(); // Look for assignments to post-variables if (lhs && lhs->isPostVar()) { if (vars.find(lhs) == vars.end()) { // Add a record in the map for this postvar transPost &el = vars[lhs]; el.used = false; el.type = ((Assign *)*rt)->getType(); // Constuct a temporary. We should probably be smarter and actually check that it's not otherwise // used here. std::string tmpname = el.type->getTempName() + (tmpcount++) + "post" ; el.tmp = Location::tempOf(new Const(tmpname.c_str())); // Keep a copy of the referrent. For example, if the lhs is r[0]', base is r[0] el.base = lhs->getSubExp1(); el.post = lhs; // The whole post-var, e.g. r[0]' el.isNew = true; // The emulator generator sets optimise false // I think this forces always generating the temps (MVE) if (!optimise) { el.used = true; el.isNew = false; } } } // For an assignment, the two expressions to search are the left and right hand sides (could just put the // whole assignment on, I suppose) ss = new Binary(opList, lhs->clone(), new Binary(opList, rhs->clone(), new Terminal(opNil))); } else if ((*rt)->isFlagAssgn()) { // An opFlagCall is assumed to be a Binary with a string and an opList of parameters ss = (Binary *)((Binary *)*rt)->getSubExp2(); } else ss = NULL; /* Look for usages of post-variables' referents * Trickier than you'd think, as we need to make sure to skip over the post-variables themselves. ie match * r[0] but not r[0]' * Note: back with SemStrs, we could use a match expression which was a wildcard prepended to the base * expression; this would match either the base (r[0]) or the post-var (r[0]'). * Can't really use this with Exps, so we search twice; once for the base, and once for the post, and if we * get more with the former, then we have a use of the base (consider r[0] + r[0]') */ for (std::map<Exp *, transPost, lessExpStar>::iterator sr = vars.begin(); sr != vars.end(); sr++) { if (sr->second.isNew) { // Make sure we don't match a var in its defining statement sr->second.isNew = false; continue; } Binary *cur; for (cur = ss; !cur->isNil(); cur = (Binary *)cur->getSubExp2()) { if (sr->second.used) break; // Don't bother; already know it's used Exp *s = cur->getSubExp1(); if (!s) continue; if (*s == *sr->second.base) { sr->second.used = true; break; } std::list<Exp *> res1, res2; s->searchAll(sr->second.base, res1); s->searchAll(sr->second.post, res2); // Each match of a post will also match the base. // But if there is a bare (non-post) use of the base, there will be a result in res1 that is not in res2 if (res1.size() > res2.size()) sr->second.used = true; } } } // Second pass: Replace post-variables with temporaries where needed for (rt = rts->begin(); rt != rts->end(); rt++) { for (std::map<Exp *, transPost, lessExpStar>::iterator sr = vars.begin(); sr != vars.end(); sr++) { if (sr->second.used) { (*rt)->searchAndReplace(sr->first, sr->second.tmp); } else { (*rt)->searchAndReplace(sr->first, sr->second.base); } } } // Finally: Append assignments where needed from temps to base vars // Example: esp' = esp-4; m[esp'] = modrm; FLAG(esp) // all the esp' are replaced with say tmp1, you need a "esp = tmp1" at the end to actually make the change for (std::map<Exp *, transPost, lessExpStar>::iterator sr = vars.begin(); sr != vars.end(); sr++) { if (sr->second.used) { Assign *te = new Assign(sr->second.type, sr->second.base->clone(), sr->second.tmp); rts->push_back(te); } else { // The temp is either used (uncloned) in the assignment, or is deleted here //delete sr->second.tmp; } } #ifdef DEBUG_POSTVAR std::cout << "\nTo =>\n"; for (std::list<Exp *>::iterator p = rts->begin(); p != rts->end(); p++) { std::cout << setw(8) << " "; (*p)->print(std::cout); std::cout << "\n"; } std::cout << "\n"; #endif return rts; }
bool Constraints::solve(std::list<ConstraintMap>& solns) { LOG << conSet.size() << " constraints:"; std::ostringstream os; conSet.print(os); LOG << os.str().c_str(); // Replace Ta[loc] = ptr(alpha) with // Tloc = alpha LocationSet::iterator cc; for (cc = conSet.begin(); cc != conSet.end(); cc++) { Exp* c = *cc; if (!c->isEquality()) continue; Exp* left = ((Binary*)c)->getSubExp1(); if (!left->isTypeOf()) continue; Exp* leftSub = ((Unary*)left)->getSubExp1(); if (!leftSub->isAddrOf()) continue; Exp* right = ((Binary*)c)->getSubExp2(); if (!right->isTypeVal()) continue; Type* t = ((TypeVal*)right)->getType(); if (!t->isPointer()) continue; // Don't modify a key in a map Exp* clone = c->clone(); // left is typeof(addressof(something)) -> typeof(something) left = ((Binary*)clone)->getSubExp1(); leftSub = ((Unary*)left)->getSubExp1(); Exp* something = ((Unary*)leftSub)->getSubExp1(); ((Unary*)left)->setSubExp1ND(something); ((Unary*)leftSub)->setSubExp1ND(NULL); delete leftSub; // right is <alpha*> -> <alpha> right = ((Binary*)clone)->getSubExp2(); t = ((TypeVal*)right)->getType(); ((TypeVal*)right)->setType(((PointerType*)t)->getPointsTo()->clone()); delete t; conSet.remove(c); conSet.insert(clone); delete c; } // Sort constraints into a few categories. Disjunctions go to a special // list, always true is just ignored, and constraints of the form // typeof(x) = y (where y is a type value) go to a map called fixed. // Constraint terms of the form Tx = Ty go into a map of LocationSets // called equates for fast lookup for (cc = conSet.begin(); cc != conSet.end(); cc++) { Exp* c = *cc; if (c->isTrue()) continue; if (c->isFalse()) { if (VERBOSE || DEBUG_TA) LOG << "Constraint failure: always false constraint\n"; return false; } if (c->isDisjunction()) { disjunctions.push_back(c); continue; } // Break up conjunctions into terms Exp* rem = c, *term; while ((term = nextConjunct(rem)) != NULL) { assert(term->isEquality()); Exp* lhs = ((Binary*)term)->getSubExp1(); Exp* rhs = ((Binary*)term)->getSubExp2(); if (rhs->isTypeOf()) { // Of the form typeof(x) = typeof(z) // Insert into equates equates.addEquate(lhs, rhs); } else { // Of the form typeof(x) = <typeval> // Insert into fixed assert(rhs->isTypeVal()); fixed[lhs] = rhs; } } } {LOG << "\n" << (unsigned)disjunctions.size() << " disjunctions: "; std::list<Exp*>::iterator dd; for (dd = disjunctions.begin(); dd != disjunctions.end(); dd++) LOG << *dd << ",\n"; LOG << "\n";} LOG << fixed.size() << " fixed: " << fixed.prints(); LOG << equates.size() << " equates: " << equates.prints(); // Substitute the fixed types into the disjunctions substIntoDisjuncts(fixed); // Substitute the fixed types into the equates. This may generate more // fixed types substIntoEquates(fixed); LOG << "\nAfter substitute fixed into equates:\n"; {LOG << "\n" << (unsigned)disjunctions.size() << " disjunctions: "; std::list<Exp*>::iterator dd; for (dd = disjunctions.begin(); dd != disjunctions.end(); dd++) LOG << *dd << ",\n"; LOG << "\n";} LOG << fixed.size() << " fixed: " << fixed.prints(); LOG << equates.size() << " equates: " << equates.prints(); // Substitute again the fixed types into the disjunctions // (since there may be more fixed types from the above) substIntoDisjuncts(fixed); LOG << "\nAfter second substitute fixed into disjunctions:\n"; {LOG << "\n" << (unsigned)disjunctions.size() << " disjunctions: "; std::list<Exp*>::iterator dd; for (dd = disjunctions.begin(); dd != disjunctions.end(); dd++) LOG << *dd << ",\n"; LOG << "\n";} LOG << fixed.size() << " fixed: " << fixed.prints(); LOG << equates.size() << " equates: " << equates.prints(); ConstraintMap soln; bool ret = doSolve(disjunctions.begin(), soln, solns); if (ret) { // For each solution, we need to find disjunctions of the form // <alphaN> = <type> or // <type> = <alphaN> // and substitute these into each part of the solution std::list<ConstraintMap>::iterator it; for (it = solns.begin(); it != solns.end(); it++) it->substAlpha(); } return ret; }