Index: lib/CodeGen/MachineCopyPropagation.cpp =================================================================== --- lib/CodeGen/MachineCopyPropagation.cpp +++ lib/CodeGen/MachineCopyPropagation.cpp @@ -62,6 +62,7 @@ #include "llvm/Support/raw_ostream.h" #include #include +#include using namespace llvm; @@ -232,6 +233,27 @@ LLVM_DEBUG(dbgs() << "MCP: copy is a NOP, removing: "; Copy.dump()); + // Here we can go a little further and delete the first copy as well: + // %R1 = COPY %R0 << Redundant + // ... // No clobber of %R1 and no uses of %R1 defined by the first copy. + // %R0 = COPY killed %R1 << Redundant + // In other words, The first copy (PrevCopy) is only used for defining a reg + // that is used only in the second copy (Copy). Note, that "killed" flag is + // important here. + bool IsPrevCopyRedundant = false; + if (Copy.getOperand(1).isKill() && + PrevCopy.getOperand(1).getReg() != Copy.getOperand(1).getReg()) { + auto DI = + std::find(MaybeDeadCopies.begin(), MaybeDeadCopies.end(), &PrevCopy); + if (DI != MaybeDeadCopies.end()) { + MachineInstr *MaybeDead = *DI; + assert(!MRI->isReserved(MaybeDead->getOperand(0).getReg())); + + IsPrevCopyRedundant = true; + MaybeDeadCopies.erase(DI); + } + } + // Copy was redundantly redefining either Src or Def. Remove earlier kill // flags between Copy and PrevCopy because the value will be reused now. assert(Copy.isCopy()); @@ -244,6 +266,18 @@ Copy.eraseFromParent(); Changed = true; ++NumDeletes; + + if (IsPrevCopyRedundant) { + LLVM_DEBUG(dbgs() << "MCP: copy is a redundant as it's def use was " + "redundant, removing: "; + PrevCopy.dump()); + + ClobberRegister(PrevCopy.getOperand(1).getReg()); + + PrevCopy.eraseFromParent(); + ++NumDeletes; + } + return true; } Index: test/CodeGen/X86/machine-copy-prop.mir =================================================================== --- test/CodeGen/X86/machine-copy-prop.mir +++ test/CodeGen/X86/machine-copy-prop.mir @@ -8,12 +8,15 @@ define void @copyprop0() { ret void } define void @copyprop1() { ret void } define void @copyprop2() { ret void } + define void @copyprop3() { ret void } + define void @copyprop4() { ret void } define void @nocopyprop0() { ret void } define void @nocopyprop1() { ret void } define void @nocopyprop2() { ret void } define void @nocopyprop3() { ret void } define void @nocopyprop4() { ret void } define void @nocopyprop5() { ret void } + define void @nocopyprop6() { ret void } ... --- # The second copy is redundant and will be removed, check that we also remove @@ -117,6 +120,39 @@ NOOP implicit $rax, implicit $rdi ... --- +# Those two pairs of copies are redundant and can be removed. +# CHECK-LABEL: name: copyprop3 +# CHECK: bb.0: +# CHECK: NOOP implicit $rax +name: copyprop3 +body: | + bb.0: + liveins: $rax + + $rbx = COPY killed $rax + $rax = COPY killed $rbx + $rbx = COPY killed $rax + $rax = COPY killed $rbx + NOOP implicit $rax + +... +--- +# This whole chain of copies is redundant. +# CHECK-LABEL: name: copyprop4 +# CHECK: bb.0: +# CHECK: NOOP implicit $rax +name: copyprop4 +body: | + bb.0: + liveins: $rax + + renamable $rbx = COPY renamable killed $rax + renamable $rcx = COPY renamable killed $rbx + renamable $rax = COPY renamable killed $rcx + NOOP implicit $rax + +... +--- # The second copy is not redundant if the source register ($rax) is clobbered # even if the dest ($rbp) is not. # CHECK-LABEL: name: nocopyprop0 @@ -213,3 +249,17 @@ $rip = COPY $rax $rip = COPY $rax ... +# Make sure that we don't delete the first copy +# CHECK-LABEL: name: nocopyprop6 +# CHECK: bb.0: +# CHECK-NEXT: $rbx = COPY $rax +# CHECK-NEXT: NOOP implicit killed $rbx +# CHECK-NEXT: NOOP implicit $rax +name: nocopyprop6 +body: | + bb.0: + $rbx = COPY $rax + NOOP implicit killed $rbx + $rax = COPY killed $rbx + NOOP implicit $rax +...