Index: llvm/lib/CodeGen/MachineCopyPropagation.cpp =================================================================== --- llvm/lib/CodeGen/MachineCopyPropagation.cpp +++ llvm/lib/CodeGen/MachineCopyPropagation.cpp @@ -288,6 +288,8 @@ const MachineInstr &UseI, unsigned UseIdx); bool hasImplicitOverlap(const MachineInstr &MI, const MachineOperand &Use); + bool hasOverlappingMultipleDef(const MachineInstr &MI, + const MachineOperand &MODef, Register Def); /// Candidates for deletion. SmallSetVector MaybeDeadCopies; @@ -461,6 +463,17 @@ return false; } +bool MachineCopyPropagation::hasOverlappingMultipleDef( + const MachineInstr &MI, const MachineOperand &MODef, Register Def) { + for (const MachineOperand &MIDef : MI.defs()) { + if ((&MIDef != &MODef) && MIDef.isReg() && + TRI->regsOverlap(Def, MIDef.getReg())) + return true; + } + + return false; +} + /// Look for available copies whose destination register is used by \p MI and /// replace the use in \p MI with the copy's source register. void MachineCopyPropagation::forwardUses(MachineInstr &MI) { @@ -786,6 +799,9 @@ if (hasImplicitOverlap(MI, MODef)) continue; + if (hasOverlappingMultipleDef(MI, MODef, Def)) + continue; + LLVM_DEBUG(dbgs() << "MCP: Replacing " << printReg(MODef.getReg(), TRI) << "\n with " << printReg(Def, TRI) << "\n in " << MI << " from " << *Copy); Index: llvm/test/CodeGen/ARM/mcp-dest-regs-no-dup.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/ARM/mcp-dest-regs-no-dup.mir @@ -0,0 +1,59 @@ +; RUN: llc < %s -O1 -mtriple=arm-eabi -o - | FileCheck %s + + @a = hidden local_unnamed_addr global i32 0, align 4 + @b = hidden local_unnamed_addr global i32 0, align 4 + @f = hidden local_unnamed_addr global i32 0, align 4 + @c = hidden local_unnamed_addr global i32 0, align 4 + @d = hidden local_unnamed_addr global i32 0, align 4 + @e = hidden local_unnamed_addr global i32 0, align 4 + @m = hidden local_unnamed_addr global i32 0, align 4 + @g = hidden local_unnamed_addr global i32* null, align 4 + + define hidden void @h() local_unnamed_addr #0 { + call void asm sideeffect "", ""() #1 + br label %11 + + 1: ; preds = %13 + call void asm sideeffect "", ""() #1 + %2 = load i32, i32* @a, align 4 + %3 = udiv i32 %2, 45 + + ; Armv6 generates a umull that must write to two distinct destination regs. + ; CHECK: umull [[REGISTER:lr|r[0-9]+]], + ; CHECK-NOT: [[REGISTER]], + ; CHECK: {{lr|r[0-9]+}}, {{lr|r[0-9]+$}} + + %4 = load i32, i32* @b, align 4 + %5 = load i32, i32* @f, align 4 + %6 = icmp ult i32 %4, %5 + %7 = zext i1 %6 to i32 + %8 = icmp ule i32 %3, %7 + %9 = zext i1 %8 to i32 + %10 = icmp ult i32 %14, %9 + br i1 %10, label %18, label %11 + + 11: ; preds = %1, %0 + store i32 2, i32* @f, align 4 + %12 = load i32*, i32** @g, align 4 + br label %13 + + 13: ; preds = %13, %11 + %14 = load i32, i32* @c, align 4 + store i32 11, i32* @d, align 4 + store i32 0, i32* @e, align 4 + store i32 1, i32* @b, align 4 + %15 = load i32, i32* @m, align 4 + store i32 %15, i32* %12, align 4 + %16 = load i32, i32* @f, align 4 + %17 = icmp eq i32 %16, 0 + br i1 %17, label %1, label %13 + + 18: ; preds = %1 + ret void + } + + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { "target-features"="+armv8-a,-fpregs" } + attributes #1 = { nounwind } +