Chromium Code Reviews| Index: src/IceCfgNode.cpp |
| diff --git a/src/IceCfgNode.cpp b/src/IceCfgNode.cpp |
| index c00b2c77538a49faf6b7fe37af067b0fccda7094..3a08346a1b3df0d450bc92f0e440652f4525231f 100644 |
| --- a/src/IceCfgNode.cpp |
| +++ b/src/IceCfgNode.cpp |
| @@ -15,6 +15,7 @@ |
| #include "IceCfg.h" |
| #include "IceCfgNode.h" |
| #include "IceInst.h" |
| +#include "IceLiveness.h" |
| #include "IceOperand.h" |
| #include "IceTargetLowering.h" |
| @@ -49,6 +50,22 @@ void CfgNode::appendInst(Inst *Inst) { |
| Inst->updateVars(this); |
| } |
| +// Renumbers the non-deleted instructions in the node. This needs to |
| +// be done in preparation for live range analysis. The instruction |
| +// numbers in a block must be monotonically increasing. The range of |
| +// instruction numbers in a block, from lowest to highest, must not |
| +// overlap with the range of any other block. |
| +void CfgNode::renumberInstructions() { |
| + for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) { |
| + (*I)->renumber(Func); |
| + } |
| + InstList::const_iterator I = Insts.begin(), E = Insts.end(); |
| + while (I != E) { |
| + Inst *Inst = *I++; |
| + Inst->renumber(Func); |
| + } |
| +} |
| + |
| // When a node is created, the OutEdges are immediately knows, but the |
| // InEdges have to be built up incrementally. After the CFG has been |
| // constructed, the computePredecessors() pass finalizes it by |
| @@ -107,10 +124,25 @@ void CfgNode::placePhiStores() { |
| // Every block must end in a terminator instruction. |
| assert(InsertionPoint != Insts.begin()); |
| --InsertionPoint; |
| - // Confirm via assert() that InsertionPoint is a terminator |
| - // instruction. Calling getTerminatorEdges() on a non-terminator |
| - // instruction will cause an llvm_unreachable(). |
| - assert(((*InsertionPoint)->getTerminatorEdges(), true)); |
| + // Confirm that InsertionPoint is a terminator instruction. Calling |
| + // getTerminatorEdges() on a non-terminator instruction will cause |
| + // an llvm_unreachable(). |
| + (void)(*InsertionPoint)->getTerminatorEdges(); |
| + // If the current insertion point is at a conditional branch |
| + // instruction, and the previous instruction is a compare |
| + // instruction, then we move the insertion point before the compare |
| + // instruction so as not to interfere with compare/branch fusing. |
| + if (InstBr *Branch = llvm::dyn_cast<InstBr>(*InsertionPoint)) { |
| + if (!Branch->isUnconditional()) { |
| + if (InsertionPoint != Insts.begin()) { |
| + --InsertionPoint; |
| + if (!llvm::isa<InstIcmp>(*InsertionPoint) && |
| + !llvm::isa<InstFcmp>(*InsertionPoint)) { |
| + ++InsertionPoint; |
| + } |
| + } |
| + } |
| + } |
| // Consider every out-edge. |
| for (NodeList::const_iterator I1 = OutEdges.begin(), E1 = OutEdges.end(); |
| @@ -145,6 +177,19 @@ void CfgNode::deletePhis() { |
| } |
| } |
| +// Does address mode optimization. Pass each instruction to the |
| +// TargetLowering object. If it returns a new instruction |
| +// (representing the optimized address mode), then insert the new |
| +// instruction and delete the old. |
| +void CfgNode::doAddressOpt() { |
| + TargetLowering *Target = Func->getTarget(); |
| + LoweringContext &Context = Target->getContext(); |
| + Context.init(this); |
| + while (!Context.atEnd()) { |
| + Target->doAddressOpt(); |
| + } |
| +} |
| + |
| // Drives the target lowering. Passes the current instruction and the |
| // next non-deleted instruction for target lowering. |
| void CfgNode::genCode() { |
| @@ -162,6 +207,181 @@ void CfgNode::genCode() { |
| } |
| } |
| +void CfgNode::livenessLightweight() { |
| + SizeT NumVars = Func->getNumVariables(); |
| + llvm::BitVector Live(NumVars); |
| + // Process regular instructions in reverse order. |
| + for (InstList::const_reverse_iterator I = Insts.rbegin(), E = Insts.rend(); |
| + I != E; ++I) { |
| + (*I)->livenessLightweight(Live); |
| + } |
| + for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) { |
| + (*I)->livenessLightweight(Live); |
| + } |
| +} |
| + |
| +// Performs liveness analysis on the block. Returns true if the |
| +// incoming liveness changed from before, false if it stayed the same. |
| +// (If it changes, the node's predecessors need to be processed |
| +// again.) |
| +bool CfgNode::liveness(Liveness *Liveness) { |
| + SizeT NumVars = Liveness->getLocalSize(this); |
| + llvm::BitVector Live(NumVars); |
| + // Mark the beginning and ending of each variable's live range |
| + // with the sentinel instruction number 0. |
| + std::vector<int> &LiveBegin = Liveness->getLiveBegin(this); |
| + std::vector<int> &LiveEnd = Liveness->getLiveEnd(this); |
| + LiveBegin.assign(NumVars, 0); |
| + LiveEnd.assign(NumVars, 0); |
| + // Initialize Live to be the union of all successors' LiveIn. |
| + for (NodeList::const_iterator I = OutEdges.begin(), E = OutEdges.end(); |
| + I != E; ++I) { |
| + CfgNode *Succ = *I; |
| + Live |= Liveness->getLiveIn(Succ); |
| + // Mark corresponding argument of phis in successor as live. |
| + for (PhiList::const_iterator I1 = Succ->Phis.begin(), E1 = Succ->Phis.end(); |
| + I1 != E1; ++I1) { |
| + (*I1)->livenessPhiOperand(Live, this, Liveness); |
| + } |
| + } |
| + Liveness->getLiveOut(this) = Live; |
| + |
| + // Process regular instructions in reverse order. |
| + for (InstList::const_reverse_iterator I = Insts.rbegin(), E = Insts.rend(); |
| + I != E; ++I) { |
| + (*I)->liveness((*I)->getNumber(), Live, Liveness, this); |
| + } |
| + // Process phis in forward order so that we can override the |
| + // instruction number to be that of the earliest phi instruction in |
| + // the block. |
| + int32_t FirstPhiNumber = 0; // sentinel value |
| + for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) { |
| + if (FirstPhiNumber <= 0) |
|
jvoung (off chromium)
2014/05/30 15:41:31
nit: could be a strict == test, since you're just
Jim Stichnoth
2014/05/30 23:06:18
As it turns out, the <= test also makes us ignore
|
| + FirstPhiNumber = (*I)->getNumber(); |
| + (*I)->liveness(FirstPhiNumber, Live, Liveness, this); |
| + } |
| + |
| + // When using the sparse representation, after traversing the |
| + // instructions in the block, the Live bitvector should only contain |
| + // set bits for global variables upon block entry. We validate this |
| + // by shrinking the Live vector and then testing it against the |
| + // pre-shrunk version. (The shrinking is required, but the |
| + // validation is not.) |
| + llvm::BitVector LiveOrig = Live; |
| + Live.resize(Liveness->getGlobalSize()); |
| + // Non-global arguments in the entry node are allowed to be live on |
| + // entry. |
| + bool IsEntry = (Func->getEntryNode() == this); |
| + if (!(IsEntry || Live == LiveOrig)) { |
| + // This is a fatal liveness consistency error. Print some |
| + // diagnostics and abort. |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + Func->setCurrentNode(NULL); |
| + Str << "LiveOrig-Live ="; |
| + for (SizeT i = Live.size(); i < LiveOrig.size(); ++i) { |
| + if (LiveOrig.test(i)) { |
| + Str << " "; |
| + Liveness->getVariable(i, this)->dump(Func); |
| + } |
| + } |
| + Str << "\n"; |
| + llvm_unreachable("Fatal inconsistency in liveness analysis"); |
| + } |
| + |
| + bool Changed = false; |
| + llvm::BitVector &LiveIn = Liveness->getLiveIn(this); |
| + // Add in current LiveIn |
| + Live |= LiveIn; |
| + // Check result, set LiveIn=Live |
| + Changed = (Live != LiveIn); |
| + if (Changed) |
| + LiveIn = Live; |
| + return Changed; |
| +} |
| + |
| +// Now that basic liveness is complete, remove dead instructions that |
| +// were tentatively marked as dead, and compute actual live ranges. |
| +// It is assumed that within a single basic block, a live range begins |
| +// at most once and ends at most once. This is certainly true for |
| +// pure SSA form. It is also true once phis are lowered, since each |
| +// assignment to the phi-based temporary is in a different basic |
| +// block, and there is a single read that ends the live in the basic |
| +// block that contained the actual phi instruction. |
| +void CfgNode::livenessPostprocess(LivenessMode Mode, Liveness *Liveness) { |
| + int32_t FirstInstNum = 0; |
| + int32_t LastInstNum = 0; |
| + // Process phis in any order. Process only Dest operands. |
| + for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) { |
| + InstPhi *Inst = *I; |
| + Inst->deleteIfDead(); |
| + if (Inst->isDeleted()) |
| + continue; |
| + if (FirstInstNum <= 0) |
| + FirstInstNum = Inst->getNumber(); |
| + assert(Inst->getNumber() > LastInstNum); |
| + LastInstNum = Inst->getNumber(); |
| + } |
| + // Process instructions |
| + for (InstList::const_iterator I = Insts.begin(), E = Insts.end(); I != E; |
| + ++I) { |
| + Inst *Inst = *I; |
| + Inst->deleteIfDead(); |
| + if (Inst->isDeleted()) |
| + continue; |
| + if (FirstInstNum <= 0) |
| + FirstInstNum = Inst->getNumber(); |
| + assert(Inst->getNumber() > LastInstNum); |
| + LastInstNum = Inst->getNumber(); |
| + // Create fake live ranges for a Kill instruction, but only if the |
| + // linked instruction is still alive. |
| + if (Mode == Liveness_Intervals) { |
| + if (InstFakeKill *Kill = llvm::dyn_cast<InstFakeKill>(Inst)) { |
| + if (!Kill->getLinked()->isDeleted()) { |
| + SizeT NumSrcs = Inst->getSrcSize(); |
| + for (SizeT i = 0; i < NumSrcs; ++i) { |
| + Variable *Var = llvm::cast<Variable>(Inst->getSrc(i)); |
| + int32_t InstNumber = Inst->getNumber(); |
| + Liveness->addLiveRange(Var, InstNumber, InstNumber, 1); |
| + } |
| + } |
| + } |
| + } |
| + } |
| + if (Mode != Liveness_Intervals) |
| + return; |
| + |
| + SizeT NumVars = Liveness->getLocalSize(this); |
| + SizeT NumGlobals = Liveness->getGlobalSize(); |
| + llvm::BitVector &LiveIn = Liveness->getLiveIn(this); |
| + llvm::BitVector &LiveOut = Liveness->getLiveOut(this); |
| + std::vector<int> &LiveBegin = Liveness->getLiveBegin(this); |
| + std::vector<int> &LiveEnd = Liveness->getLiveEnd(this); |
| + for (SizeT i = 0; i < NumVars; ++i) { |
| + // Deal with the case where the variable is both live-in and |
| + // live-out, but LiveEnd comes before LiveBegin. In this case, we |
| + // need to add two segments to the live range because there is a |
| + // hole in the middle. This would typically happen as a result of |
| + // phi lowering in the presence of loopback edges. |
| + bool IsGlobal = (i < NumGlobals); |
| + if (IsGlobal && LiveIn[i] && LiveOut[i] && LiveBegin[i] > LiveEnd[i]) { |
| + Variable *Var = Liveness->getVariable(i, this); |
| + Liveness->addLiveRange(Var, FirstInstNum, LiveEnd[i], 1); |
| + Liveness->addLiveRange(Var, LiveBegin[i], LastInstNum + 1, 1); |
| + continue; |
| + } |
| + int32_t Begin = (IsGlobal && LiveIn[i]) ? FirstInstNum : LiveBegin[i]; |
| + int32_t End = (IsGlobal && LiveOut[i]) ? LastInstNum + 1 : LiveEnd[i]; |
| + if (Begin <= 0 && End <= 0) |
| + continue; |
| + if (Begin <= FirstInstNum) |
| + Begin = FirstInstNum; |
| + if (End <= 0) |
| + End = LastInstNum + 1; |
| + Variable *Var = Liveness->getVariable(i, this); |
| + Liveness->addLiveRange(Var, Begin, End, 1); |
| + } |
| +} |
| + |
| // ======================== Dump routines ======================== // |
| void CfgNode::emit(Cfg *Func) const { |
| @@ -194,6 +414,7 @@ void CfgNode::emit(Cfg *Func) const { |
| void CfgNode::dump(Cfg *Func) const { |
| Func->setCurrentNode(this); |
| Ostream &Str = Func->getContext()->getStrDump(); |
| + Liveness *Liveness = Func->getLiveness(); |
| if (Func->getContext()->isVerbose(IceV_Instructions)) { |
| Str << getName() << ":\n"; |
| } |
| @@ -208,6 +429,19 @@ void CfgNode::dump(Cfg *Func) const { |
| } |
| Str << "\n"; |
| } |
| + // Dump the live-in variables. |
| + llvm::BitVector LiveIn; |
| + if (Liveness) |
| + LiveIn = Liveness->getLiveIn(this); |
| + if (Func->getContext()->isVerbose(IceV_Liveness) && !LiveIn.empty()) { |
| + Str << " // LiveIn:"; |
| + for (SizeT i = 0; i < LiveIn.size(); ++i) { |
| + if (LiveIn[i]) { |
| + Str << " %" << Liveness->getVariable(i, this)->getName(); |
| + } |
| + } |
| + Str << "\n"; |
| + } |
| // Dump each instruction. |
| if (Func->getContext()->isVerbose(IceV_Instructions)) { |
| for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; |
| @@ -221,6 +455,19 @@ void CfgNode::dump(Cfg *Func) const { |
| Inst->dumpDecorated(Func); |
| } |
| } |
| + // Dump the live-out variables. |
| + llvm::BitVector LiveOut; |
| + if (Liveness) |
| + LiveOut = Liveness->getLiveOut(this); |
| + if (Func->getContext()->isVerbose(IceV_Liveness) && !LiveOut.empty()) { |
| + Str << " // LiveOut:"; |
| + for (SizeT i = 0; i < LiveOut.size(); ++i) { |
| + if (LiveOut[i]) { |
| + Str << " %" << Liveness->getVariable(i, this)->getName(); |
| + } |
| + } |
| + Str << "\n"; |
| + } |
| // Dump list of successor nodes. |
| if (Func->getContext()->isVerbose(IceV_Succs)) { |
| Str << " // succs = "; |