Index: src/IceTargetLowering.cpp |
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp |
index 1b9ca23bfe49eb96b1bc0dcc5ad38d72965c9adf..eafce5bc32813217ba58b034e1b077fffac9b3f2 100644 |
--- a/src/IceTargetLowering.cpp |
+++ b/src/IceTargetLowering.cpp |
@@ -24,6 +24,7 @@ |
#include "IceGlobalContext.h" |
#include "IceGlobalInits.h" |
#include "IceInstVarIter.h" |
+#include "IceLiveness.h" |
#include "IceOperand.h" |
#include "IceRegAlloc.h" |
@@ -511,6 +512,175 @@ void TargetLowering::regAlloc(RegAllocKind Kind) { |
// set of Variables that have no register and a non-empty live range, and |
// model an infinite number of registers. Maybe use the register aliasing |
// mechanism to get better packing of narrower slots. |
+ if (getFlags().getSplitGlobalVars()) |
+ postRegallocSplitting(RegMask); |
+} |
+ |
+namespace { |
+CfgVector<Inst *> getInstructionsInRange(CfgNode *Node, InstNumberT Start, |
+ InstNumberT End) { |
+ CfgVector<Inst *> Result; |
+ bool Started = false; |
+ auto Process = [&](InstList &Insts) { |
+ for (auto &Instr : Insts) { |
+ if (Instr.isDeleted()) { |
+ continue; |
+ } |
+ if (Instr.getNumber() == Start) { |
+ Started = true; |
+ } |
+ if (Started) { |
+ Result.push_back(&Instr); |
Jim Stichnoth
2016/08/02 05:57:50
emplace_back ?
manasijm
2016/08/02 21:41:59
Done.
|
+ } |
+ if (Instr.getNumber() == End) { |
Jim Stichnoth
2016/08/02 05:57:50
Can this be ">=", just to be safe? just in case t
manasijm
2016/08/02 21:41:59
That seems to result in missing a lot of opportuni
|
+ break; |
+ } |
+ } |
+ }; |
+ Process(Node->getPhis()); |
+ Process(Node->getInsts()); |
+ return Result; |
+} |
+} |
Jim Stichnoth
2016/08/02 05:57:50
add blank line afterwards
manasijm
2016/08/02 21:41:59
Done.
|
+void TargetLowering::postRegallocSplitting(const SmallBitVector &RegMask) { |
+ // Splits the live ranges of global(/multi block) variables and runs the |
+ // register allocator to find registers for as many of the new variables as |
+ // possible. |
+ // TODO(manasijm): Merge the small liveranges back into multi-block ones when |
+ // the variables get the same register. This will reduce the amount of new |
+ // instructions inserted. This might involve a full dataflow analysis. |
+ // Also, modify the preference mechanism in the register allocator to match. |
+ |
+ TimerMarker _(TimerStack::TT_splitGlobalVars, Func); |
+ CfgSet<Variable *> SplitCandidates; |
+ |
+ // Find variables that does not have registers but are allowed to. Also skip |
Jim Stichnoth
2016/08/02 05:57:50
that do not
manasijm
2016/08/02 21:41:59
Done.
|
+ // variables with single segment live ranges as they are not split further in |
+ // this function. |
+ for (Variable *Var : Func->getVariables()) { |
+ if (!Var->mustNotHaveReg() && !Var->hasReg()) { |
+ if (Var->getLiveRange().getNumSegments() > 1) |
+ SplitCandidates.insert(Var); |
+ } |
+ } |
+ if (SplitCandidates.empty()) |
+ return; |
+ |
+ CfgSet<Variable *> ExtraVars; |
+ |
+ struct UseInfo { |
+ Variable *Replacing = nullptr; |
+ Inst *FirstUse = nullptr; |
+ Inst *LastDef = nullptr; |
+ SizeT UseCount = 0; |
+ }; |
+ CfgUnorderedMap<Variable *, UseInfo> VarInfo; |
+ // Split the live ranges of the viable variables by node. |
+ // Compute metadata (UseInfo) for each of the resulting variables. |
+ for (auto *Var : SplitCandidates) { |
+ for (auto &Segment : Var->getLiveRange().getSegments()) { |
+ UseInfo Info; |
+ Info.Replacing = Var; |
+ auto *Node = Var->getLiveRange().getNodeForSegment(Segment.first); |
+ |
+ for (auto *Instr : |
+ getInstructionsInRange(Node, Segment.first, Segment.second)) { |
+ for (SizeT i = 0; i < Instr->getSrcSize(); ++i) { |
+ for (SizeT j = 0; j < Instr->getSrc(i)->getNumVars(); ++j) { |
Jim Stichnoth
2016/08/02 05:57:50
For local variable splitting, I made the assumptio
manasijm
2016/08/02 21:41:59
Done.
|
+ auto *Var = Instr->getSrc(i)->getVar(j); |
+ if (Var == Info.Replacing) { |
+ if (Info.FirstUse == nullptr && !llvm::isa<InstPhi>(Instr)) { |
+ Info.FirstUse = Instr; |
+ } |
+ Info.UseCount++; |
+ } |
+ } |
+ } |
+ if (Instr->getDest() == Info.Replacing && !llvm::isa<InstPhi>(Instr)) { |
Jim Stichnoth
2016/08/02 05:57:50
It looks like Phi instructions are not considered
manasijm
2016/08/02 21:41:59
Done.
Jim Stichnoth
2016/08/04 01:59:17
I don't see any new comment or TODO on this issue?
|
+ Info.LastDef = Instr; |
+ } |
+ } |
+ |
+ static constexpr SizeT MinUseThreshold = 3; |
+ // Skip if variable has less than `MinUseThreshold` uses in the segment. |
+ if (Info.UseCount < MinUseThreshold) |
+ continue; |
+ |
+ if (!Info.FirstUse && !Info.LastDef) { |
+ continue; |
+ } |
+ |
+ LiveRange LR; |
+ LR.addSegment(Segment); |
+ Variable *NewVar = Func->makeVariable(Var->getType()); |
+ |
+ NewVar->setLiveRange(LR); |
+ |
+ VarInfo[NewVar] = Info; |
+ |
+ ExtraVars.insert(NewVar); |
+ } |
+ } |
+ // Run the register allocator with all these new variables included |
+ LinearScan RegAlloc(Func); |
+ RegAlloc.init(RAK_Global, SplitCandidates); |
+ RegAlloc.scan(RegMask, getFlags().getRandomizeRegisterAllocation()); |
+ |
+ // Modify the Cfg to use the new variables that now now have registers. |
Jim Stichnoth
2016/08/02 05:57:50
now now
manasijm
2016/08/02 21:41:59
Done.
|
+ for (auto *ExtraVar : ExtraVars) { |
+ if (!ExtraVar->hasReg()) { |
+ continue; |
+ } |
+ |
+ auto &Info = VarInfo[ExtraVar]; |
+ |
+ assert(ExtraVar->getLiveRange().getSegments().size() == 1); |
+ auto Segment = ExtraVar->getLiveRange().getSegments()[0]; |
+ |
+ auto *Node = |
+ Info.Replacing->getLiveRange().getNodeForSegment(Segment.first); |
+ |
+ auto RelevantInsts = |
+ getInstructionsInRange(Node, Segment.first, Segment.second); |
+ |
+ if (RelevantInsts.empty()) |
+ continue; |
+ |
+ // Replace old variables |
+ for (auto *Instr : RelevantInsts) { |
+ if (llvm::isa<InstPhi>(Instr)) |
+ continue; |
+ for (SizeT i = 0; i < Instr->getSrcSize(); ++i) { |
+ // It's safe to iterate over the top-level src operands rather than |
+ // using |
+ // FOREACH_VAR_IN_INST(), because any variables inside e.g. mem operands |
+ // should already have registers. |
+ if (auto *Var = llvm::dyn_cast<Variable>(Instr->getSrc(i))) { |
+ if (Var == Info.Replacing) { |
+ Instr->replaceSource(i, ExtraVar); |
+ } |
+ } |
+ } |
+ if (Instr->getDest() == Info.Replacing) { |
+ Instr->replaceDest(ExtraVar); |
+ } |
+ } |
+ |
+ assert(Info.FirstUse != Info.LastDef); |
+ assert(Info.FirstUse || Info.LastDef); |
+ |
+ // Insert spill code |
+ if (Info.FirstUse != nullptr) { |
+ auto *NewInst = |
+ Func->getTarget()->createLoweredMove(ExtraVar, Info.Replacing); |
+ Node->getInsts().insert(instToIterator(Info.FirstUse), NewInst); |
+ } |
+ if (Info.LastDef != nullptr) { |
+ auto *NewInst = |
+ Func->getTarget()->createLoweredMove(Info.Replacing, ExtraVar); |
+ Node->getInsts().insertAfter(instToIterator(Info.LastDef), NewInst); |
+ } |
+ } |
} |
void TargetLowering::markRedefinitions() { |