Index: lib/CodeGen/MachineCopyPropagation.cpp =================================================================== --- lib/CodeGen/MachineCopyPropagation.cpp +++ lib/CodeGen/MachineCopyPropagation.cpp @@ -85,16 +85,29 @@ } static bool NoInterveningSideEffect(const MachineInstr *CopyMI, - const MachineInstr *MI) { + const MachineInstr *MI, unsigned Reg) { 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()) + if (I->isTerminator()) return false; + if (I->hasUnmodeledSideEffects() || I->isCall()) { + // Continue if the instruction explicitely preserves the register + // (calls often do) + bool RegIsPreserved = false; + for (const MachineOperand &MO : MI->operands()) { + if (MO.isRegMask() && + !MachineOperand::clobbersPhysReg(MO.getRegMask(), Reg)) { + RegIsPreserved = true; + break; + } + } + if (!RegIsPreserved) + return false; + } } return true; } @@ -142,9 +155,9 @@ DenseMap::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) && + (!MRI->isReserved(Src) || + NoInterveningSideEffect(CopyMI, MI, Src))) { // The two copies cancel out and the source of the first copy // hasn't been overridden, eliminate the second one. e.g. // %ECX = COPY %EAX @@ -276,13 +289,35 @@ 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 (Reg2MIMap::iterator I = AvailCopyMap.begin(), E = AvailCopyMap.end(), + Next; I != E; I = Next) { + Next = std::next(I); + unsigned Reg = I->first; + if (RegMask->clobbersPhysReg(Reg)) + AvailCopyMap.erase(I); + } + for (Reg2MIMap::iterator I = CopyMap.begin(), E = CopyMap.end(), Next; + I != E; I = Next) { + Next = std::next(I); + unsigned Reg = I->first; + if (RegMask->clobbersPhysReg(Reg)) + CopyMap.erase(I); + } + for (SourceMap::iterator I = SrcMap.begin(), E = SrcMap.end(), Next; + I != E; I = Next) { + Next = std::next(I); + unsigned Reg = I->first; + if (RegMask->clobbersPhysReg(Reg)) { + const DestList &Defs = I->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); + } + } + } } for (unsigned Reg : Defs) { Index: test/CodeGen/X86/machine-copy-prop.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/machine-copy-prop.mir @@ -0,0 +1,21 @@ +# RUN: llc -march=x86 -run-pass machine-cp -o /dev/null %s 2>&1 | FileCheck %s + +--- | + declare preserve_mostcc void @foo() + define void @copyprop1() { ret void } +... +--- +# CHECK-LABEL: name: copyprop1 +# CHECK: bb.0: +# CHECK-NEXT: %rax = COPY %rdi +# CHECK-NEXT: CALL64pcrel32 @foo, csr_64_rt_mostregs, implicit %rsp, implicit-def %rsp +# CHECK-NOT: %rdi = COPY %rax +# CHECK-NEXT: NOOP implicit %rax, implicit %rdi +name: copyprop1 +body: | + bb.0: + %rax = COPY %rdi + CALL64pcrel32 @foo, csr_64_rt_mostregs, implicit %rsp, implicit-def %rsp + %rdi = COPY %rax + NOOP implicit %rax, implicit %rdi +...