[llvm] r261965 - MachineCopyPropagation: Keep scanning through instructions with regmasks
Matthias Braun via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 25 19:18:50 PST 2016
Author: matze
Date: Thu Feb 25 21:18:50 2016
New Revision: 261965
URL: http://llvm.org/viewvc/llvm-project?rev=261965&view=rev
Log:
MachineCopyPropagation: Keep scanning through instructions with regmasks
This also simplifies the code by removing the overly conservative
NoInterveningSideEffect() function. This function checked:
- That the two copies belong to the same block: We only process one
block at a time and clear our maps in between it is impossible to find a
copy from a different block.
- There is no terminator between the two copy instructions: This is not
allowed anyway (the MachineVerifier would complain)
- Does not have instructions with hasUnmodeledSideEffects() or isCall()
set: Even for those instructuction we must have all clobbers/defs of
registers explicit as an operand. If the register is explicitely
clobbered we would never come to the point of checking for
NoInterveningSideEffect() anyway.
(I also checked this with a temporary build of the test-suite with all
potentially failing conditions in NoInterveningSideEffect() turned into
asserts)
Differential Revision: http://reviews.llvm.org/D17474
Modified:
llvm/trunk/lib/CodeGen/MachineCopyPropagation.cpp
llvm/trunk/test/CodeGen/X86/machine-copy-prop.mir
Modified: llvm/trunk/lib/CodeGen/MachineCopyPropagation.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineCopyPropagation.cpp?rev=261965&r1=261964&r2=261965&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/MachineCopyPropagation.cpp (original)
+++ llvm/trunk/lib/CodeGen/MachineCopyPropagation.cpp Thu Feb 25 21:18:50 2016
@@ -32,6 +32,10 @@ using namespace llvm;
STATISTIC(NumDeletes, "Number of dead copies deleted");
namespace {
+ typedef SmallVector<unsigned, 4> RegList;
+ typedef DenseMap<unsigned, RegList> SourceMap;
+ typedef DenseMap<unsigned, MachineInstr*> Reg2MIMap;
+
class MachineCopyPropagation : public MachineFunctionPass {
const TargetRegisterInfo *TRI;
const TargetInstrInfo *TII;
@@ -46,11 +50,7 @@ namespace {
bool runOnMachineFunction(MachineFunction &MF) override;
private:
- typedef SmallVector<unsigned, 4> DestList;
- typedef DenseMap<unsigned, DestList> SourceMap;
- typedef DenseMap<unsigned, MachineInstr*> Reg2MIMap;
-
- void SourceNoLongerAvailable(unsigned Reg);
+ void ClobberRegister(unsigned Reg);
void CopyPropagateBlock(MachineBasicBlock &MBB);
/// Candidates for deletion.
@@ -70,35 +70,45 @@ char &llvm::MachineCopyPropagationID = M
INITIALIZE_PASS(MachineCopyPropagation, "machine-cp",
"Machine Copy Propagation Pass", false, false)
-void MachineCopyPropagation::SourceNoLongerAvailable(unsigned Reg) {
+/// Remove any entry in \p Map where the register is a subregister or equal to
+/// a register contained in \p Regs.
+static void removeRegsFromMap(Reg2MIMap &Map, const RegList &Regs,
+ const TargetRegisterInfo &TRI) {
+ for (unsigned Reg : Regs) {
+ // Source of copy is no longer available for propagation.
+ for (MCSubRegIterator SR(Reg, &TRI, true); SR.isValid(); ++SR)
+ Map.erase(*SR);
+ }
+}
+
+/// Remove any entry in \p Map that is marked clobbered in \p RegMask.
+/// The map will typically have a lot fewer entries than the regmask clobbers,
+/// so this is more efficient than iterating the clobbered registers and calling
+/// ClobberRegister() on them.
+static void removeClobberedRegsFromMap(Reg2MIMap &Map,
+ const MachineOperand &RegMask) {
+ for (Reg2MIMap::iterator I = Map.begin(), E = Map.end(), Next; I != E;
+ I = Next) {
+ Next = std::next(I);
+ unsigned Reg = I->first;
+ if (RegMask.clobbersPhysReg(Reg))
+ Map.erase(I);
+ }
+}
+
+void MachineCopyPropagation::ClobberRegister(unsigned Reg) {
for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) {
+ CopyMap.erase(*AI);
+ AvailCopyMap.erase(*AI);
+
SourceMap::iterator SI = SrcMap.find(*AI);
if (SI != SrcMap.end()) {
- const DestList& Defs = SI->second;
- for (unsigned MappedDef : Defs) {
- // Source of copy is no longer available for propagation.
- for (MCSubRegIterator SR(MappedDef, TRI, true); SR.isValid(); ++SR)
- AvailCopyMap.erase(*SR);
- }
+ removeRegsFromMap(AvailCopyMap, SI->second, *TRI);
+ SrcMap.erase(SI);
}
}
}
-static bool NoInterveningSideEffect(const MachineInstr *CopyMI,
- const MachineInstr *MI) {
- const MachineBasicBlock *MBB = CopyMI->getParent();
- if (MI->getParent() != MBB)
- return false;
-
- for (MachineBasicBlock::const_iterator I = std::next(CopyMI->getIterator()),
- E = MBB->end(), E2 = MI->getIterator(); I != E && I != E2; ++I) {
- if (I->hasUnmodeledSideEffects() || I->isCall() ||
- I->isTerminator())
- return false;
- }
- return true;
-}
-
/// isNopCopy - Return true if the specified copy is really a nop. That is
/// if the source of the copy is the same of the definition of the copy that
/// supplied the source. If the source of the copy is a sub-register than it
@@ -142,9 +152,7 @@ void MachineCopyPropagation::CopyPropaga
DenseMap<unsigned, MachineInstr*>::iterator CI = AvailCopyMap.find(Src);
if (CI != AvailCopyMap.end()) {
MachineInstr *CopyMI = CI->second;
- if (!MRI->isReserved(Def) &&
- (!MRI->isReserved(Src) || NoInterveningSideEffect(CopyMI, MI)) &&
- isNopCopy(CopyMI, Def, Src, TRI)) {
+ if (!MRI->isReserved(Def) && isNopCopy(CopyMI, Def, Src, TRI)) {
// The two copies cancel out and the source of the first copy
// hasn't been overridden, eliminate the second one. e.g.
// %ECX<def> = COPY %EAX<kill>
@@ -197,14 +205,9 @@ void MachineCopyPropagation::CopyPropaga
// %xmm2<def> = copy %xmm0
// ...
// %xmm2<def> = copy %xmm9
- SourceNoLongerAvailable(Def);
+ ClobberRegister(Def);
// Remember Def is defined by the copy.
- // ... Make sure to clear the def maps of aliases first.
- for (MCRegAliasIterator AI(Def, TRI, false); AI.isValid(); ++AI) {
- CopyMap.erase(*AI);
- AvailCopyMap.erase(*AI);
- }
for (MCSubRegIterator SR(Def, TRI, /*IncludeSelf=*/true); SR.isValid();
++SR) {
CopyMap[*SR] = MI;
@@ -213,7 +216,7 @@ void MachineCopyPropagation::CopyPropaga
// Remember source that's copied to Def. Once it's clobbered, then
// it's no longer available for copy propagation.
- SmallVectorImpl<unsigned> &DestList = SrcMap[Src];
+ RegList &DestList = SrcMap[Src];
if (std::find(DestList.begin(), DestList.end(), Def) == DestList.end())
DestList.push_back(Def);
@@ -260,9 +263,8 @@ void MachineCopyPropagation::CopyPropaga
}
// The instruction has a register mask operand which means that it clobbers
- // a large set of registers. It is possible to use the register mask to
- // prune the available copies, but treat it like a basic block boundary for
- // now.
+ // a large set of registers. Treat clobbered registers the same way as
+ // defined registers.
if (RegMask) {
// Erase any MaybeDeadCopies whose destination register is clobbered.
for (MachineInstr *MaybeDead : MaybeDeadCopies) {
@@ -276,25 +278,23 @@ void MachineCopyPropagation::CopyPropaga
Changed = true;
++NumDeletes;
}
-
- // Clear all data structures as if we were beginning a new basic block.
MaybeDeadCopies.clear();
- AvailCopyMap.clear();
- CopyMap.clear();
- SrcMap.clear();
- continue;
- }
- for (unsigned Reg : Defs) {
- // No longer defined by a copy.
- for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) {
- CopyMap.erase(*AI);
- AvailCopyMap.erase(*AI);
+ removeClobberedRegsFromMap(AvailCopyMap, *RegMask);
+ removeClobberedRegsFromMap(CopyMap, *RegMask);
+ for (SourceMap::iterator I = SrcMap.begin(), E = SrcMap.end(), Next;
+ I != E; I = Next) {
+ Next = std::next(I);
+ if (RegMask->clobbersPhysReg(I->first)) {
+ removeRegsFromMap(AvailCopyMap, I->second, *TRI);
+ SrcMap.erase(I);
+ }
}
+ }
- // If 'Reg' is previously source of a copy, it is no longer available for
- // copy propagation.
- SourceNoLongerAvailable(Reg);
+ // Any previous copy definition or reading the Defs is no longer available.
+ for (unsigned Reg : Defs) {
+ ClobberRegister(Reg);
}
}
Modified: llvm/trunk/test/CodeGen/X86/machine-copy-prop.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/machine-copy-prop.mir?rev=261965&r1=261964&r2=261965&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/machine-copy-prop.mir (original)
+++ llvm/trunk/test/CodeGen/X86/machine-copy-prop.mir Thu Feb 25 21:18:50 2016
@@ -1,13 +1,16 @@
-# RUN: llc -march=x86 -run-pass machine-cp -verify-machineinstrs -o /dev/null %s 2>&1 | FileCheck %s
+# RUN: llc -march=x86 -run-pass machine-cp -o /dev/null %s 2>&1 | FileCheck %s
--- |
declare void @foo()
define void @copyprop_remove_kill0() { ret void }
define void @copyprop_remove_kill1() { ret void }
define void @copyprop_remove_kill2() { ret void }
+ define void @copyprop0() { ret void }
+ define void @nocopyprop0() { ret void }
+ define void @nocopyprop1() { ret void }
...
---
-# The second copy is redundand and will be removed, check that we also remove
+# The second copy is redundant and will be removed, check that we also remove
# the kill flag of intermediate instructions.
# CHECK-LABEL: name: copyprop_remove_kill0
# CHECK: bb.0:
@@ -24,7 +27,7 @@ body: |
NOOP implicit %rax, implicit %rdi
...
---
-# The second copy is redundand and will be removed, check that we also remove
+# The second copy is redundant and will be removed, check that we also remove
# the kill flag of intermediate instructions.
# CHECK-LABEL: name: copyprop_remove_kill1
# CHECK: bb.0:
@@ -41,7 +44,7 @@ body: |
NOOP implicit %rax, implicit %rdi
...
---
-# The second copy is redundand and will be removed, check that we also remove
+# The second copy is redundant and will be removed, check that we also remove
# the kill flag of intermediate instructions.
# CHECK-LABEL: name: copyprop_remove_kill2
# CHECK: bb.0:
@@ -57,3 +60,55 @@ body: |
%di = COPY %ax
NOOP implicit %rax, implicit %rdi
...
+---
+# The second copy is redundant; the call preserves the source and dest register.
+# CHECK-LABEL: name: copyprop0
+# CHECK: bb.0:
+# CHECK-NEXT: %rax = COPY %rdi
+# CHECK-NEXT: CALL64pcrel32 @foo, csr_64_rt_mostregs
+# CHECK-NEXT: NOOP implicit %edi
+# CHECK-NOT: COPY
+# CHECK-NEXT: NOOP implicit %rax, implicit %rdi
+name: copyprop0
+body: |
+ bb.0:
+ %rax = COPY %rdi
+ CALL64pcrel32 @foo, csr_64_rt_mostregs
+ NOOP implicit killed %edi
+ %rdi = COPY %rax
+ NOOP implicit %rax, implicit %rdi
+...
+---
+# The second copy is not redundant if the source register (%rax) is clobbered
+# even if the dest (%rbp) is not.
+# CHECK-LABEL: name: nocopyprop0
+# CHECK: bb.0:
+# CHECK-NEXT: %rax = COPY %rbp
+# CHECK-NEXT: CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp
+# CHECK-NEXT: %rbp = COPY %rax
+# CHECK-NEXT: NOOP implicit %rax, implicit %rbp
+name: nocopyprop0
+body: |
+ bb.0:
+ %rax = COPY %rbp
+ CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp
+ %rbp = COPY %rax
+ NOOP implicit %rax, implicit %rbp
+...
+---
+# The second copy is not redundant if the dest register (%rax) is clobbered
+# even if the source (%rbp) is not.
+# CHECK-LABEL: name: nocopyprop1
+# CHECK: bb.0:
+# CHECK-NEXT: %rbp = COPY %rax
+# CHECK-NEXT: CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp
+# CHECK-NEXT: %rax = COPY %rbp
+# CHECK-NEXT: NOOP implicit %rax, implicit %rbp
+name: nocopyprop1
+body: |
+ bb.0:
+ %rbp = COPY %rax
+ CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp
+ %rax = COPY %rbp
+ NOOP implicit %rax, implicit %rbp
+...
More information about the llvm-commits
mailing list