diff --git a/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp b/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp --- a/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp +++ b/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp @@ -274,7 +274,8 @@ // appropriate location, we can try to sink the current instruction // past it. if (!KillMI || KillMI->getParent() != MBB || KillMI == MI || - MachineBasicBlock::iterator(KillMI) == OldPos || KillMI->isTerminator()) + MachineBasicBlock::iterator(KillMI) == OldPos || KillMI->isTerminator() || + KillMI->getOpcode() == TargetOpcode::INLINEASM_BR) return false; // If any of the definitions are used by another instruction between the @@ -888,7 +889,8 @@ return false; if (KillMI->hasUnmodeledSideEffects() || KillMI->isCall() || - KillMI->isBranch() || KillMI->isTerminator()) + KillMI->isBranch() || KillMI->isTerminator() || + KillMI->getOpcode() == TargetOpcode::INLINEASM_BR) // Don't move pass calls, etc. return false; @@ -948,7 +950,8 @@ return false; ++NumVisited; if (OtherMI.hasUnmodeledSideEffects() || OtherMI.isCall() || - OtherMI.isBranch() || OtherMI.isTerminator()) + OtherMI.isBranch() || OtherMI.isTerminator() || + OtherMI.getOpcode() == TargetOpcode::INLINEASM_BR) // Don't move pass calls, etc. return false; for (const MachineOperand &MO : OtherMI.operands()) { @@ -1122,7 +1125,8 @@ return false; ++NumVisited; if (OtherMI.hasUnmodeledSideEffects() || OtherMI.isCall() || - OtherMI.isBranch() || OtherMI.isTerminator()) + OtherMI.isBranch() || OtherMI.isTerminator() || + OtherMI.getOpcode() == TargetOpcode::INLINEASM_BR) // Don't move pass calls, etc. return false; SmallVector OtherDefs; diff --git a/llvm/test/CodeGen/X86/twoaddr-inlineasm_br.ll b/llvm/test/CodeGen/X86/twoaddr-inlineasm_br.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/twoaddr-inlineasm_br.ll @@ -0,0 +1,31 @@ +; RUN: llc -O2 $1 -print-after=twoaddressinstruction -stop-after=twoaddressinstruction -o /dev/null 2>&1 %s | FileCheck %s +%struct1 = type { i8*, %struct2, %struct3 } +%struct2 = type { %struct2*, %struct2* } +%struct3 = type { %struct4 } +%struct4 = type { i32 } +%struct5 = type { %struct6, %struct2, void (%struct1*)*, void (%struct1*)* } +%struct6 = type { i32 } + +define i32 @klist_dec_and_del(%struct1* %0) { + %2 = getelementptr inbounds %struct1, %struct1* %0, i64 0, i32 2 + %3 = getelementptr inbounds %struct3, %struct3* %2, i64 0, i32 0, i32 0 +; The LEA should not be sunk past the INLINEASM_BR, otherwise the execution of +; the LEA becomes conditional on whether the INLINEASM_BR branches or not, +; which would be incorrect. +; CHECK: %0:gr64 = LEA64r %1:gr64, 1, $noreg, 24, $noreg +; CHECK-NEXT: INLINEASM_BR &"" [sideeffect] [mayload] [maystore] [attdialect], $0:[mem:m], killed %1:gr64, 1, $noreg, 24, $noreg, $1:[imm], 1, $2:[imm], blockaddress(@klist_dec_and_del, %ir-block.4), $3:[clobber], implicit-def dead early-clobber $df, $4:[clobber], implicit-def early-clobber $fpsw, $5:[clobber], implicit-def dead early-clobber $eflags + callbr void asm sideeffect "", "*m,er,X,~{memory},~{dirflag},~{fpsr},~{flags}"(i32* %3, i32 1, i8* blockaddress(@klist_dec_and_del, %4)) + to label %8 [label %4] + +4: ; preds = %1 + %5 = getelementptr %struct3, %struct3* %2, i64 -6 + br label %6 + +6: ; preds = %4 + %7 = bitcast %struct3* %5 to %struct5** + store %struct5* null, %struct5** %7, align 8 + br label %8 + +8: ; preds = %6, %1 + ret i32 undef +}