aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/CodeGen/MachineSink.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/CodeGen/MachineSink.cpp')
-rw-r--r--contrib/llvm/lib/CodeGen/MachineSink.cpp376
1 files changed, 332 insertions, 44 deletions
diff --git a/contrib/llvm/lib/CodeGen/MachineSink.cpp b/contrib/llvm/lib/CodeGen/MachineSink.cpp
index bedfdd84b1ca..354f46e9e625 100644
--- a/contrib/llvm/lib/CodeGen/MachineSink.cpp
+++ b/contrib/llvm/lib/CodeGen/MachineSink.cpp
@@ -77,6 +77,7 @@ static cl::opt<unsigned> SplitEdgeProbabilityThreshold(
STATISTIC(NumSunk, "Number of machine instructions sunk");
STATISTIC(NumSplit, "Number of critical edges split");
STATISTIC(NumCoalesces, "Number of copies coalesced");
+STATISTIC(NumPostRACopySink, "Number of copies sunk after RA");
namespace {
@@ -138,7 +139,7 @@ namespace {
MachineBasicBlock *From,
MachineBasicBlock *To);
- /// \brief Postpone the splitting of the given critical
+ /// Postpone the splitting of the given critical
/// edge (\p From, \p To).
///
/// We do not split the edges on the fly. Indeed, this invalidates
@@ -210,8 +211,8 @@ bool MachineSinking::PerformTrivialForwardCoalescing(MachineInstr &MI,
MachineInstr *DefMI = MRI->getVRegDef(SrcReg);
if (DefMI->isCopyLike())
return false;
- DEBUG(dbgs() << "Coalescing: " << *DefMI);
- DEBUG(dbgs() << "*** to: " << MI);
+ LLVM_DEBUG(dbgs() << "Coalescing: " << *DefMI);
+ LLVM_DEBUG(dbgs() << "*** to: " << MI);
MRI->replaceRegWith(DstReg, SrcReg);
MI.eraseFromParent();
@@ -295,7 +296,7 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(MF.getFunction()))
return false;
- DEBUG(dbgs() << "******** Machine Sinking ********\n");
+ LLVM_DEBUG(dbgs() << "******** Machine Sinking ********\n");
TII = MF.getSubtarget().getInstrInfo();
TRI = MF.getSubtarget().getRegisterInfo();
@@ -322,14 +323,14 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) {
for (auto &Pair : ToSplit) {
auto NewSucc = Pair.first->SplitCriticalEdge(Pair.second, *this);
if (NewSucc != nullptr) {
- DEBUG(dbgs() << " *** Splitting critical edge: "
- << printMBBReference(*Pair.first) << " -- "
- << printMBBReference(*NewSucc) << " -- "
- << printMBBReference(*Pair.second) << '\n');
+ LLVM_DEBUG(dbgs() << " *** Splitting critical edge: "
+ << printMBBReference(*Pair.first) << " -- "
+ << printMBBReference(*NewSucc) << " -- "
+ << printMBBReference(*Pair.second) << '\n');
MadeChange = true;
++NumSplit;
} else
- DEBUG(dbgs() << " *** Not legal to break critical edge\n");
+ LLVM_DEBUG(dbgs() << " *** Not legal to break critical edge\n");
}
// If this iteration over the code changed anything, keep iterating.
if (!MadeChange) break;
@@ -371,7 +372,7 @@ bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) {
if (!ProcessedBegin)
--I;
- if (MI.isDebugValue())
+ if (MI.isDebugInstr())
continue;
bool Joined = PerformTrivialForwardCoalescing(MI, &MBB);
@@ -708,7 +709,7 @@ MachineSinking::FindSuccToSinkTo(MachineInstr &MI, MachineBasicBlock *MBB,
return SuccToSinkTo;
}
-/// \brief Return true if MI is likely to be usable as a memory operation by the
+/// Return true if MI is likely to be usable as a memory operation by the
/// implicit null check optimization.
///
/// This is a "best effort" heuristic, and should not be relied upon for
@@ -752,6 +753,37 @@ static bool SinkingPreventsImplicitNullCheck(MachineInstr &MI,
MBP.LHS.getReg() == BaseReg;
}
+/// Sink an instruction and its associated debug instructions.
+static void performSink(MachineInstr &MI, MachineBasicBlock &SuccToSinkTo,
+ MachineBasicBlock::iterator InsertPos) {
+ // Collect matching debug values.
+ SmallVector<MachineInstr *, 2> DbgValuesToSink;
+ collectDebugValues(MI, DbgValuesToSink);
+
+ // If we cannot find a location to use (merge with), then we erase the debug
+ // location to prevent debug-info driven tools from potentially reporting
+ // wrong location information.
+ if (!SuccToSinkTo.empty() && InsertPos != SuccToSinkTo.end())
+ MI.setDebugLoc(DILocation::getMergedLocation(MI.getDebugLoc(),
+ InsertPos->getDebugLoc()));
+ else
+ MI.setDebugLoc(DebugLoc());
+
+ // Move the instruction.
+ MachineBasicBlock *ParentBlock = MI.getParent();
+ SuccToSinkTo.splice(InsertPos, ParentBlock, MI,
+ ++MachineBasicBlock::iterator(MI));
+
+ // Move previously adjacent debug value instructions to the insert position.
+ for (SmallVectorImpl<MachineInstr *>::iterator DBI = DbgValuesToSink.begin(),
+ DBE = DbgValuesToSink.end();
+ DBI != DBE; ++DBI) {
+ MachineInstr *DbgMI = *DBI;
+ SuccToSinkTo.splice(InsertPos, ParentBlock, DbgMI,
+ ++MachineBasicBlock::iterator(DbgMI));
+ }
+}
+
/// SinkInstruction - Determine whether it is safe to sink the specified machine
/// instruction out of its current block into a successor.
bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
@@ -803,7 +835,7 @@ bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
return false;
}
- DEBUG(dbgs() << "Sink instr " << MI << "\tinto block " << *SuccToSinkTo);
+ LLVM_DEBUG(dbgs() << "Sink instr " << MI << "\tinto block " << *SuccToSinkTo);
// If the block has multiple predecessors, this is a critical edge.
// Decide if we can sink along it or need to break the edge.
@@ -813,26 +845,26 @@ bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
bool TryBreak = false;
bool store = true;
if (!MI.isSafeToMove(AA, store)) {
- DEBUG(dbgs() << " *** NOTE: Won't sink load along critical edge.\n");
+ LLVM_DEBUG(dbgs() << " *** NOTE: Won't sink load along critical edge.\n");
TryBreak = true;
}
// We don't want to sink across a critical edge if we don't dominate the
// successor. We could be introducing calculations to new code paths.
if (!TryBreak && !DT->dominates(ParentBlock, SuccToSinkTo)) {
- DEBUG(dbgs() << " *** NOTE: Critical edge found\n");
+ LLVM_DEBUG(dbgs() << " *** NOTE: Critical edge found\n");
TryBreak = true;
}
// Don't sink instructions into a loop.
if (!TryBreak && LI->isLoopHeader(SuccToSinkTo)) {
- DEBUG(dbgs() << " *** NOTE: Loop header found\n");
+ LLVM_DEBUG(dbgs() << " *** NOTE: Loop header found\n");
TryBreak = true;
}
// Otherwise we are OK with sinking along a critical edge.
if (!TryBreak)
- DEBUG(dbgs() << "Sinking along critical edge.\n");
+ LLVM_DEBUG(dbgs() << "Sinking along critical edge.\n");
else {
// Mark this edge as to be split.
// If the edge can actually be split, the next iteration of the main loop
@@ -840,8 +872,8 @@ bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
bool Status =
PostponeSplitCriticalEdge(MI, ParentBlock, SuccToSinkTo, BreakPHIEdge);
if (!Status)
- DEBUG(dbgs() << " *** PUNTING: Not legal or profitable to "
- "break critical edge\n");
+ LLVM_DEBUG(dbgs() << " *** PUNTING: Not legal or profitable to "
+ "break critical edge\n");
// The instruction will not be sunk this time.
return false;
}
@@ -854,8 +886,8 @@ bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
bool Status = PostponeSplitCriticalEdge(MI, ParentBlock,
SuccToSinkTo, BreakPHIEdge);
if (!Status)
- DEBUG(dbgs() << " *** PUNTING: Not legal or profitable to "
- "break critical edge\n");
+ LLVM_DEBUG(dbgs() << " *** PUNTING: Not legal or profitable to "
+ "break critical edge\n");
// The instruction will not be sunk this time.
return false;
}
@@ -865,30 +897,7 @@ bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
while (InsertPos != SuccToSinkTo->end() && InsertPos->isPHI())
++InsertPos;
- // collect matching debug values.
- SmallVector<MachineInstr *, 2> DbgValuesToSink;
- collectDebugValues(MI, DbgValuesToSink);
-
- // Merge or erase debug location to ensure consistent stepping in profilers
- // and debuggers.
- if (!SuccToSinkTo->empty() && InsertPos != SuccToSinkTo->end())
- MI.setDebugLoc(DILocation::getMergedLocation(MI.getDebugLoc(),
- InsertPos->getDebugLoc()));
- else
- MI.setDebugLoc(DebugLoc());
-
-
- // Move the instruction.
- SuccToSinkTo->splice(InsertPos, ParentBlock, MI,
- ++MachineBasicBlock::iterator(MI));
-
- // Move previously adjacent debug value instructions to the insert position.
- for (SmallVectorImpl<MachineInstr *>::iterator DBI = DbgValuesToSink.begin(),
- DBE = DbgValuesToSink.end(); DBI != DBE; ++DBI) {
- MachineInstr *DbgMI = *DBI;
- SuccToSinkTo->splice(InsertPos, ParentBlock, DbgMI,
- ++MachineBasicBlock::iterator(DbgMI));
- }
+ performSink(MI, *SuccToSinkTo, InsertPos);
// Conservatively, clear any kill flags, since it's possible that they are no
// longer correct.
@@ -902,3 +911,282 @@ bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
return true;
}
+
+//===----------------------------------------------------------------------===//
+// This pass is not intended to be a replacement or a complete alternative
+// for the pre-ra machine sink pass. It is only designed to sink COPY
+// instructions which should be handled after RA.
+//
+// This pass sinks COPY instructions into a successor block, if the COPY is not
+// used in the current block and the COPY is live-in to a single successor
+// (i.e., doesn't require the COPY to be duplicated). This avoids executing the
+// copy on paths where their results aren't needed. This also exposes
+// additional opportunites for dead copy elimination and shrink wrapping.
+//
+// These copies were either not handled by or are inserted after the MachineSink
+// pass. As an example of the former case, the MachineSink pass cannot sink
+// COPY instructions with allocatable source registers; for AArch64 these type
+// of copy instructions are frequently used to move function parameters (PhyReg)
+// into virtual registers in the entry block.
+//
+// For the machine IR below, this pass will sink %w19 in the entry into its
+// successor (%bb.1) because %w19 is only live-in in %bb.1.
+// %bb.0:
+// %wzr = SUBSWri %w1, 1
+// %w19 = COPY %w0
+// Bcc 11, %bb.2
+// %bb.1:
+// Live Ins: %w19
+// BL @fun
+// %w0 = ADDWrr %w0, %w19
+// RET %w0
+// %bb.2:
+// %w0 = COPY %wzr
+// RET %w0
+// As we sink %w19 (CSR in AArch64) into %bb.1, the shrink-wrapping pass will be
+// able to see %bb.0 as a candidate.
+//===----------------------------------------------------------------------===//
+namespace {
+
+class PostRAMachineSinking : public MachineFunctionPass {
+public:
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ static char ID;
+ PostRAMachineSinking() : MachineFunctionPass(ID) {}
+ StringRef getPassName() const override { return "PostRA Machine Sink"; }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
+ MachineFunctionProperties getRequiredProperties() const override {
+ return MachineFunctionProperties().set(
+ MachineFunctionProperties::Property::NoVRegs);
+ }
+
+private:
+ /// Track which register units have been modified and used.
+ LiveRegUnits ModifiedRegUnits, UsedRegUnits;
+
+ /// Sink Copy instructions unused in the same block close to their uses in
+ /// successors.
+ bool tryToSinkCopy(MachineBasicBlock &BB, MachineFunction &MF,
+ const TargetRegisterInfo *TRI, const TargetInstrInfo *TII);
+};
+} // namespace
+
+char PostRAMachineSinking::ID = 0;
+char &llvm::PostRAMachineSinkingID = PostRAMachineSinking::ID;
+
+INITIALIZE_PASS(PostRAMachineSinking, "postra-machine-sink",
+ "PostRA Machine Sink", false, false)
+
+static bool aliasWithRegsInLiveIn(MachineBasicBlock &MBB, unsigned Reg,
+ const TargetRegisterInfo *TRI) {
+ LiveRegUnits LiveInRegUnits(*TRI);
+ LiveInRegUnits.addLiveIns(MBB);
+ return !LiveInRegUnits.available(Reg);
+}
+
+static MachineBasicBlock *
+getSingleLiveInSuccBB(MachineBasicBlock &CurBB,
+ const SmallPtrSetImpl<MachineBasicBlock *> &SinkableBBs,
+ unsigned Reg, const TargetRegisterInfo *TRI) {
+ // Try to find a single sinkable successor in which Reg is live-in.
+ MachineBasicBlock *BB = nullptr;
+ for (auto *SI : SinkableBBs) {
+ if (aliasWithRegsInLiveIn(*SI, Reg, TRI)) {
+ // If BB is set here, Reg is live-in to at least two sinkable successors,
+ // so quit.
+ if (BB)
+ return nullptr;
+ BB = SI;
+ }
+ }
+ // Reg is not live-in to any sinkable successors.
+ if (!BB)
+ return nullptr;
+
+ // Check if any register aliased with Reg is live-in in other successors.
+ for (auto *SI : CurBB.successors()) {
+ if (!SinkableBBs.count(SI) && aliasWithRegsInLiveIn(*SI, Reg, TRI))
+ return nullptr;
+ }
+ return BB;
+}
+
+static MachineBasicBlock *
+getSingleLiveInSuccBB(MachineBasicBlock &CurBB,
+ const SmallPtrSetImpl<MachineBasicBlock *> &SinkableBBs,
+ ArrayRef<unsigned> DefedRegsInCopy,
+ const TargetRegisterInfo *TRI) {
+ MachineBasicBlock *SingleBB = nullptr;
+ for (auto DefReg : DefedRegsInCopy) {
+ MachineBasicBlock *BB =
+ getSingleLiveInSuccBB(CurBB, SinkableBBs, DefReg, TRI);
+ if (!BB || (SingleBB && SingleBB != BB))
+ return nullptr;
+ SingleBB = BB;
+ }
+ return SingleBB;
+}
+
+static void clearKillFlags(MachineInstr *MI, MachineBasicBlock &CurBB,
+ SmallVectorImpl<unsigned> &UsedOpsInCopy,
+ LiveRegUnits &UsedRegUnits,
+ const TargetRegisterInfo *TRI) {
+ for (auto U : UsedOpsInCopy) {
+ MachineOperand &MO = MI->getOperand(U);
+ unsigned SrcReg = MO.getReg();
+ if (!UsedRegUnits.available(SrcReg)) {
+ MachineBasicBlock::iterator NI = std::next(MI->getIterator());
+ for (MachineInstr &UI : make_range(NI, CurBB.end())) {
+ if (UI.killsRegister(SrcReg, TRI)) {
+ UI.clearRegisterKills(SrcReg, TRI);
+ MO.setIsKill(true);
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void updateLiveIn(MachineInstr *MI, MachineBasicBlock *SuccBB,
+ SmallVectorImpl<unsigned> &UsedOpsInCopy,
+ SmallVectorImpl<unsigned> &DefedRegsInCopy) {
+ for (auto DefReg : DefedRegsInCopy)
+ SuccBB->removeLiveIn(DefReg);
+ for (auto U : UsedOpsInCopy) {
+ unsigned Reg = MI->getOperand(U).getReg();
+ if (!SuccBB->isLiveIn(Reg))
+ SuccBB->addLiveIn(Reg);
+ }
+}
+
+static bool hasRegisterDependency(MachineInstr *MI,
+ SmallVectorImpl<unsigned> &UsedOpsInCopy,
+ SmallVectorImpl<unsigned> &DefedRegsInCopy,
+ LiveRegUnits &ModifiedRegUnits,
+ LiveRegUnits &UsedRegUnits) {
+ bool HasRegDependency = false;
+ for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
+ MachineOperand &MO = MI->getOperand(i);
+ if (!MO.isReg())
+ continue;
+ unsigned Reg = MO.getReg();
+ if (!Reg)
+ continue;
+ if (MO.isDef()) {
+ if (!ModifiedRegUnits.available(Reg) || !UsedRegUnits.available(Reg)) {
+ HasRegDependency = true;
+ break;
+ }
+ DefedRegsInCopy.push_back(Reg);
+
+ // FIXME: instead of isUse(), readsReg() would be a better fix here,
+ // For example, we can ignore modifications in reg with undef. However,
+ // it's not perfectly clear if skipping the internal read is safe in all
+ // other targets.
+ } else if (MO.isUse()) {
+ if (!ModifiedRegUnits.available(Reg)) {
+ HasRegDependency = true;
+ break;
+ }
+ UsedOpsInCopy.push_back(i);
+ }
+ }
+ return HasRegDependency;
+}
+
+bool PostRAMachineSinking::tryToSinkCopy(MachineBasicBlock &CurBB,
+ MachineFunction &MF,
+ const TargetRegisterInfo *TRI,
+ const TargetInstrInfo *TII) {
+ SmallPtrSet<MachineBasicBlock *, 2> SinkableBBs;
+ // FIXME: For now, we sink only to a successor which has a single predecessor
+ // so that we can directly sink COPY instructions to the successor without
+ // adding any new block or branch instruction.
+ for (MachineBasicBlock *SI : CurBB.successors())
+ if (!SI->livein_empty() && SI->pred_size() == 1)
+ SinkableBBs.insert(SI);
+
+ if (SinkableBBs.empty())
+ return false;
+
+ bool Changed = false;
+
+ // Track which registers have been modified and used between the end of the
+ // block and the current instruction.
+ ModifiedRegUnits.clear();
+ UsedRegUnits.clear();
+
+ for (auto I = CurBB.rbegin(), E = CurBB.rend(); I != E;) {
+ MachineInstr *MI = &*I;
+ ++I;
+
+ if (MI->isDebugInstr())
+ continue;
+
+ // Do not move any instruction across function call.
+ if (MI->isCall())
+ return false;
+
+ if (!MI->isCopy() || !MI->getOperand(0).isRenamable()) {
+ LiveRegUnits::accumulateUsedDefed(*MI, ModifiedRegUnits, UsedRegUnits,
+ TRI);
+ continue;
+ }
+
+ // Track the operand index for use in Copy.
+ SmallVector<unsigned, 2> UsedOpsInCopy;
+ // Track the register number defed in Copy.
+ SmallVector<unsigned, 2> DefedRegsInCopy;
+
+ // Don't sink the COPY if it would violate a register dependency.
+ if (hasRegisterDependency(MI, UsedOpsInCopy, DefedRegsInCopy,
+ ModifiedRegUnits, UsedRegUnits)) {
+ LiveRegUnits::accumulateUsedDefed(*MI, ModifiedRegUnits, UsedRegUnits,
+ TRI);
+ continue;
+ }
+ assert((!UsedOpsInCopy.empty() && !DefedRegsInCopy.empty()) &&
+ "Unexpect SrcReg or DefReg");
+ MachineBasicBlock *SuccBB =
+ getSingleLiveInSuccBB(CurBB, SinkableBBs, DefedRegsInCopy, TRI);
+ // Don't sink if we cannot find a single sinkable successor in which Reg
+ // is live-in.
+ if (!SuccBB) {
+ LiveRegUnits::accumulateUsedDefed(*MI, ModifiedRegUnits, UsedRegUnits,
+ TRI);
+ continue;
+ }
+ assert((SuccBB->pred_size() == 1 && *SuccBB->pred_begin() == &CurBB) &&
+ "Unexpected predecessor");
+
+ // Clear the kill flag if SrcReg is killed between MI and the end of the
+ // block.
+ clearKillFlags(MI, CurBB, UsedOpsInCopy, UsedRegUnits, TRI);
+ MachineBasicBlock::iterator InsertPos = SuccBB->getFirstNonPHI();
+ performSink(*MI, *SuccBB, InsertPos);
+ updateLiveIn(MI, SuccBB, UsedOpsInCopy, DefedRegsInCopy);
+
+ Changed = true;
+ ++NumPostRACopySink;
+ }
+ return Changed;
+}
+
+bool PostRAMachineSinking::runOnMachineFunction(MachineFunction &MF) {
+ bool Changed = false;
+ const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+
+ ModifiedRegUnits.init(*TRI);
+ UsedRegUnits.init(*TRI);
+ for (auto &BB : MF)
+ Changed |= tryToSinkCopy(BB, MF, TRI, TII);
+
+ return Changed;
+}