Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Unified Diff: src/IceTargetLowering.cpp

Issue 2172313002: Subzero : Live Range Splitting after initial Register Allocation (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Format Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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() {

Powered by Google App Engine
This is Rietveld 408576698