summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp')
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp92
1 files changed, 64 insertions, 28 deletions
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 30e0da319e8..06f0ea54373 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -105,6 +105,37 @@ PreferredTuple ChoosePreferredUse(PreferredTuple &CurrentUse,
}
return CurrentUse;
}
+
+/// Find a suitable place to insert some instructions and insert them. This
+/// function accounts for special cases like inserting before a PHI node.
+/// The current strategy for inserting before PHI's is to duplicate the
+/// instructions for each predecessor. However, while that's ok for G_TRUNC
+/// on most targets since it generally requires no code, other targets/cases may
+/// want to try harder to find a dominating block.
+static void InsertInsnsWithoutSideEffectsBeforeUse(
+ MachineIRBuilder &Builder, MachineInstr &DefMI, MachineOperand &UseMO,
+ std::function<void(MachineBasicBlock::iterator)> Inserter) {
+ MachineInstr &UseMI = *UseMO.getParent();
+
+ MachineBasicBlock *InsertBB = UseMI.getParent();
+
+ // If the use is a PHI then we want the predecessor block instead.
+ if (UseMI.isPHI()) {
+ MachineOperand *PredBB = std::next(&UseMO);
+ InsertBB = PredBB->getMBB();
+ }
+
+ // If the block is the same block as the def then we want to insert just after
+ // the def instead of at the start of the block.
+ if (InsertBB == DefMI.getParent()) {
+ MachineBasicBlock::iterator InsertPt = &DefMI;
+ Inserter(std::next(InsertPt));
+ return;
+ }
+
+ // Otherwise we want the start of the BB
+ Inserter(InsertBB->getFirstNonPHI());
+}
} // end anonymous namespace
bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) {
@@ -153,22 +184,6 @@ bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) {
// type since by definition the result of an extend is larger.
assert(Preferred.Ty != LoadValueTy && "Extending to same type?");
- // Rewrite the load and schedule the canonical use for erasure.
- const auto TruncateUse = [&MI](MachineIRBuilder &Builder,
- MachineOperand &UseMO, unsigned DstReg,
- unsigned SrcReg) {
- MachineInstr &UseMI = *UseMO.getParent();
- MachineBasicBlock &UseMBB = *UseMI.getParent();
-
- Builder.setInsertPt(UseMBB, MachineBasicBlock::iterator(UseMI));
-
- if (UseMI.isPHI())
- Builder.setInsertPt(*MI.getParent(),
- std::next(MachineBasicBlock::iterator(MI)));
-
- Builder.buildTrunc(DstReg, SrcReg);
- };
-
// Rewrite the load to the chosen extending load.
unsigned ChosenDstReg = Preferred.MI->getOperand(0).getReg();
MI.setDesc(
@@ -180,7 +195,7 @@ bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) {
// Rewrite all the uses to fix up the types.
SmallVector<MachineInstr *, 1> ScheduleForErase;
- SmallVector<std::pair<MachineOperand*, unsigned>, 4> ScheduleForAssignReg;
+ SmallVector<std::pair<MachineOperand *, MachineInstr *>, 4> ScheduleForInsert;
for (auto &UseMO : MRI.use_operands(LoadValue.getReg())) {
MachineInstr *UseMI = UseMO.getParent();
@@ -204,7 +219,6 @@ bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) {
// ... = ... %2(s32)
MRI.replaceRegWith(UseDstReg, ChosenDstReg);
ScheduleForErase.push_back(UseMO.getParent());
- Observer.erasedInstr(*UseMO.getParent());
} else if (Preferred.Ty.getSizeInBits() < UseDstTy.getSizeInBits()) {
// If the preferred size is smaller, then keep the extend but extend
// from the result of the extending load. For example:
@@ -229,9 +243,11 @@ bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) {
// %4:_(s8) = G_TRUNC %2:_(s32)
// %3:_(s64) = G_ZEXT %2:_(s8)
// ... = ... %3(s64)
- unsigned NewVReg = MRI.cloneVirtualRegister(MI.getOperand(0).getReg());
- TruncateUse(Builder, UseMO, NewVReg, ChosenDstReg);
- ScheduleForAssignReg.emplace_back(&UseMO, NewVReg);
+ InsertInsnsWithoutSideEffectsBeforeUse(
+ Builder, MI, UseMO,
+ [&](MachineBasicBlock::iterator InsertBefore) {
+ ScheduleForInsert.emplace_back(&UseMO, &*InsertBefore);
+ });
}
continue;
}
@@ -239,20 +255,40 @@ bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) {
// We're going to update the load to def this value later so just erase
// the old extend.
ScheduleForErase.push_back(UseMO.getParent());
- Observer.erasedInstr(*UseMO.getParent());
continue;
}
// The use isn't an extend. Truncate back to the type we originally loaded.
// This is free on many targets.
- unsigned NewVReg = MRI.cloneVirtualRegister(MI.getOperand(0).getReg());
- TruncateUse(Builder, UseMO, NewVReg, ChosenDstReg);
- ScheduleForAssignReg.emplace_back(&UseMO, NewVReg);
+ InsertInsnsWithoutSideEffectsBeforeUse(
+ Builder, MI, UseMO, [&](MachineBasicBlock::iterator InsertBefore) {
+ ScheduleForInsert.emplace_back(&UseMO, &*InsertBefore);
+ });
}
- for (auto &Assignment : ScheduleForAssignReg)
- Assignment.first->setReg(Assignment.second);
- for (auto &EraseMI : ScheduleForErase)
+
+ DenseMap<MachineBasicBlock *, MachineInstr *> EmittedInsns;
+ for (auto &InsertionInfo : ScheduleForInsert) {
+ MachineOperand *UseMO = InsertionInfo.first;
+ MachineInstr *InsertBefore = InsertionInfo.second;
+
+ MachineInstr *PreviouslyEmitted =
+ EmittedInsns.lookup(InsertBefore->getParent());
+ if (PreviouslyEmitted) {
+ UseMO->setReg(PreviouslyEmitted->getOperand(0).getReg());
+ continue;
+ }
+
+ Builder.setInsertPt(*InsertBefore->getParent(), InsertBefore);
+ unsigned NewDstReg = MRI.cloneVirtualRegister(MI.getOperand(0).getReg());
+ MachineInstr *NewMI = Builder.buildTrunc(NewDstReg, ChosenDstReg);
+ EmittedInsns[InsertBefore->getParent()] = NewMI;
+ UseMO->setReg(NewDstReg);
+ Observer.createdInstr(*NewMI);
+ }
+ for (auto &EraseMI : ScheduleForErase) {
EraseMI->eraseFromParent();
+ Observer.erasedInstr(*EraseMI);
+ }
MI.getOperand(0).setReg(ChosenDstReg);
return true;
OpenPOWER on IntegriCloud