Esempio n. 1
0
// Helper function for UserProc::propagateStatements()
// Works on basic block n; call from UserProc with n=0 (entry BB)
// If an SSA location is in usedByDomPhi it means it is used in a phi that dominates its assignment
// However, it could turn out that the phi is dead, in which case we don't want to keep the associated entries in
// usedByDomPhi. So we maintain the map defdByPhi which maps locations defined at a phi to the phi statements. Every
// time we see a use of a location in defdByPhi, we remove that map entry. At the end of the procedure we therefore have
// only dead phi statements in the map, so we can delete the associated entries in defdByPhi and also remove the dead
// phi statements.
// We add to the set usedByDomPhi0 whenever we see a location referenced by a phi parameter. When we see a definition
// for such a location, we remove it from the usedByDomPhi0 set (to save memory) and add it to the usedByDomPhi set.
// For locations defined before they are used in a phi parameter, there will be no entry in usedByDomPhi, so we ignore
// it. Remember that each location is defined only once, so that's the time to decide if it is dominated by a phi use or
// not.
void DataFlow::findLiveAtDomPhi(int n, LocationSet& usedByDomPhi, LocationSet& usedByDomPhi0,
			std::map<Exp*, PhiAssign*, lessExpStar>& defdByPhi) {
	// For each statement this BB
	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->isPhi()) {
			// For each phi parameter, insert an entry into usedByDomPhi0
			PhiAssign* pa = (PhiAssign*)S;
			PhiAssign::iterator it;
			for (it = pa->begin(); it != pa->end(); ++it) {
				if (it->e) {
					RefExp* re = new RefExp(it->e, it->def);
					usedByDomPhi0.insert(re);
				}
			}
			// Insert an entry into the defdByPhi map
			RefExp* wrappedLhs = new RefExp(pa->getLeft(), pa);
			defdByPhi[wrappedLhs] = pa;
			// Fall through to the below, because phi uses are also legitimate uses
		}
		LocationSet ls;
		S->addUsedLocs(ls);
		// Consider uses of this statement
		LocationSet::iterator it;
		for (it = ls.begin(); it != ls.end(); ++it) {
			// Remove this entry from the map, since it is not unused
			defdByPhi.erase(*it);
		}
		// Now process any definitions
		ls.clear();
		S->getDefinitions(ls);
		for (it = ls.begin(); it != ls.end(); ++it) {
			RefExp* wrappedDef = new RefExp(*it, S);
			// If this definition is in the usedByDomPhi0 set, then it is in fact dominated by a phi use, so move it to
			// the final usedByDomPhi set
			if (usedByDomPhi0.find(wrappedDef) != usedByDomPhi0.end()) {
				usedByDomPhi0.remove(wrappedDef);
				usedByDomPhi.insert(wrappedDef);
			}
		}
	}

	// Visit each child in the dominator graph
	// Note: this is a linear search!
	// Note also that usedByDomPhi0 may have some irrelevant entries, but this will do no harm, and attempting to erase
	// the irrelevant ones would probably cost more than leaving them alone
	int sz = idom.size();
	for (int c = 0; c < sz; ++c) {
		if (idom[c] != n) continue;
		// Recurse to the child
		findLiveAtDomPhi(c, usedByDomPhi, usedByDomPhi0, defdByPhi);
	}
}
Esempio n. 2
0
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;
}