Index: src/IceInst.cpp |
diff --git a/src/IceInst.cpp b/src/IceInst.cpp |
index 3f0c97dedb9f21a88bc123da84a256d76c41e03d..b282d03a099cf9922c07f07724a3ef8e357fa8e3 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,25 +75,146 @@ 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 a Variable, it returns true if this instruction ends |
+// 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)) { |
+ LREndedBits Mask = LiveRangesEnded; |
+ for (SizeT I = 0; I < getSrcSize(); ++I) { |
+ Operand *Src = getSrc(I); |
+ SizeT NumVars = Src->getNumVars(); |
+ for (SizeT J = 0; J < NumVars; ++J) { |
+ 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) |
Dest->setDefinition(this, Node); |
- 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) { |
+ for (SizeT J = 0; J < NumVars; ++J) { |
Variable *Var = Src->getVar(J); |
Var->setUse(this, Node); |
} |
} |
} |
+void Inst::livenessLightweight(llvm::BitVector &Live) { |
+ if (isDeleted()) |
+ return; |
+ if (llvm::isa<InstFakeKill>(this)) |
+ return; |
+ 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); |
+ } |
+ } |
+} |
+ |
+void Inst::liveness(int32_t InstNumber, llvm::BitVector &Live, |
+ Liveness *Liveness, const CfgNode *Node) { |
+ if (isDeleted()) |
+ return; |
+ if (llvm::isa<InstFakeKill>(this)) |
+ 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 +314,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 +449,7 @@ void Inst::dumpDecorated(const Cfg *Func) const { |
if (isDeleted()) |
Str << " //"; |
dump(Func); |
+ dumpExtras(Func); |
Str << "\n"; |
} |
@@ -319,6 +464,32 @@ 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)) { |
+ for (SizeT I = 0; I < getSrcSize(); ++I) { |
+ Operand *Src = getSrc(I); |
+ SizeT NumVars = Src->getNumVars(); |
+ for (SizeT J = 0; J < NumVars; ++J) { |
+ 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 +724,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 |