Chromium Code Reviews| Index: src/IceInst.cpp |
| diff --git a/src/IceInst.cpp b/src/IceInst.cpp |
| index 3f0c97dedb9f21a88bc123da84a256d76c41e03d..e866940cc17980debf394888d2c2f82cdd93437c 100644 |
| --- a/src/IceInst.cpp |
| +++ b/src/IceInst.cpp |
| @@ -15,6 +15,7 @@ |
| #include "IceCfg.h" |
| #include "IceCfgNode.h" |
| #include "IceInst.h" |
| +#include "IceLiveness.h" |
| #include "IceOperand.h" |
| namespace Ice { |
| @@ -74,9 +75,47 @@ const size_t InstIcmpAttributesSize = llvm::array_lengthof(InstIcmpAttributes); |
| } // end of anonymous namespace |
| Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
| - : Kind(Kind), Number(Func->newInstNumber()), Deleted(false), |
| + : Kind(Kind), Number(Func->newInstNumber()), Deleted(false), Dead(false), |
| HasSideEffects(false), Dest(Dest), MaxSrcs(MaxSrcs), NumSrcs(0), |
| - Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)) {} |
| + Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)), LiveRangesEnded(0) {} |
| + |
| +// Assign the instruction a new number. |
| +void Inst::renumber(Cfg *Func) { |
| + Number = isDeleted() ? -1 : Func->newInstNumber(); |
| +} |
| + |
| +// Delete the instruction if its tentative Dead flag is still set |
| +// after liveness analysis. |
| +void Inst::deleteIfDead() { |
| + if (Dead) |
| + setDeleted(); |
| +} |
| + |
| +// If Src is an Variable, it returns true if this instruction ends |
|
jvoung (off chromium)
2014/05/28 17:48:15
"is a Variable"?
Jim Stichnoth
2014/05/29 01:39:46
Fixed this and several other instances. :) (This
|
| +// Src's live range. Otherwise, returns false. |
| +bool Inst::isLastUse(const Operand *TestSrc) const { |
| + if (LiveRangesEnded == 0) |
| + return false; // early-exit optimization |
| + if (const Variable *TestVar = llvm::dyn_cast<const Variable>(TestSrc)) { |
| + SizeT VarIndex = 0; |
|
jvoung (off chromium)
2014/05/28 17:48:15
VarIndex unused here (just incremented)? Looks lik
Jim Stichnoth
2014/05/29 01:39:46
Done.
|
| + SizeT Mask = LiveRangesEnded; |
|
JF
2014/05/25 22:50:50
You should use the same typedef for LiveRangesEnde
Jim Stichnoth
2014/05/29 01:39:46
Done.
|
| + for (SizeT I = 0; I < getSrcSize(); ++I) { |
| + Operand *Src = getSrc(I); |
| + SizeT NumVars = Src->getNumVars(); |
| + for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
| + const Variable *Var = Src->getVar(J); |
| + if (Var == TestVar) { |
| + // We've found where the variable is used in the instruction. |
| + return Mask & 1; |
| + } |
| + Mask >>= 1; |
| + if (Mask == 0) |
| + return false; // another early-exit optimization |
| + } |
| + } |
| + } |
| + return false; |
| +} |
| void Inst::updateVars(CfgNode *Node) { |
| if (Dest) |
| @@ -93,6 +132,90 @@ void Inst::updateVars(CfgNode *Node) { |
| } |
| } |
| +void Inst::liveness(LivenessMode Mode, int32_t InstNumber, |
| + llvm::BitVector &Live, Liveness *Liveness, |
| + const CfgNode *Node) { |
| + if (isDeleted()) |
| + return; |
| + if (llvm::isa<InstFakeKill>(this)) |
| + return; |
| + |
| + // For lightweight liveness, do the simple calculation and return. |
| + if (Mode == Liveness_LREndLightweight) { |
| + resetLastUses(); |
| + SizeT VarIndex = 0; |
| + for (SizeT I = 0; I < getSrcSize(); ++I) { |
| + Operand *Src = getSrc(I); |
| + SizeT NumVars = Src->getNumVars(); |
| + for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
| + const Variable *Var = Src->getVar(J); |
| + if (Var->isMultiblockLife()) |
| + continue; |
| + SizeT Index = Var->getIndex(); |
| + if (Live[Index]) |
| + continue; |
| + Live[Index] = true; |
| + setLastUse(VarIndex); |
|
jvoung (off chromium)
2014/05/28 17:48:15
I see... so VarIndex is an optimized, different nu
Jim Stichnoth
2014/05/29 01:39:46
OK, it looks like I never properly documented VarI
|
| + } |
| + } |
| + return; |
| + } |
| + |
| + std::vector<int32_t> &LiveBegin = Liveness->getLiveBegin(Node); |
| + std::vector<int32_t> &LiveEnd = Liveness->getLiveEnd(Node); |
| + Dead = false; |
| + if (Dest) { |
| + SizeT VarNum = Liveness->getLiveIndex(Dest); |
| + if (Live[VarNum]) { |
| + Live[VarNum] = false; |
| + LiveBegin[VarNum] = InstNumber; |
| + } else { |
| + if (!hasSideEffects()) |
| + Dead = true; |
| + } |
| + } |
| + if (Dead) |
| + return; |
| + // Phi arguments only get added to Live in the predecessor node, but |
| + // we still need to update LiveRangesEnded. |
| + bool IsPhi = llvm::isa<InstPhi>(this); |
| + resetLastUses(); |
| + SizeT VarIndex = 0; |
| + for (SizeT I = 0; I < getSrcSize(); ++I) { |
| + Operand *Src = getSrc(I); |
| + SizeT NumVars = Src->getNumVars(); |
| + for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
| + const Variable *Var = Src->getVar(J); |
| + SizeT VarNum = Liveness->getLiveIndex(Var); |
| + if (!Live[VarNum]) { |
| + setLastUse(VarIndex); |
| + if (!IsPhi) { |
| + Live[VarNum] = true; |
| + // For a variable in SSA form, its live range can end at |
| + // most once in a basic block. However, after lowering to |
| + // two-address instructions, we end up with sequences like |
| + // "t=b;t+=c;a=t" where t's live range begins and ends |
| + // twice. ICE only allows a variable to have a single |
| + // liveness interval in a basic block (except for blocks |
| + // where a variable is live-in and live-out but there is a |
| + // gap in the middle, and except for the special |
| + // InstFakeKill instruction that can appear multiple |
| + // times in the same block). Therefore, this lowered |
| + // sequence needs to represent a single conservative live |
| + // range for t. Since the instructions are being traversed |
| + // backwards, we make sure LiveEnd is only set once by |
| + // setting it only when LiveEnd[VarNum]==0 (sentinel value). |
| + // Note that it's OK to set LiveBegin multiple times because |
| + // of the backwards traversal. |
| + if (LiveEnd[VarNum] == 0) { |
| + LiveEnd[VarNum] = InstNumber; |
| + } |
| + } |
| + } |
| + } |
| + } |
| +} |
| + |
| InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, |
| Variable *Dest) |
| : Inst(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) { |
| @@ -192,6 +315,28 @@ Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { |
| return NULL; |
| } |
| +// Updates liveness for a particular operand based on the given |
| +// predecessor edge. Doesn't mark the operand as live if the Phi |
| +// instruction is dead or deleted. |
| +void InstPhi::livenessPhiOperand(llvm::BitVector &Live, CfgNode *Target, |
| + Liveness *Liveness) { |
| + if (isDeleted() || Dead) |
| + return; |
| + for (SizeT I = 0; I < getSrcSize(); ++I) { |
| + if (Labels[I] == Target) { |
| + if (Variable *Var = llvm::dyn_cast<Variable>(getSrc(I))) { |
| + SizeT SrcIndex = Liveness->getLiveIndex(Var); |
| + if (!Live[SrcIndex]) { |
| + setLastUse(I); |
| + Live[SrcIndex] = true; |
| + } |
| + } |
| + return; |
| + } |
| + } |
| + llvm_unreachable("Phi operand not found for specified target node"); |
| +} |
| + |
| // Change "a=phi(...)" to "a_phi=phi(...)" and return a new |
| // instruction "a=a_phi". |
| Inst *InstPhi::lower(Cfg *Func, CfgNode *Node) { |
| @@ -305,6 +450,7 @@ void Inst::dumpDecorated(const Cfg *Func) const { |
| if (isDeleted()) |
| Str << " //"; |
| dump(Func); |
| + dumpExtras(Func); |
| Str << "\n"; |
| } |
| @@ -319,6 +465,33 @@ void Inst::dump(const Cfg *Func) const { |
| dumpSources(Func); |
| } |
| +void Inst::dumpExtras(const Cfg *Func) const { |
| + Ostream &Str = Func->getContext()->getStrDump(); |
| + bool First = true; |
| + // Print "LIVEEND={a,b,c}" for all source operands whose live ranges |
| + // are known to end at this instruction. |
| + if (Func->getContext()->isVerbose(IceV_Liveness)) { |
| + SizeT VarIndex = 0; |
|
jvoung (off chromium)
2014/05/28 17:48:15
VarIndex unused?
Jim Stichnoth
2014/05/29 01:39:46
Done.
|
| + for (SizeT I = 0; I < getSrcSize(); ++I) { |
| + Operand *Src = getSrc(I); |
| + SizeT NumVars = Src->getNumVars(); |
| + for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
| + const Variable *Var = Src->getVar(J); |
| + if (isLastUse(Var)) { |
| + if (First) |
| + Str << " // LIVEEND={"; |
| + else |
| + Str << ","; |
| + Var->dump(Func); |
| + First = false; |
| + } |
| + } |
| + } |
| + if (!First) |
| + Str << "}"; |
| + } |
| +} |
| + |
| void Inst::dumpSources(const Cfg *Func) const { |
| Ostream &Str = Func->getContext()->getStrDump(); |
| for (SizeT I = 0; I < getSrcSize(); ++I) { |
| @@ -553,4 +726,6 @@ void InstTarget::dump(const Cfg *Func) const { |
| Inst::dump(Func); |
| } |
| +void InstTarget::dumpExtras(const Cfg *Func) const { Inst::dumpExtras(Func); } |
| + |
| } // end of namespace Ice |