summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r--llvm/lib/CodeGen/CodeGen.cpp1
-rw-r--r--llvm/lib/CodeGen/MachineSink.cpp188
-rw-r--r--llvm/lib/CodeGen/TargetInstrInfo.cpp27
-rw-r--r--llvm/lib/CodeGen/TargetPassConfig.cpp10
4 files changed, 225 insertions, 1 deletions
diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index a268dc509e5..51f7e0c87cd 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -76,6 +76,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
initializePeepholeOptimizerPass(Registry);
initializePostMachineSchedulerPass(Registry);
initializePostRAHazardRecognizerPass(Registry);
+ initializePostRAMachineSinkingPass(Registry);
initializePostRASchedulerPass(Registry);
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
initializeProcessImplicitDefsPass(Registry);
diff --git a/llvm/lib/CodeGen/MachineSink.cpp b/llvm/lib/CodeGen/MachineSink.cpp
index bedfdd84b1c..97ddce3e9d2 100644
--- a/llvm/lib/CodeGen/MachineSink.cpp
+++ b/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 {
@@ -902,3 +903,190 @@ 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"; }
+
+private:
+ /// Track which registers have been modified and used.
+ BitVector ModifiedRegs, UsedRegs;
+
+ /// 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 MachineBasicBlock *
+getSingleLiveInSuccBB(MachineBasicBlock &CurBB,
+ ArrayRef<MachineBasicBlock *> SinkableBBs, unsigned Reg,
+ const TargetRegisterInfo *TRI) {
+ SmallSet<unsigned, 8> AliasedRegs;
+ for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
+ AliasedRegs.insert(*AI);
+
+ // Try to find a single sinkable successor in which Reg is live-in.
+ MachineBasicBlock *BB = nullptr;
+ for (auto *SI : SinkableBBs) {
+ if (SI->isLiveIn(Reg)) {
+ // 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 (SI == BB)
+ continue;
+ for (const auto LI : SI->liveins())
+ if (AliasedRegs.count(LI.PhysReg))
+ return nullptr;
+ }
+ return BB;
+}
+
+bool PostRAMachineSinking::tryToSinkCopy(MachineBasicBlock &CurBB,
+ MachineFunction &MF,
+ const TargetRegisterInfo *TRI,
+ const TargetInstrInfo *TII) {
+ SmallVector<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.push_back(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.
+ ModifiedRegs.reset();
+ UsedRegs.reset();
+
+ for (auto I = CurBB.rbegin(), E = CurBB.rend(); I != E;) {
+ MachineInstr *MI = &*I;
+ ++I;
+
+ // Do not move any instruction across function call.
+ if (MI->isCall())
+ return false;
+
+ if (!MI->isCopy() || !MI->getOperand(0).isRenamable()) {
+ TII->trackRegDefsUses(*MI, ModifiedRegs, UsedRegs, TRI);
+ continue;
+ }
+
+ unsigned DefReg = MI->getOperand(0).getReg();
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ // Don't sink the COPY if it would violate a register dependency.
+ if (ModifiedRegs[DefReg] || ModifiedRegs[SrcReg] || UsedRegs[DefReg]) {
+ TII->trackRegDefsUses(*MI, ModifiedRegs, UsedRegs, TRI);
+ continue;
+ }
+
+ MachineBasicBlock *SuccBB =
+ getSingleLiveInSuccBB(CurBB, SinkableBBs, DefReg, TRI);
+ // Don't sink if we cannot find a single sinkable successor in which Reg
+ // is live-in.
+ if (!SuccBB) {
+ TII->trackRegDefsUses(*MI, ModifiedRegs, UsedRegs, 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.
+ if (UsedRegs[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);
+ MI->getOperand(1).setIsKill(true);
+ break;
+ }
+ }
+ }
+
+ MachineBasicBlock::iterator InsertPos = SuccBB->getFirstNonPHI();
+ SuccBB->splice(InsertPos, &CurBB, MI);
+ SuccBB->removeLiveIn(DefReg);
+ if (!SuccBB->isLiveIn(SrcReg))
+ SuccBB->addLiveIn(SrcReg);
+
+ 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();
+ ModifiedRegs.resize(TRI->getNumRegs());
+ UsedRegs.resize(TRI->getNumRegs());
+
+ for (auto &BB : MF)
+ Changed |= tryToSinkCopy(BB, MF, TRI, TII);
+
+ return Changed;
+}
diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp
index 963f8178b50..ea06b266b99 100644
--- a/llvm/lib/CodeGen/TargetInstrInfo.cpp
+++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp
@@ -882,6 +882,33 @@ void TargetInstrInfo::genAlternativeCodeSequence(
reassociateOps(Root, *Prev, Pattern, InsInstrs, DelInstrs, InstIdxForVirtReg);
}
+void TargetInstrInfo::trackRegDefsUses(const MachineInstr &MI,
+ BitVector &ModifiedRegs,
+ BitVector &UsedRegs,
+ const TargetRegisterInfo *TRI) const {
+ for (const MachineOperand &MO : MI.operands()) {
+ if (MO.isRegMask())
+ ModifiedRegs.setBitsNotInMask(MO.getRegMask());
+ if (!MO.isReg())
+ continue;
+ unsigned Reg = MO.getReg();
+ if (!Reg)
+ continue;
+ if (MO.isDef()) {
+ // Some architectures (e.g. AArch64 XZR/WZR) have registers that are
+ // constant and may be used as destinations to indicate the generated
+ // value is discarded. No need to track such case as a def.
+ if (!TRI->isConstantPhysReg(Reg))
+ for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
+ ModifiedRegs.set(*AI);
+ } else {
+ assert(MO.isUse() && "Reg operand not a def and not a use");
+ for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
+ UsedRegs.set(*AI);
+ }
+ }
+}
+
bool TargetInstrInfo::isReallyTriviallyReMaterializableGeneric(
const MachineInstr &MI, AliasAnalysis *AA) const {
const MachineFunction &MF = *MI.getMF();
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 98e4fa9c0d0..e3ddc930657 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -80,6 +80,9 @@ static cl::opt<bool> DisablePostRAMachineLICM("disable-postra-machine-licm",
cl::desc("Disable Machine LICM"));
static cl::opt<bool> DisableMachineSink("disable-machine-sink", cl::Hidden,
cl::desc("Disable Machine Sinking"));
+static cl::opt<bool> DisablePostRAMachineSink("disable-postra-machine-sink",
+ cl::Hidden,
+ cl::desc("Disable PostRA Machine Sinking"));
static cl::opt<bool> DisableLSR("disable-lsr", cl::Hidden,
cl::desc("Disable Loop Strength Reduction Pass"));
static cl::opt<bool> DisableConstantHoisting("disable-constant-hoisting",
@@ -252,6 +255,9 @@ static IdentifyingPassPtr overridePass(AnalysisID StandardID,
if (StandardID == &MachineSinkingID)
return applyDisable(TargetID, DisableMachineSink);
+ if (StandardID == &PostRAMachineSinkingID)
+ return applyDisable(TargetID, DisablePostRAMachineSink);
+
if (StandardID == &MachineCopyPropagationID)
return applyDisable(TargetID, DisableCopyProp);
@@ -837,8 +843,10 @@ void TargetPassConfig::addMachinePasses() {
addPostRegAlloc();
// Insert prolog/epilog code. Eliminate abstract frame index references...
- if (getOptLevel() != CodeGenOpt::None)
+ if (getOptLevel() != CodeGenOpt::None) {
+ addPass(&PostRAMachineSinkingID);
addPass(&ShrinkWrapID);
+ }
// Prolog/Epilog inserter needs a TargetMachine to instantiate. But only
// do so if it hasn't been disabled, substituted, or overridden.
OpenPOWER on IntegriCloud