This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG2a721374aef3: [IR] Don't use blockaddresses as callbr arguments (authored by nikic). Herald added a reviewer: bollu. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Changed prior to commit: https://reviews.llvm.org/D129288?vs=443898&id=444908#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D129288/new/ https://reviews.llvm.org/D129288 Files: clang/lib/CodeGen/CGStmt.cpp clang/test/CodeGen/asm-goto.c clang/test/CodeGen/asm.c clang/test/Modules/asm-goto.c llvm/docs/LangRef.rst llvm/docs/ReleaseNotes.rst llvm/include/llvm/IR/InlineAsm.h llvm/include/llvm/IR/Instructions.h llvm/lib/Bitcode/Reader/BitcodeReader.cpp llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp llvm/lib/IR/InlineAsm.cpp llvm/lib/IR/Instructions.cpp llvm/lib/IR/Verifier.cpp llvm/test/Analysis/BasicAA/pr52735.ll llvm/test/Assembler/call-arg-is-callee.ll llvm/test/Assembler/inline-asm-constraint-error.ll llvm/test/Bitcode/callbr.ll llvm/test/CodeGen/AArch64/callbr-asm-label.ll llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll llvm/test/CodeGen/AArch64/speculation-hardening-sls.ll llvm/test/CodeGen/ARM/speculation-hardening-sls.ll llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll llvm/test/CodeGen/SystemZ/asm-20.ll llvm/test/CodeGen/X86/callbr-asm-bb-exports.ll llvm/test/CodeGen/X86/callbr-asm-blockplacement.ll llvm/test/CodeGen/X86/callbr-asm-branch-folding.ll llvm/test/CodeGen/X86/callbr-asm-destinations.ll llvm/test/CodeGen/X86/callbr-asm-errors.ll llvm/test/CodeGen/X86/callbr-asm-instr-scheduling.ll llvm/test/CodeGen/X86/callbr-asm-kill.mir llvm/test/CodeGen/X86/callbr-asm-label-addr.ll llvm/test/CodeGen/X86/callbr-asm-obj-file.ll llvm/test/CodeGen/X86/callbr-asm-outputs-pred-succ.ll llvm/test/CodeGen/X86/callbr-asm-outputs.ll llvm/test/CodeGen/X86/callbr-asm-phi-placement.ll llvm/test/CodeGen/X86/callbr-asm-sink.ll llvm/test/CodeGen/X86/callbr-asm.ll llvm/test/CodeGen/X86/callbr-codegenprepare.ll llvm/test/CodeGen/X86/inline-asm-pic.ll llvm/test/CodeGen/X86/shrinkwrap-callbr.ll llvm/test/CodeGen/X86/speculation-hardening-sls.ll llvm/test/CodeGen/X86/tail-dup-asm-goto.ll llvm/test/Instrumentation/MemorySanitizer/msan_asm_conservative.ll llvm/test/Transforms/CallSiteSplitting/callsite-split-callbr.ll llvm/test/Transforms/CodeExtractor/PartialInlinePGOMultiRegion.ll llvm/test/Transforms/Coroutines/coro-debug.ll llvm/test/Transforms/GVN/callbr-loadpre-critedge.ll llvm/test/Transforms/GVN/callbr-scalarpre-critedge.ll llvm/test/Transforms/GVN/critical-edge-split-failure.ll llvm/test/Transforms/IROutliner/illegal-callbr.ll llvm/test/Transforms/Inline/blockaddress.ll llvm/test/Transforms/Inline/callbr.ll llvm/test/Transforms/JumpThreading/callbr-edge-split.ll llvm/test/Transforms/JumpThreading/pr46857-callbr.ll llvm/test/Transforms/LICM/callbr-crash.ll llvm/test/Transforms/LoopDeletion/two-predecessors.ll llvm/test/Transforms/LoopRotate/callbr.ll llvm/test/Transforms/LoopStrengthReduce/callbr-critical-edge-splitting.ll llvm/test/Transforms/LoopStrengthReduce/callbr-critical-edge-splitting2.ll llvm/test/Transforms/LoopStrengthReduce/remove_scev_indvars.ll llvm/test/Transforms/LoopUnroll/callbr.ll llvm/test/Transforms/PGOProfile/callbr.ll llvm/test/Transforms/SimpleLoopUnswitch/not-safe-to-clone.ll llvm/test/Transforms/SimplifyCFG/callbr-destinations.ll llvm/test/Transforms/SimplifyCFG/jump-threading.ll llvm/test/Verifier/callbr.ll llvm/test/Verifier/dominates.ll llvm/test/tools/llvm-diff/callbr.ll llvm/test/tools/llvm-diff/phinode.ll llvm/test/tools/llvm-reduce/remove-function-arguments-of-funcs-used-in-blockaddress.ll llvm/unittests/IR/InstructionsTest.cpp polly/test/ScopDetect/callbr.ll
Index: polly/test/ScopDetect/callbr.ll =================================================================== --- polly/test/ScopDetect/callbr.ll +++ polly/test/ScopDetect/callbr.ll @@ -12,7 +12,7 @@ define void @func(i32 %n, double* noalias nonnull %A) { entry: - callbr void asm sideeffect "", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@func, %for)) #1 + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() #1 to label %fallthrough [label %for] fallthrough: Index: llvm/unittests/IR/InstructionsTest.cpp =================================================================== --- llvm/unittests/IR/InstructionsTest.cpp +++ llvm/unittests/IR/InstructionsTest.cpp @@ -1498,7 +1498,7 @@ std::unique_ptr<Module> M = parseIR(Context, R"( define void @foo() { entry: - callbr void asm sideeffect "// XXX: ${0:l}", "X"(i8* blockaddress(@foo, %branch_test.exit)) + callbr void asm sideeffect "// XXX: ${0:l}", "!i"() to label %land.rhs.i [label %branch_test.exit] land.rhs.i: @@ -1528,20 +1528,6 @@ EXPECT_EQ(&BranchTestExit, CBI.getIndirectDest(0)); CBI.setIndirectDest(0, &IfThen); EXPECT_EQ(&IfThen, CBI.getIndirectDest(0)); - - // Further, test that changing the indirect destination updates the arg - // operand to use the block address of the new indirect destination basic - // block. This is a critical invariant of CallBrInst. - BlockAddress *IndirectBA = BlockAddress::get(CBI.getIndirectDest(0)); - BlockAddress *ArgBA = cast<BlockAddress>(CBI.getArgOperand(0)); - EXPECT_EQ(IndirectBA, ArgBA) - << "After setting the indirect destination, callbr had an indirect " - "destination of '" - << CBI.getIndirectDest(0)->getName() << "', but a argument of '" - << ArgBA->getBasicBlock()->getName() << "'. These should always match:\n" - << CBI; - EXPECT_EQ(IndirectBA->getBasicBlock(), &IfThen); - EXPECT_EQ(ArgBA->getBasicBlock(), &IfThen); } TEST(InstructionsTest, UnaryOperator) { Index: llvm/test/tools/llvm-reduce/remove-function-arguments-of-funcs-used-in-blockaddress.ll =================================================================== --- llvm/test/tools/llvm-reduce/remove-function-arguments-of-funcs-used-in-blockaddress.ll +++ llvm/test/tools/llvm-reduce/remove-function-arguments-of-funcs-used-in-blockaddress.ll @@ -4,27 +4,17 @@ ; CHECK-INTERESTINGNESS: define void @func( ; CHECK-FINAL: define void @func() define void @func(i1 %arg) { -; CHECK-ALL: bb: -; CHECK-ALL: br label %bb4 -bb: - br label %bb4 - -; CHECK-ALL: bb4 -bb4: -; CHECK-INTERESTINGNESS: callbr void asm -; CHECK-INTERESTINGNESS-SAME: blockaddress -; CHECK-FINAL: callbr void asm sideeffect "", "i"(i8* blockaddress(@func, %bb11)) -; CHECK-ALL: to label %bb5 [label %bb11] - callbr void asm sideeffect "", "i"(i8* blockaddress(@func, %bb11)) - to label %bb5 [label %bb11] +; CHECK-ALL: entry: +; CHECK-INTERESTINGNESS: call void @foo({{.*}}blockaddress +; CHECK-FINAL: call void @foo(i8* blockaddress(@func, %bb5)) +entry: + call void @foo(i8* blockaddress(@func, %bb5)) + ret void ; CHECK-ALL: bb5: -; CHECK-ALL: br label %bb11 -bb5: - br label %bb11 - -; CHECK-ALL: bb11: ; CHECK-ALL: ret void -bb11: +bb5: ret void } + +declare void @foo(i8*) Index: llvm/test/tools/llvm-diff/phinode.ll =================================================================== --- llvm/test/tools/llvm-diff/phinode.ll +++ llvm/test/tools/llvm-diff/phinode.ll @@ -9,7 +9,7 @@ ; CHECK-NEXT: < %7 = phi i32 [ 0, %2 ], [ -1, %1 ] ; CHECK-NEXT: < ret i32 %7 define i32 @foo(i32 %0) #0 { - callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %6)) + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() to label %2 [label %6] 2: Index: llvm/test/tools/llvm-diff/callbr.ll =================================================================== --- llvm/test/tools/llvm-diff/callbr.ll +++ llvm/test/tools/llvm-diff/callbr.ll @@ -1,8 +1,8 @@ -; RUN: not llvm-diff %s %s 2>&1 | FileCheck %s +; RUN: llvm-diff %s %s define void @foo() { entry: - callbr void asm sideeffect "", "i,i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %return), i8* blockaddress(@foo, %t_no)) + callbr void asm sideeffect "", "!i,!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough [label %return, label %t_no] asm.fallthrough: @@ -15,17 +15,9 @@ ret void } -; CHECK: in function bar: -; CHECK-NOT: in function foo: -; CHECK-NEXT: in block %entry: -; CHECK-NEXT: > callbr void asm sideeffect "", "i,i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %t_no), i8* blockaddress(@foo, %return)) -; CHECK-NEXT: to label %asm.fallthrough [label %return, label %t_no] -; CHECK-NEXT: < callbr void asm sideeffect "", "i,i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %t_no), i8* blockaddress(@foo, %return)) -; CHECK-NEXT: to label %asm.fallthrough [label %return, label %t_no] - define void @bar() { entry: - callbr void asm sideeffect "", "i,i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %t_no), i8* blockaddress(@foo, %return)) + callbr void asm sideeffect "", "!i,!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough [label %return, label %t_no] asm.fallthrough: Index: llvm/test/Verifier/dominates.ll =================================================================== --- llvm/test/Verifier/dominates.ll +++ llvm/test/Verifier/dominates.ll @@ -71,13 +71,13 @@ define i32 @f6(i32 %x) { bb0: - %y1 = callbr i32 asm "", "=r"() to label %bb1 [label %bb2] + %y1 = callbr i32 asm "", "=r,!i"() to label %bb1 [label %bb2] bb1: ret i32 0 bb2: ret i32 %y1 ; CHECK: Instruction does not dominate all uses! -; CHECK-NEXT: %y1 = callbr i32 asm "", "=r"() +; CHECK-NEXT: %y1 = callbr i32 asm "", "=r,!i"() ; CHECK-NEXT: to label %bb1 [label %bb2] ; CHECK-NEXT: ret i32 %y1 } Index: llvm/test/Verifier/callbr.ll =================================================================== --- llvm/test/Verifier/callbr.ll +++ llvm/test/Verifier/callbr.ll @@ -1,52 +1,58 @@ ; RUN: not opt -S %s -verify 2>&1 | FileCheck %s -; CHECK: Indirect label missing from arglist. -; CHECK-NEXT: #test1 -define void @test1() { - ; The %4 in the indirect label list is not found in the blockaddresses in the - ; arg list (bad). - callbr void asm sideeffect "#test1", "i,i"(i8* blockaddress(@test1, %3), i8* blockaddress(@test1, %2)) - to label %1 [label %4, label %2] +; CHECK: Number of label constraints does not match number of callbr dests +; CHECK-NEXT: #too_few_label_constraints +define void @too_few_label_constraints() { + callbr void asm sideeffect "#too_few_label_constraints", "!i"() + to label %1 [label %2, label %3] 1: ret void 2: ret void 3: ret void -4: - ret void } -; CHECK-NOT: Indirect label missing from arglist. -define void @test2() { - ; %4 and %2 are both in the indirect label list and the arg list (good). - callbr void asm sideeffect "${0:l} ${1:l}", "i,i"(i8* blockaddress(@test2, %4), i8* blockaddress(@test2, %2)) - to label %1 [label %4, label %2] +; CHECK-NOT: Number of label constraints does not match number of callbr dests +define void @correct_label_constraints() { + callbr void asm sideeffect "${0:l} ${1:l}", "!i,!i"() + to label %1 [label %2, label %3] 1: ret void 2: ret void 3: ret void -4: - ret void } -; CHECK-NOT: Indirect label missing from arglist. -define void @test3() { - ; note %2 blockaddress. Such a case is possible when passing the address of - ; a label as an input to the inline asm (both address of label and asm goto - ; use blockaddress constants; we're testing that the indirect label list from - ; the asm goto is in the arg list to the asm). - callbr void asm sideeffect "${0:l} ${1:l} ${2:l}", "i,X,i"(i8* blockaddress(@test3, %4), i8* blockaddress(@test3, %2), i8* blockaddress(@test3, %3)) - to label %1 [label %3, label %4] +; CHECK: Number of label constraints does not match number of callbr dests +; CHECK-NEXT: #too_many_label_constraints +define void @too_many_label_constraints() { + callbr void asm sideeffect "#too_many_label_constraints", "!i,!i,!i"() + to label %1 [label %2, label %3] 1: ret void 2: ret void 3: ret void -4: +} + +; CHECK: Label constraints can only be used with callbr +; CHECK-NEXT: #label_constraint_without_callbr +define void @label_constraint_without_callbr() { + call void asm sideeffect "#label_constraint_without_callbr", "!i"() + ret void +} + +; CHECK: Number of label constraints does not match number of callbr dests +; CHECK-NEXT: #callbr_without_label_constraint +define void @callbr_without_label_constraint() { + callbr void asm sideeffect "#callbr_without_label_constraint", ""() + to label %1 [label %2] +1: + ret void +2: ret void } @@ -55,7 +61,7 @@ ; CHECK-NEXT: #test4 define i32 @test4(i1 %var) { entry: - %ret = callbr i32 asm sideeffect "#test4", "=r,i"(i8* blockaddress(@test4, %abnormal)) to label %normal [label %abnormal] + %ret = callbr i32 asm sideeffect "#test4", "=r,!i"() to label %normal [label %abnormal] normal: ret i32 0 @@ -63,14 +69,3 @@ abnormal: ret i32 %ret } - -;; Ensure you cannot specify the same label as both normal and indirect targets. -; CHECK: Duplicate callbr destination! -; CHECK-NEXT: #test5 -define i32 @test5() { -entry: - %ret = callbr i32 asm sideeffect "#test5", "=r,i"(i8* blockaddress(@test5, %both)) to label %both [label %both] - -both: - ret i32 0 -} Index: llvm/test/Transforms/SimplifyCFG/jump-threading.ll =================================================================== --- llvm/test/Transforms/SimplifyCFG/jump-threading.ll +++ llvm/test/Transforms/SimplifyCFG/jump-threading.ll @@ -424,7 +424,7 @@ define void @callbr() { ; CHECK-LABEL: @callbr( ; CHECK-NEXT: entry: -; CHECK-NEXT: callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@callbr, [[TARGET:%.*]])) +; CHECK-NEXT: callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() ; CHECK-NEXT: to label [[IF_END:%.*]] [label %target] ; CHECK: target: ; CHECK-NEXT: br label [[IF_END]] @@ -432,7 +432,7 @@ ; CHECK-NEXT: ret void ; entry: - callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@callbr, %target)) + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() to label %join [label %target] target: Index: llvm/test/Transforms/SimplifyCFG/callbr-destinations.ll =================================================================== --- llvm/test/Transforms/SimplifyCFG/callbr-destinations.ll +++ llvm/test/Transforms/SimplifyCFG/callbr-destinations.ll @@ -5,7 +5,7 @@ define void @fun0() { entry: - callbr void asm sideeffect "", "i"(i8* blockaddress(@fun0, %bb1)) + callbr void asm sideeffect "", "!i"() to label %bb2 [label %bb1] bb1: ; preds = %bb @@ -17,7 +17,7 @@ define void @fun1() { entry: - callbr void asm sideeffect "", "i"(i8* blockaddress(@fun1, %bb1)) + callbr void asm sideeffect "", "!i"() to label %bb2 [label %bb1] bb2: ; preds = %bb Index: llvm/test/Transforms/SimpleLoopUnswitch/not-safe-to-clone.ll =================================================================== --- llvm/test/Transforms/SimpleLoopUnswitch/not-safe-to-clone.ll +++ llvm/test/Transforms/SimpleLoopUnswitch/not-safe-to-clone.ll @@ -11,7 +11,7 @@ br i1 %tree, label %if.end8, label %if.else if.else: ; preds = %for.cond - callbr void asm sideeffect ".pushsection __jump_table, \22aw\22 \0A\09.popsection \0A\09", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@mem_cgroup_node_nr_lru_pages, %for.cond5)) + callbr void asm sideeffect ".pushsection __jump_table, \22aw\22 \0A\09.popsection \0A\09", "!i,~{dirflag},~{fpsr},~{flags}"() to label %if.end8 [label %for.cond5] for.cond5: ; preds = %if.else, %for.cond5 Index: llvm/test/Transforms/PGOProfile/callbr.ll =================================================================== --- llvm/test/Transforms/PGOProfile/callbr.ll +++ llvm/test/Transforms/PGOProfile/callbr.ll @@ -5,7 +5,7 @@ ; CHECK-NOT: ptrtoint void (i8*)* asm sideeffect ; CHECK: callbr void asm sideeffect %retval = alloca i32, align 4 - callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@a, %b)) #1 + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() #1 to label %asm.fallthrough [label %b] asm.fallthrough: Index: llvm/test/Transforms/LoopUnroll/callbr.ll =================================================================== --- llvm/test/Transforms/LoopUnroll/callbr.ll +++ llvm/test/Transforms/LoopUnroll/callbr.ll @@ -32,7 +32,7 @@ br i1 %tobool, label %for.inc, label %if.then if.then: ; preds = %for.body - callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@d, %l_yes)) + callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough [label %l_yes] asm.fallthrough: ; preds = %if.then Index: llvm/test/Transforms/LoopStrengthReduce/remove_scev_indvars.ll =================================================================== --- llvm/test/Transforms/LoopStrengthReduce/remove_scev_indvars.ll +++ llvm/test/Transforms/LoopStrengthReduce/remove_scev_indvars.ll @@ -96,7 +96,7 @@ ; Check that this doesn't crash define void @kernfs_path_from_node() { entry: - callbr void asm sideeffect "", "i"(i8* blockaddress(@kernfs_path_from_node, %while.body)) + callbr void asm sideeffect "", "!i"() to label %asm.fallthrough [label %while.body] asm.fallthrough: ; preds = %entry Index: llvm/test/Transforms/LoopStrengthReduce/callbr-critical-edge-splitting2.ll =================================================================== --- llvm/test/Transforms/LoopStrengthReduce/callbr-critical-edge-splitting2.ll +++ llvm/test/Transforms/LoopStrengthReduce/callbr-critical-edge-splitting2.ll @@ -17,9 +17,9 @@ if.then: ; preds = %entry ; It's ok to modify this test in the future should be able to split critical ; edges here, just noting that this is the critical edge that we care about. -; CHECK: callbr void asm sideeffect "", "i"(i8* blockaddress(@b, %cleanup.cont.critedge)) +; CHECK: callbr void asm sideeffect "", "!i"() ; CHECK-NEXT: to label %return [label %cleanup.cont.critedge] - callbr void asm sideeffect "", "i"(i8* blockaddress(@b, %cleanup.cont.critedge)) + callbr void asm sideeffect "", "!i"() to label %return [label %cleanup.cont.critedge] cleanup.cont.critedge: ; preds = %entry, %if.then @@ -46,7 +46,7 @@ br i1 %tobool.not.i, label %if.then2, label %if.then.i if.then.i: ; preds = %if.then - callbr void asm sideeffect "", "i"(i8* blockaddress(@do_pages_move_nr_pages, %if.then2)) + callbr void asm sideeffect "", "!i"() to label %if.end3 [label %if.then2] if.then2: ; preds = %if.then, %if.then.i Index: llvm/test/Transforms/LoopStrengthReduce/callbr-critical-edge-splitting.ll =================================================================== --- llvm/test/Transforms/LoopStrengthReduce/callbr-critical-edge-splitting.ll +++ llvm/test/Transforms/LoopStrengthReduce/callbr-critical-edge-splitting.ll @@ -9,8 +9,8 @@ ; LEGACYPM-NEXT: entry: ; LEGACYPM-NEXT: br label [[FOR_COND:%.*]] ; LEGACYPM: for.cond: -; LEGACYPM-NEXT: callbr void asm sideeffect "", "i,i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test1, [[COND_TRUE_I:%.*]]), i8* blockaddress(@test1, [[FOR_ENDSPLIT:%.*]])) -; LEGACYPM-NEXT: to label [[ASM_FALLTHROUGH_I_I:%.*]] [label [[COND_TRUE_I]], label %for.endsplit] +; LEGACYPM-NEXT: callbr void asm sideeffect "", "!i,!i,~{dirflag},~{fpsr},~{flags}"() +; LEGACYPM-NEXT: to label [[ASM_FALLTHROUGH_I_I:%.*]] [label [[COND_TRUE_I:%.*]], label %for.endsplit] ; LEGACYPM: asm.fallthrough.i.i: ; LEGACYPM-NEXT: unreachable ; LEGACYPM: cond.true.i: @@ -28,15 +28,15 @@ ; LEGACYPM: for.endsplit: ; LEGACYPM-NEXT: br label [[FOR_END]] ; LEGACYPM: for.end: -; LEGACYPM-NEXT: [[PGOCOUNT_PROMOTED24:%.*]] = phi i64 [ [[LSR_IV_NEXT]], [[DO_BODY_I_I_RDRAND_INT_EXIT_I_CRIT_EDGE_FOR_END_CRIT_EDGE]] ], [ undef, [[FOR_ENDSPLIT]] ] +; LEGACYPM-NEXT: [[PGOCOUNT_PROMOTED24:%.*]] = phi i64 [ [[LSR_IV_NEXT]], [[DO_BODY_I_I_RDRAND_INT_EXIT_I_CRIT_EDGE_FOR_END_CRIT_EDGE]] ], [ undef, [[FOR_ENDSPLIT:%.*]] ] ; LEGACYPM-NEXT: ret i32 undef ; ; NEWPM-LABEL: @test1( ; NEWPM-NEXT: entry: ; NEWPM-NEXT: br label [[FOR_COND:%.*]] ; NEWPM: for.cond: -; NEWPM-NEXT: callbr void asm sideeffect "", "i,i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test1, [[COND_TRUE_I:%.*]]), i8* blockaddress(@test1, [[FOR_END:%.*]])) -; NEWPM-NEXT: to label [[ASM_FALLTHROUGH_I_I:%.*]] [label [[COND_TRUE_I]], label %for.end] +; NEWPM-NEXT: callbr void asm sideeffect "", "!i,!i,~{dirflag},~{fpsr},~{flags}"() +; NEWPM-NEXT: to label [[ASM_FALLTHROUGH_I_I:%.*]] [label [[COND_TRUE_I:%.*]], label %for.end] ; NEWPM: asm.fallthrough.i.i: ; NEWPM-NEXT: unreachable ; NEWPM: cond.true.i: @@ -45,7 +45,7 @@ ; NEWPM-NEXT: br i1 true, label [[DO_BODY_I_I_RDRAND_INT_EXIT_I_CRIT_EDGE:%.*]], label [[DO_BODY_I_I_DO_BODY_I_I_CRIT_EDGE]] ; NEWPM: do.body.i.i.rdrand_int.exit.i_crit_edge: ; NEWPM-NEXT: [[TMP0:%.*]] = add i64 1, undef -; NEWPM-NEXT: br i1 true, label [[FOR_END]], label [[FOR_INC:%.*]] +; NEWPM-NEXT: br i1 true, label [[FOR_END:%.*]], label [[FOR_INC:%.*]] ; NEWPM: for.inc: ; NEWPM-NEXT: br label [[FOR_COND]] ; NEWPM: for.end: @@ -58,7 +58,7 @@ for.cond: ; preds = %for.inc, %entry ; It's ok to modify this test in the future should we be able to split critical ; edges here, just noting that this is the critical edge that we care about. - callbr void asm sideeffect "", "i,i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test1, %cond.true.i), i8* blockaddress(@test1, %for.end)) + callbr void asm sideeffect "", "!i,!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough.i.i [label %cond.true.i, label %for.end] asm.fallthrough.i.i: ; preds = %for.cond Index: llvm/test/Transforms/LoopRotate/callbr.ll =================================================================== --- llvm/test/Transforms/LoopRotate/callbr.ll +++ llvm/test/Transforms/LoopRotate/callbr.ll @@ -31,7 +31,7 @@ ; CHECK: .lr.ph: ; CHECK-NEXT: br label [[TMP13:%.*]] ; CHECK: [[DOT11:%.*]] = phi i32 [ undef, [[DOTLR_PH]] ], [ [[TMP14:%.*]], [[J_EXIT_I:%.*]] ] -; CHECK-NEXT: callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@o, [[M_EXIT]])) #1 +; CHECK-NEXT: callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() #1 ; CHECK-NEXT: to label [[J_EXIT_I]] [label %m.exit] ; CHECK: j.exit.i: ; CHECK-NEXT: [[TMP14]] = tail call i32 asm "", "={ax},~{dirflag},~{fpsr},~{flags}"() #2 @@ -79,7 +79,7 @@ br i1 %13, label %m.exit, label %14 ; <label>:14: ; preds = %12 - callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@o, %m.exit)) #1 + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() #1 to label %j.exit.i [label %m.exit] j.exit.i: ; preds = %14 Index: llvm/test/Transforms/LoopDeletion/two-predecessors.ll =================================================================== --- llvm/test/Transforms/LoopDeletion/two-predecessors.ll +++ llvm/test/Transforms/LoopDeletion/two-predecessors.ll @@ -7,17 +7,17 @@ define dso_local i32 @hoge() local_unnamed_addr #0 { ; CHECK-LABEL: @hoge( ; CHECK-NEXT: bb: -; CHECK-NEXT: callbr void asm sideeffect "", "i"(i8* blockaddress(@hoge, [[BB2:%.*]])) +; CHECK-NEXT: callbr void asm sideeffect "", "!i"() ; CHECK-NEXT: to label [[BB1:%.*]] [label %bb2] ; CHECK: bb1: -; CHECK-NEXT: br label [[BB2]] +; CHECK-NEXT: br label [[BB2:%.*]] ; CHECK: bb2: ; CHECK-NEXT: [[TMP:%.*]] = phi i32 [ undef, [[BB1]] ], [ [[TMP3:%.*]], [[BB2]] ], [ undef, [[BB:%.*]] ] ; CHECK-NEXT: [[TMP3]] = tail call i32 bitcast (i32 (...)* @widget to i32 (i32)*)(i32 [[TMP]]) ; CHECK-NEXT: br label [[BB2]] ; bb: - callbr void asm sideeffect "", "i"(i8* blockaddress(@hoge, %bb2)) #1 + callbr void asm sideeffect "", "!i"() #1 to label %bb1 [label %bb2] bb1: ; preds = %bb Index: llvm/test/Transforms/LICM/callbr-crash.ll =================================================================== --- llvm/test/Transforms/LICM/callbr-crash.ll +++ llvm/test/Transforms/LICM/callbr-crash.ll @@ -6,7 +6,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[FOR_COND:%.*]] ; CHECK: for.cond: -; CHECK-NEXT: callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@j, [[FOR_END_SPLIT_LOOP_EXIT1:%.*]])) +; CHECK-NEXT: callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() ; CHECK-NEXT: to label [[COND_TRUE_I:%.*]] [label %for.end.split.loop.exit1] ; CHECK: cond.true.i: ; CHECK-NEXT: br i1 true, label [[FOR_END_SPLIT_LOOP_EXIT:%.*]], label [[FOR_COND]] @@ -17,14 +17,14 @@ ; CHECK-NEXT: [[PHI_PH2:%.*]] = phi i32 [ undef, [[FOR_COND]] ] ; CHECK-NEXT: br label [[FOR_END]] ; CHECK: for.end: -; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[ASMRESULT1_I_I_LE]], [[FOR_END_SPLIT_LOOP_EXIT]] ], [ [[PHI_PH2]], [[FOR_END_SPLIT_LOOP_EXIT1]] ] +; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[ASMRESULT1_I_I_LE]], [[FOR_END_SPLIT_LOOP_EXIT]] ], [ [[PHI_PH2]], [[FOR_END_SPLIT_LOOP_EXIT1:%.*]] ] ; CHECK-NEXT: ret i32 [[PHI]] ; entry: br label %for.cond for.cond: ; preds = %cond.true.i, %entry - callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@j, %for.end)) + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() to label %cond.true.i [label %for.end] cond.true.i: ; preds = %for.cond Index: llvm/test/Transforms/JumpThreading/pr46857-callbr.ll =================================================================== --- llvm/test/Transforms/JumpThreading/pr46857-callbr.ll +++ llvm/test/Transforms/JumpThreading/pr46857-callbr.ll @@ -8,10 +8,10 @@ ; CHECK-NEXT: bb: ; CHECK-NEXT: br i1 [[ARG:%.*]], label [[BB7:%.*]], label [[BB4:%.*]] ; CHECK: bb4: -; CHECK-NEXT: callbr void asm sideeffect "", "i"(i8* blockaddress(@func, [[BB7_THR_COMM:%.*]])) +; CHECK-NEXT: callbr void asm sideeffect "", "!i"() ; CHECK-NEXT: to label [[BB5:%.*]] [label %bb7.thr_comm] ; CHECK: bb5: -; CHECK-NEXT: br label [[BB7_THR_COMM]] +; CHECK-NEXT: br label [[BB7_THR_COMM:%.*]] ; CHECK: bb7.thr_comm: ; CHECK-NEXT: [[I91:%.*]] = xor i1 [[ARG2:%.*]], [[ARG]] ; CHECK-NEXT: br i1 [[I91]], label [[BB11:%.*]], label [[BB11]] @@ -31,7 +31,7 @@ br label %bb7 bb4: - callbr void asm sideeffect "", "i"(i8* blockaddress(@func, %bb6)) + callbr void asm sideeffect "", "!i"() to label %bb5 [label %bb6] bb5: Index: llvm/test/Transforms/JumpThreading/callbr-edge-split.ll =================================================================== --- llvm/test/Transforms/JumpThreading/callbr-edge-split.ll +++ llvm/test/Transforms/JumpThreading/callbr-edge-split.ll @@ -12,10 +12,10 @@ ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[TMP0]], 0 ; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]] ; CHECK: if.else: -; CHECK-NEXT: callbr void asm sideeffect "", "i"(i8* blockaddress(@c, [[IF_THEN2:%.*]])) +; CHECK-NEXT: callbr void asm sideeffect "", "!i"() ; CHECK-NEXT: to label [[NORMAL:%.*]] [label %if.then2] ; CHECK: normal: -; CHECK-NEXT: br label [[IF_THEN2]] +; CHECK-NEXT: br label [[IF_THEN2:%.*]] ; CHECK: if.end: ; CHECK-NEXT: [[CALL:%.*]] = call i32 @b() ; CHECK-NEXT: [[PHITMP:%.*]] = icmp ne i32 [[CALL]], 0 @@ -37,7 +37,7 @@ br label %if.end if.else: ; preds = %entry - callbr void asm sideeffect "", "i"(i8* blockaddress(@c, %if.end)) #2 + callbr void asm sideeffect "", "!i"() #2 to label %normal [label %if.end] normal: ; preds = %if.else Index: llvm/test/Transforms/Inline/callbr.ll =================================================================== --- llvm/test/Transforms/Inline/callbr.ll +++ llvm/test/Transforms/Inline/callbr.ll @@ -14,7 +14,7 @@ %3 = alloca i32, align 4 store i32 %0, i32* %3, align 4 %4 = load i32, i32* %3, align 4 - callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %4, i8* blockaddress(@t32, %7), i8* blockaddress(@t32, %6)) #1 + callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %4) #1 to label %5 [label %7, label %6] ; <label>:5: ; preds = %1 @@ -39,7 +39,7 @@ ; CHECK-NOT: @t32 ; CHECK: define dso_local i32 @main -; CHECK: callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %6, i8* blockaddress(@main, %9), i8* blockaddress(@main, %8)) +; CHECK: callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %6) ; CHECK: to label %7 [label %9, label %8] ; CHECK: 7: ; CHECK-NEXT: store i32 0, i32* %1, align 4 Index: llvm/test/Transforms/Inline/blockaddress.ll =================================================================== --- llvm/test/Transforms/Inline/blockaddress.ll +++ llvm/test/Transforms/Inline/blockaddress.ll @@ -59,7 +59,7 @@ %3 = alloca i32, align 4 store i32 %0, i32* %3, align 4 %4 = load i32, i32* %3, align 4 - callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %4, i8* blockaddress(@foo, %7), i8* blockaddress(@foo, %6)) #1 + callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %4) #1 to label %5 [label %7, label %6] ; <label>:5: ; preds = %1 @@ -100,7 +100,7 @@ %3 = alloca i32, align 4 store i32 %0, i32* %3, align 4 %4 = load i32, i32* %3, align 4 - callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %4, i8* blockaddress(@baz, %7), i8* blockaddress(@baz, %6)) #1 + callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %4) #1 to label %5 [label %7, label %6] ; <label>:5: ; preds = %1 Index: llvm/test/Transforms/IROutliner/illegal-callbr.ll =================================================================== --- llvm/test/Transforms/IROutliner/illegal-callbr.ll +++ llvm/test/Transforms/IROutliner/illegal-callbr.ll @@ -16,15 +16,14 @@ ; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]]) ; CHECK-NEXT: ret i32 0 ; CHECK: fail1: -; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B]], 1 -; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[B]], 1 +; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]]) ; CHECK-NEXT: ret i32 0 ; bb0: %0 = add i32 %a, 4 %1 = add i32 %b, 1 %2 = add i32 %b, 1 - callbr void asm "xorl $0, $0; jmp ${1:l}", "r,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@function1, %fail1)) to label %normal [label %fail1] + callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail1] normal: %3 = add i32 %b, 1 %4 = add i32 %b, 1 @@ -46,15 +45,14 @@ ; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]]) ; CHECK-NEXT: ret i32 0 ; CHECK: fail1: -; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B]], 1 -; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[B]], 1 +; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]]) ; CHECK-NEXT: ret i32 0 ; bb0: %0 = add i32 %a, 4 %1 = add i32 %b, 1 %2 = add i32 %b, 1 - callbr void asm "xorl $0, $0; jmp ${1:l}", "r,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@function2, %fail1)) to label %normal [label %fail1] + callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail1] normal: %3 = add i32 %b, 1 %4 = add i32 %b, 1 Index: llvm/test/Transforms/GVN/critical-edge-split-failure.ll =================================================================== --- llvm/test/Transforms/GVN/critical-edge-split-failure.ll +++ llvm/test/Transforms/GVN/critical-edge-split-failure.ll @@ -31,9 +31,9 @@ ; Splitting the critical edge from if.then to if.end will fail, but should not ; cause an infinite loop in GVN. If we can one day split edges of callbr ; indirect targets, great! -; CHECK: callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@l2tp_recv_dequeue, %if.end)) +; CHECK: callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() ; CHECK-NEXT: to label %asm.fallthrough.i [label %if.end] - callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@l2tp_recv_dequeue, %if.end)) + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough.i [label %if.end] asm.fallthrough.i: ; preds = %if.then Index: llvm/test/Transforms/GVN/callbr-scalarpre-critedge.ll =================================================================== --- llvm/test/Transforms/GVN/callbr-scalarpre-critedge.ll +++ llvm/test/Transforms/GVN/callbr-scalarpre-critedge.ll @@ -8,8 +8,8 @@ ; CHECK-LABEL: @wombat( ; CHECK-NEXT: bb: ; CHECK-NEXT: [[TMP5:%.*]] = or i64 [[ARG2:%.*]], [[ARG:%.*]] -; CHECK-NEXT: callbr void asm sideeffect "", "i,i"(i8* blockaddress(@wombat, [[BB7:%.*]]), i8* blockaddress(@wombat, [[BB_BB9_CRIT_EDGE:%.*]])) -; CHECK-NEXT: to label [[BB6:%.*]] [label [[BB7]], label %bb.bb9_crit_edge] +; CHECK-NEXT: callbr void asm sideeffect "", "!i,!i"() +; CHECK-NEXT: to label [[BB6:%.*]] [label [[BB7:%.*]], label %bb.bb9_crit_edge] ; CHECK: bb.bb9_crit_edge: ; CHECK-NEXT: [[DOTPRE:%.*]] = trunc i64 [[TMP5]] to i32 ; CHECK-NEXT: br label [[BB9:%.*]] @@ -20,13 +20,13 @@ ; CHECK-NEXT: tail call void @barney(i32 [[TMP8]]) ; CHECK-NEXT: br label [[BB9]] ; CHECK: bb9: -; CHECK-NEXT: [[TMP10_PRE_PHI:%.*]] = phi i32 [ [[DOTPRE]], [[BB_BB9_CRIT_EDGE]] ], [ [[TMP8]], [[BB7]] ] +; CHECK-NEXT: [[TMP10_PRE_PHI:%.*]] = phi i32 [ [[DOTPRE]], [[BB_BB9_CRIT_EDGE:%.*]] ], [ [[TMP8]], [[BB7]] ] ; CHECK-NEXT: store i32 [[TMP10_PRE_PHI]], i32* [[ARG3:%.*]], align 4 ; CHECK-NEXT: ret void ; bb: %tmp5 = or i64 %arg2, %arg - callbr void asm sideeffect "", "i,i"(i8* blockaddress(@wombat, %bb7), i8* blockaddress(@wombat, %bb9)) + callbr void asm sideeffect "", "!i,!i"() to label %bb6 [label %bb7, label %bb9] bb6: ; preds = %bb Index: llvm/test/Transforms/GVN/callbr-loadpre-critedge.ll =================================================================== --- llvm/test/Transforms/GVN/callbr-loadpre-critedge.ll +++ llvm/test/Transforms/GVN/callbr-loadpre-critedge.ll @@ -9,8 +9,8 @@ define void @widget(%struct.pluto** %tmp1) { ; CHECK-LABEL: @widget( ; CHECK-NEXT: bb: -; CHECK-NEXT: callbr void asm sideeffect "", "i,i"(i8* blockaddress(@widget, [[BB5:%.*]]), i8* blockaddress(@widget, [[BB_BB8_CRIT_EDGE:%.*]])) -; CHECK-NEXT: to label [[BB4:%.*]] [label [[BB5]], label %bb.bb8_crit_edge] +; CHECK-NEXT: callbr void asm sideeffect "", "!i,!i"() +; CHECK-NEXT: to label [[BB4:%.*]] [label [[BB5:%.*]], label %bb.bb8_crit_edge] ; CHECK: bb.bb8_crit_edge: ; CHECK-NEXT: [[TMP10_PRE:%.*]] = load %struct.pluto*, %struct.pluto** [[TMP1:%.*]], align 8 ; CHECK-NEXT: br label [[BB8:%.*]] @@ -21,7 +21,7 @@ ; CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds [[STRUCT_PLUTO:%.*]], %struct.pluto* [[TMP6]], i64 0, i32 1 ; CHECK-NEXT: br label [[BB8]] ; CHECK: bb8: -; CHECK-NEXT: [[TMP10:%.*]] = phi %struct.pluto* [ [[TMP6]], [[BB5]] ], [ [[TMP10_PRE]], [[BB_BB8_CRIT_EDGE]] ] +; CHECK-NEXT: [[TMP10:%.*]] = phi %struct.pluto* [ [[TMP6]], [[BB5]] ], [ [[TMP10_PRE]], [[BB_BB8_CRIT_EDGE:%.*]] ] ; CHECK-NEXT: [[TMP9:%.*]] = phi i8* [ [[TMP7]], [[BB5]] ], [ null, [[BB_BB8_CRIT_EDGE]] ] ; CHECK-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[STRUCT_PLUTO]], %struct.pluto* [[TMP10]], i64 0, i32 0 ; CHECK-NEXT: [[TMP12:%.*]] = load i8, i8* [[TMP11]], align 1 @@ -29,7 +29,7 @@ ; CHECK-NEXT: ret void ; bb: - callbr void asm sideeffect "", "i,i"(i8* blockaddress(@widget, %bb5), i8* blockaddress(@widget, %bb8)) + callbr void asm sideeffect "", "!i,!i"() to label %bb4 [label %bb5, label %bb8] bb4: ; preds = %bb Index: llvm/test/Transforms/Coroutines/coro-debug.ll =================================================================== --- llvm/test/Transforms/Coroutines/coro-debug.ll +++ llvm/test/Transforms/Coroutines/coro-debug.ll @@ -56,7 +56,7 @@ %4 = load i32, i32* %x.addr, align 4, !dbg !20 %add = add nsw i32 %4, 1, !dbg !21 store i32 %add, i32* %x.addr, align 4, !dbg !22 - %asm_res = callbr i32 asm "", "=r,r,i"(i32 %x, i8* blockaddress(@f, %indirect.dest)) + %asm_res = callbr i32 asm "", "=r,r,!i"(i32 %x) to label %coro_Cleanup [label %indirect.dest] indirect.dest: Index: llvm/test/Transforms/CodeExtractor/PartialInlinePGOMultiRegion.ll =================================================================== --- llvm/test/Transforms/CodeExtractor/PartialInlinePGOMultiRegion.ll +++ llvm/test/Transforms/CodeExtractor/PartialInlinePGOMultiRegion.ll @@ -101,7 +101,7 @@ br label %for.cond2 for.end: ; preds = %for.cond2 - callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@bar, %l_yes)) + callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough [label %l_yes] asm.fallthrough: ; preds = %for.end br label %l_yes Index: llvm/test/Transforms/CallSiteSplitting/callsite-split-callbr.ll =================================================================== --- llvm/test/Transforms/CallSiteSplitting/callsite-split-callbr.ll +++ llvm/test/Transforms/CallSiteSplitting/callsite-split-callbr.ll @@ -7,7 +7,7 @@ define void @caller() { ; CHECK-LABEL: define {{[^@]+}}@caller() { ; CHECK-NEXT: Top: -; CHECK-NEXT: callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@caller, [[TOP_SPLIT:%.*]])) +; CHECK-NEXT: callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() ; CHECK-NEXT: to label [[NEXTCOND:%.*]] [label %Top.split] ; CHECK: Top.split: ; CHECK-NEXT: call void @callee(i1 false) @@ -18,8 +18,8 @@ ; CHECK-NEXT: call void @callee(i1 true) ; CHECK-NEXT: br label [[CALLSITEBB]] ; CHECK: CallSiteBB: -; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ false, [[TOP_SPLIT]] ], [ true, [[NEXTCOND_SPLIT]] ] -; CHECK-NEXT: callbr void asm sideeffect "", "r,i,~{dirflag},~{fpsr},~{flags}"(i1 [[PHI]], i8* blockaddress(@caller, [[END2:%.*]])) +; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ false, [[TOP_SPLIT:%.*]] ], [ true, [[NEXTCOND_SPLIT]] ] +; CHECK-NEXT: callbr void asm sideeffect "", "r,!i,~{dirflag},~{fpsr},~{flags}"(i1 [[PHI]]) ; CHECK-NEXT: to label [[END:%.*]] [label %End2] ; CHECK: End: ; CHECK-NEXT: ret void @@ -27,7 +27,7 @@ ; CHECK-NEXT: ret void ; Top: - callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@caller, %CallSiteBB)) + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() to label %NextCond [label %CallSiteBB] NextCond: @@ -36,7 +36,7 @@ CallSiteBB: %phi = phi i1 [0, %Top],[1, %NextCond] call void @callee(i1 %phi) - callbr void asm sideeffect "", "r,i,~{dirflag},~{fpsr},~{flags}"(i1 %phi, i8* blockaddress(@caller, %End2)) + callbr void asm sideeffect "", "r,!i,~{dirflag},~{fpsr},~{flags}"(i1 %phi) to label %End [label %End2] End: Index: llvm/test/Instrumentation/MemorySanitizer/msan_asm_conservative.ll =================================================================== --- llvm/test/Instrumentation/MemorySanitizer/msan_asm_conservative.ll +++ llvm/test/Instrumentation/MemorySanitizer/msan_asm_conservative.ll @@ -276,7 +276,7 @@ ; and the compiler doesn't crash. define dso_local i32 @asm_goto(i32 %n) sanitize_memory { entry: - callbr void asm sideeffect "cmp $0, $1; jnz ${2:l}", "r,r,i,~{dirflag},~{fpsr},~{flags}"(i32 %n, i32 1, i8* blockaddress(@asm_goto, %skip_label)) + callbr void asm sideeffect "cmp $0, $1; jnz ${2:l}", "r,r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %n, i32 1) to label %cleanup [label %skip_label] skip_label: ; preds = %entry Index: llvm/test/CodeGen/X86/tail-dup-asm-goto.ll =================================================================== --- llvm/test/CodeGen/X86/tail-dup-asm-goto.ll +++ llvm/test/CodeGen/X86/tail-dup-asm-goto.ll @@ -50,7 +50,7 @@ bb110: ; preds = %bb106, %bb100 %i10.1 = phi ptr [ %arg2, %bb106 ], [ %i28.i, %bb100 ] - callbr void asm sideeffect "#$0 $1 $2", "i,i,i,~{dirflag},~{fpsr},~{flags}"(i32 42, i1 false, ptr blockaddress(@test1, %bb17.i.i.i)) + callbr void asm sideeffect "#$0 $1 $2", "i,i,!i,~{dirflag},~{fpsr},~{flags}"(i32 42, i1 false) to label %kmem_cache_has_cpu_partial.exit [label %bb17.i.i.i] bb17.i.i.i: ; preds = %bb110 Index: llvm/test/CodeGen/X86/speculation-hardening-sls.ll =================================================================== --- llvm/test/CodeGen/X86/speculation-hardening-sls.ll +++ llvm/test/CodeGen/X86/speculation-hardening-sls.ll @@ -64,7 +64,7 @@ ; RET-NEXT: int3 ; IJMP-NOT: int3 entry: - callbr void asm sideeffect "jmp $0", "X"(ptr blockaddress(@asmgoto, %d)) + callbr void asm sideeffect "jmp $0", "!i"() to label %asm.fallthrough [label %d] ; The asm goto above produces a direct branch: Index: llvm/test/CodeGen/X86/shrinkwrap-callbr.ll =================================================================== --- llvm/test/CodeGen/X86/shrinkwrap-callbr.ll +++ llvm/test/CodeGen/X86/shrinkwrap-callbr.ll @@ -48,7 +48,7 @@ if.end: %call = tail call i32 @fn() - callbr void asm sideeffect "# jump to $0", "i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test1, %two)) + callbr void asm sideeffect "# jump to $0", "!i,~{dirflag},~{fpsr},~{flags}"() to label %return [label %two] two: Index: llvm/test/CodeGen/X86/inline-asm-pic.ll =================================================================== --- llvm/test/CodeGen/X86/inline-asm-pic.ll +++ llvm/test/CodeGen/X86/inline-asm-pic.ll @@ -34,7 +34,7 @@ ; CHECK-NEXT: Ltmp0: ## Block address taken ; CHECK-NEXT: LBB1_1: ## %overflow ; CHECK-NEXT: retl - callbr void asm "# ${0:l}\0A", "i"(ptr blockaddress(@x, %overflow)) + callbr void asm "# ${0:l}\0A", "!i"() to label %return [label %overflow] overflow: Index: llvm/test/CodeGen/X86/callbr-codegenprepare.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-codegenprepare.ll +++ llvm/test/CodeGen/X86/callbr-codegenprepare.ll @@ -12,7 +12,7 @@ define dso_local i32 @futex_lock_pi_atomic() local_unnamed_addr { entry: - %0 = callbr i32 asm "", "=r,i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@futex_lock_pi_atomic, %b.exit)) + %0 = callbr i32 asm "", "=r,!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough.i [label %b.exit] asm.fallthrough.i: Index: llvm/test/CodeGen/X86/callbr-asm.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm.ll +++ llvm/test/CodeGen/X86/callbr-asm.ll @@ -23,7 +23,7 @@ ; CHECK-NEXT: retl entry: %0 = add i32 %a, 4 - callbr void asm "xorl $0, $0; jmp ${1:l}", "r,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, ptr blockaddress(@test1, %fail)) to label %normal [label %fail] + callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail] normal: ret i32 0 @@ -53,7 +53,7 @@ ; CHECK-NEXT: retl entry: %0 = add i32 %a, 4 - callbr void asm inteldialect "xor $0, $0; jmp ${1:l}", "r,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, ptr blockaddress(@test1b, %fail)) to label %normal [label %fail] + callbr void asm inteldialect "xor $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail] normal: ret i32 0 @@ -74,7 +74,7 @@ unreachableasm: %0 = add i32 %a, 4 - callbr void asm sideeffect "xorl $0, $0; jmp ${1:l}", "r,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, ptr blockaddress(@test2, %fail)) to label %normal [label %fail] + callbr void asm sideeffect "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail] normal: ret i32 0 @@ -148,11 +148,11 @@ br label %label04 label04: ; preds = %normal0, %label03 - callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}", "i,i,i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test3, %label01), ptr blockaddress(@test3, %label02), ptr blockaddress(@test3, %label03)) + callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}", "!i,!i,!i,~{dirflag},~{fpsr},~{flags}"() to label %normal0 [label %label01, label %label02, label %label03] normal0: ; preds = %label04 - callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}; jmp ${3:l}", "i,i,i,i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test3, %label01), ptr blockaddress(@test3, %label02), ptr blockaddress(@test3, %label03), ptr blockaddress(@test3, %label04)) + callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}; jmp ${3:l}", "!i,!i,!i,!i,~{dirflag},~{fpsr},~{flags}"() to label %normal1 [label %label01, label %label02, label %label03, label %label04] normal1: ; preds = %normal0 @@ -175,11 +175,11 @@ ; CHECK-NEXT: .LBB4_3: # %quux ; CHECK-NEXT: retl entry: - callbr void asm sideeffect "ja $0", "i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test4, %quux)) + callbr void asm sideeffect "ja $0", "!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough [label %quux] asm.fallthrough: ; preds = %entry - callbr void asm sideeffect "ja ${0:l}", "i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test4, %quux)) + callbr void asm sideeffect "ja ${0:l}", "!i,~{dirflag},~{fpsr},~{flags}"() to label %cleanup [label %quux] quux: ; preds = %asm.fallthrough, %entry Index: llvm/test/CodeGen/X86/callbr-asm-sink.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-sink.ll +++ llvm/test/CodeGen/X86/callbr-asm-sink.ll @@ -21,7 +21,7 @@ ; CHECK-NEXT: movq $0, -8(%rax) ; CHECK-NEXT: retq %2 = getelementptr inbounds %struct1, %struct1* %0, i64 0, i32 1 - callbr void asm sideeffect "# $0 $1", "*m,i,~{memory},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) %2, i8* blockaddress(@klist_dec_and_del, %3)) + callbr void asm sideeffect "# $0 $1", "*m,!i,~{memory},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) %2) to label %6 [label %3] 3: Index: llvm/test/CodeGen/X86/callbr-asm-phi-placement.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-phi-placement.ll +++ llvm/test/CodeGen/X86/callbr-asm-phi-placement.ll @@ -36,7 +36,7 @@ %a = phi ptr [ %arg, %entry ], [ %b, %loop ] %b = load ptr, ptr %mem, align 8 call void @foo(ptr %a) - callbr void asm sideeffect "", "*m,i"(ptr elementtype(i8) %b, ptr blockaddress(@test1, %loop)) + callbr void asm sideeffect "", "*m,!i"(ptr elementtype(i8) %b) to label %end [label %loop] end: Index: llvm/test/CodeGen/X86/callbr-asm-outputs.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-outputs.ll +++ llvm/test/CodeGen/X86/callbr-asm-outputs.ll @@ -20,7 +20,7 @@ ; CHECK-NEXT: retl entry: %add = add nsw i32 %x, 4 - %ret = callbr i32 asm "xorl $1, $0; jmp ${2:l}", "=r,r,i,~{dirflag},~{fpsr},~{flags}"(i32 %add, ptr blockaddress(@test1, %abnormal)) + %ret = callbr i32 asm "xorl $1, $0; jmp ${2:l}", "=r,r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %add) to label %normal [label %abnormal] normal: @@ -77,11 +77,11 @@ br i1 %cmp, label %if.then, label %if.else if.then: ; preds = %entry - %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "={si},={di},r,i,i,0,1,~{dirflag},~{fpsr},~{flags}"(i32 %out1, ptr blockaddress(@test2, %label_true), ptr blockaddress(@test2, %return), i32 %out1, i32 %out2) + %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "={si},={di},r,!i,!i,0,1,~{dirflag},~{fpsr},~{flags}"(i32 %out1, i32 %out1, i32 %out2) to label %if.end [label %label_true, label %return] if.else: ; preds = %entry - %1 = callbr { i32, i32 } asm sideeffect "testl $0, $1; testl $2, $3; jne ${5:l}", "={si},={di},r,r,i,i,0,1,~{dirflag},~{fpsr},~{flags}"(i32 %out1, i32 %out2, ptr blockaddress(@test2, %label_true), ptr blockaddress(@test2, %return), i32 %out1, i32 %out2) + %1 = callbr { i32, i32 } asm sideeffect "testl $0, $1; testl $2, $3; jne ${5:l}", "={si},={di},r,r,!i,!i,0,1,~{dirflag},~{fpsr},~{flags}"(i32 %out1, i32 %out2, i32 %out1, i32 %out2) to label %if.end [label %label_true, label %return] if.end: ; preds = %if.else, %if.then @@ -140,10 +140,10 @@ br i1 %cmp, label %true, label %false true: - %0 = callbr { i32, i32 } asm sideeffect ".word $0, $1", "={si},={di},i" (ptr blockaddress(@test3, %indirect)) to label %asm.fallthrough [label %indirect] + %0 = callbr { i32, i32 } asm sideeffect ".word $0, $1", "={si},={di},!i" () to label %asm.fallthrough [label %indirect] false: - %1 = callbr { i32, i32 } asm sideeffect ".word $0, $1", "={ax},={dx},i" (ptr blockaddress(@test3, %indirect)) to label %asm.fallthrough [label %indirect] + %1 = callbr { i32, i32 } asm sideeffect ".word $0, $1", "={ax},={dx},!i" () to label %asm.fallthrough [label %indirect] asm.fallthrough: %vals = phi { i32, i32 } [ %0, %true ], [ %1, %false ] @@ -182,13 +182,13 @@ ; CHECK-NEXT: .LBB3_4: # %return ; CHECK-NEXT: retl entry: - %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "=r,=r,r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %out1, ptr blockaddress(@test4, %label_true), ptr blockaddress(@test4, %return)) + %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "=r,=r,r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %out1) to label %asm.fallthrough [label %label_true, label %return] asm.fallthrough: ; preds = %entry %asmresult = extractvalue { i32, i32 } %0, 0 %asmresult1 = extractvalue { i32, i32 } %0, 1 - %1 = callbr { i32, i32 } asm sideeffect "testl $0, $1; testl $2, $3; jne ${5:l}", "=r,=r,r,r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %asmresult, i32 %asmresult1, ptr blockaddress(@test4, %label_true), ptr blockaddress(@test4, %return)) + %1 = callbr { i32, i32 } asm sideeffect "testl $0, $1; testl $2, $3; jne ${5:l}", "=r,=r,r,r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %asmresult, i32 %asmresult1) to label %asm.fallthrough2 [label %label_true, label %return] asm.fallthrough2: ; preds = %asm.fallthrough @@ -218,7 +218,7 @@ ; CHECK-NEXT: # %bb.1: ; CHECK-NEXT: retl %1 = call i32 @llvm.read_register.i32(metadata !3) - %2 = callbr i32 asm "", "={esp},X,{esp},~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test5, %4), i32 %1) + %2 = callbr i32 asm "", "={esp},!i,{esp},~{dirflag},~{fpsr},~{flags}"(i32 %1) to label %3 [label %4] 3: Index: llvm/test/CodeGen/X86/callbr-asm-outputs-pred-succ.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-outputs-pred-succ.ll +++ llvm/test/CodeGen/X86/callbr-asm-outputs-pred-succ.ll @@ -32,12 +32,12 @@ ; Function Attrs: nounwind uwtable define dso_local i32 @main(i32 %0, ptr nocapture readnone %1) #0 { - %3 = callbr i32 asm "jmp ${1:l}", "=r,i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@main, %11)) #3 + %3 = callbr i32 asm "jmp ${1:l}", "=r,!i,~{dirflag},~{fpsr},~{flags}"() #3 to label %4 [label %11] 4: ; preds = %2 %5 = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 %3) - %6 = callbr i32 asm "jmp ${1:l}", "=r,i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@main, %7)) #3 + %6 = callbr i32 asm "jmp ${1:l}", "=r,!i,~{dirflag},~{fpsr},~{flags}"() #3 to label %9 [label %7] 7: ; preds = %4 Index: llvm/test/CodeGen/X86/callbr-asm-obj-file.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-obj-file.ll +++ llvm/test/CodeGen/X86/callbr-asm-obj-file.ll @@ -8,7 +8,7 @@ define void @test1() { entry: - callbr void asm sideeffect "je ${0:l}", "i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test1, %a.b.normal.jump)) + callbr void asm sideeffect "je ${0:l}", "!i,~{dirflag},~{fpsr},~{flags}"() to label %asm.fallthrough [label %a.b.normal.jump] asm.fallthrough: Index: llvm/test/CodeGen/X86/callbr-asm-label-addr.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-label-addr.ll +++ llvm/test/CodeGen/X86/callbr-asm-label-addr.ll @@ -10,7 +10,7 @@ ; CHECK-NEXT: .Ltmp0: ; CHECK-NEXT: # %bb.2: # %baz entry: - callbr void asm sideeffect ".quad ${0:l}\0A\09.quad ${1:l}", "i,i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test1, %baz), ptr blockaddress(@test1, %bar)) + callbr void asm sideeffect ".quad ${0:l}\0A\09.quad ${1:l}", "i,!i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test1, %baz)) to label %asm.fallthrough [label %bar] asm.fallthrough: Index: llvm/test/CodeGen/X86/callbr-asm-kill.mir =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-kill.mir +++ llvm/test/CodeGen/X86/callbr-asm-kill.mir @@ -21,7 +21,7 @@ %a = phi i8* [ %arg, %entry ], [ %b, %loop ] %b = load i8*, i8** %mem, align 8 call void @foo(i8* %a) - callbr void asm sideeffect "", "*m,i"(i8* elementtype(i8) %b, i8* blockaddress(@test1, %loop)) + callbr void asm sideeffect "", "*m,!i"(i8* elementtype(i8) %b) to label %end [label %loop] end: ; preds = %loop Index: llvm/test/CodeGen/X86/callbr-asm-instr-scheduling.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-instr-scheduling.ll +++ llvm/test/CodeGen/X86/callbr-asm-instr-scheduling.ll @@ -49,7 +49,7 @@ %shr = lshr i64 %addr, %sh_prom %and = and i64 %shr, 511 %arrayidx = getelementptr %struct.pgd_t, ptr %2, i64 %and - callbr void asm sideeffect "1: jmp 6f\0A2:\0A.skip -(((5f-4f) - (2b-1b)) > 0) * ((5f-4f) - (2b-1b)),0x90\0A3:\0A.section .altinstructions,\22a\22\0A .long 1b - .\0A .long 4f - .\0A .word ${1:P}\0A .byte 3b - 1b\0A .byte 5f - 4f\0A .byte 3b - 2b\0A.previous\0A.section .altinstr_replacement,\22ax\22\0A4: jmp ${5:l}\0A5:\0A.previous\0A.section .altinstructions,\22a\22\0A .long 1b - .\0A .long 0\0A .word ${0:P}\0A .byte 3b - 1b\0A .byte 0\0A .byte 0\0A.previous\0A.section .altinstr_aux,\22ax\22\0A6:\0A testb $2,$3\0A jnz ${4:l}\0A jmp ${5:l}\0A.previous\0A", "i,i,i,*m,i,i,~{dirflag},~{fpsr},~{flags}"(i16 528, i32 117, i32 1, ptr elementtype(i8) getelementptr inbounds (%struct.cpuinfo_x86, ptr @boot_cpu_data, i64 0, i32 12, i32 1, i64 58), ptr blockaddress(@early_ioremap_pmd, %if.end.i), ptr blockaddress(@early_ioremap_pmd, %if.then.i)) + callbr void asm sideeffect "1: jmp 6f\0A2:\0A.skip -(((5f-4f) - (2b-1b)) > 0) * ((5f-4f) - (2b-1b)),0x90\0A3:\0A.section .altinstructions,\22a\22\0A .long 1b - .\0A .long 4f - .\0A .word ${1:P}\0A .byte 3b - 1b\0A .byte 5f - 4f\0A .byte 3b - 2b\0A.previous\0A.section .altinstr_replacement,\22ax\22\0A4: jmp ${5:l}\0A5:\0A.previous\0A.section .altinstructions,\22a\22\0A .long 1b - .\0A .long 0\0A .word ${0:P}\0A .byte 3b - 1b\0A .byte 0\0A .byte 0\0A.previous\0A.section .altinstr_aux,\22ax\22\0A6:\0A testb $2,$3\0A jnz ${4:l}\0A jmp ${5:l}\0A.previous\0A", "i,i,i,*m,!i,!i,~{dirflag},~{fpsr},~{flags}"(i16 528, i32 117, i32 1, ptr elementtype(i8) getelementptr inbounds (%struct.cpuinfo_x86, ptr @boot_cpu_data, i64 0, i32 12, i32 1, i64 58)) to label %_static_cpu_has.exit.thread.i [label %if.end.i, label %if.then.i] _static_cpu_has.exit.thread.i: ; preds = %entry Index: llvm/test/CodeGen/X86/callbr-asm-errors.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-errors.ll +++ /dev/null @@ -1,18 +0,0 @@ -; RUN: not llc -mtriple=i686-- < %s 2> %t -; RUN: FileCheck %s < %t - -; CHECK: Duplicate callbr destination - -; A test for asm-goto duplicate labels limitation - -define i32 @test(i32 %a) { -entry: - %0 = add i32 %a, 4 - callbr void asm "xorl $0, $0; jmp ${1:l}", "r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, ptr blockaddress(@test, %fail), ptr blockaddress(@test, %fail)) to label %normal [label %fail, label %fail] - -normal: - ret i32 %0 - -fail: - ret i32 1 -} Index: llvm/test/CodeGen/X86/callbr-asm-destinations.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-destinations.ll +++ llvm/test/CodeGen/X86/callbr-asm-destinations.ll @@ -1,14 +1,49 @@ -; RUN: not llc -mtriple=i686-- < %s 2> %t -; RUN: FileCheck %s < %t +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=i686-- -verify-machineinstrs < %s | FileCheck %s -; CHECK: Duplicate callbr destination +define i32 @duplicate_normal_and_indirect_dest(i32 %a) { +; CHECK-LABEL: duplicate_normal_and_indirect_dest: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: addl $4, %eax +; CHECK-NEXT: #APP +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: jmp .Ltmp0 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: .Ltmp0: # Block address taken +; CHECK-NEXT: # %bb.1: # %fail +; CHECK-NEXT: movl $1, %eax +; CHECK-NEXT: retl +entry: + %0 = add i32 %a, 4 + callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %fail [label %fail] -; A test for asm-goto duplicate labels limitation +fail: + ret i32 1 +} -define i32 @test(i32 %a) { +define i32 @duplicate_indirect_dest(i32 %a) { +; CHECK-LABEL: duplicate_indirect_dest: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: addl $4, %eax +; CHECK-NEXT: #APP +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: jmp .Ltmp1 +; CHECK-NEXT: jmp .Ltmp1 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: # %bb.1: # %normal +; CHECK-NEXT: retl +; CHECK-NEXT: .Ltmp1: # Block address taken +; CHECK-NEXT: .LBB1_2: # %fail +; CHECK-NEXT: movl $1, %eax +; CHECK-NEXT: retl entry: %0 = add i32 %a, 4 - callbr void asm "xorl $0, $0; jmp ${1:l}", "r,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, ptr blockaddress(@test, %fail)) to label %fail [label %fail] + callbr void asm "xorl $0, $0; jmp ${1:l}; jmp ${2:l}", "r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail, label %fail] + +normal: + ret i32 %0 fail: ret i32 1 Index: llvm/test/CodeGen/X86/callbr-asm-branch-folding.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-branch-folding.ll +++ llvm/test/CodeGen/X86/callbr-asm-branch-folding.ll @@ -116,7 +116,7 @@ br i1 %tobool13, label %if.else, label %if.then14 if.then14: ; preds = %if.end12 - callbr void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@n, %if.then20.critedge)) + callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"() to label %cleanup [label %if.then20.critedge] if.then20.critedge: ; preds = %if.then14 Index: llvm/test/CodeGen/X86/callbr-asm-blockplacement.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-blockplacement.ll +++ llvm/test/CodeGen/X86/callbr-asm-blockplacement.ll @@ -85,7 +85,7 @@ bb15: ; preds = %bb8 %tmp16 = getelementptr [0 x %struct.wibble], ptr @global, i64 0, i64 %tmp4, i32 2 store ptr %tmp9, ptr %tmp16 - callbr void asm sideeffect "", "i"(ptr blockaddress(@foo, %bb18)) + callbr void asm sideeffect "", "!i"() to label %bb17 [label %bb18] bb17: ; preds = %bb15 Index: llvm/test/CodeGen/X86/callbr-asm-bb-exports.ll =================================================================== --- llvm/test/CodeGen/X86/callbr-asm-bb-exports.ll +++ llvm/test/CodeGen/X86/callbr-asm-bb-exports.ll @@ -17,14 +17,14 @@ ; CHECK-NEXT: t2: i32,ch = CopyFromReg t0, Register:i32 %2 ; CHECK-NEXT: t8: i32 = add t2, Constant:i32<4> ; CHECK-NEXT: t22: ch,glue = CopyToReg t17, Register:i32 %5, t8 -; CHECK-NEXT: t30: ch,glue = inlineasm_br t22, TargetExternalSymbol:i64'xorl $0, $0; jmp ${1:l}', MDNode:ch<null>, TargetConstant:i64<8>, TargetConstant:i32<2359305>, Register:i32 %5, TargetConstant:i64<13>, TargetBlockAddress:i64<@test, %fail> 0, TargetConstant:i32<12>, Register:i32 $df, TargetConstant:i32<12>, Register:i16 $fpsw, TargetConstant:i32<12>, Register:i32 $eflags, t22:1 +; CHECK-NEXT: t30: ch,glue = inlineasm_br t22, TargetExternalSymbol:i64'xorl $0, $0; jmp ${1:l}', MDNode:ch<null>, TargetConstant:i64<0>, TargetConstant:i32<2359305>, Register:i32 %5, TargetConstant:i64<13>, TargetBlockAddress:i64<@test, %fail> 0, TargetConstant:i32<12>, Register:i32 $df, TargetConstant:i32<12>, Register:i16 $fpsw, TargetConstant:i32<12>, Register:i32 $eflags, t22:1 define i32 @test(i32 %a, i32 %b, i32 %c) { entry: %0 = add i32 %a, 4 %1 = add i32 %b, 1 %2 = add i32 %c, 1 - callbr void asm "xorl $0, $0; jmp ${1:l}", "r,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, ptr blockaddress(@test, %fail)) to label %normal [label %fail] + callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail] normal: ret i32 %1 Index: llvm/test/CodeGen/SystemZ/asm-20.ll =================================================================== --- llvm/test/CodeGen/SystemZ/asm-20.ll +++ llvm/test/CodeGen/SystemZ/asm-20.ll @@ -4,7 +4,7 @@ define i32 @c() { entry: - callbr void asm sideeffect "j d", "i"(i8* blockaddress(@c, %d)) + callbr void asm sideeffect "j d", "!i"() to label %asm.fallthrough [label %d] asm.fallthrough: ; preds = %entry Index: llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll =================================================================== --- llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll +++ llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll @@ -111,7 +111,7 @@ ; PPC64BE-NEXT: li r3, 0 ; PPC64BE-NEXT: b .LBB3_1 entry: - callbr void asm sideeffect "nop", "i,~{lr}"(i8* blockaddress(@ClobberLR_BR, %return_early)) + callbr void asm sideeffect "nop", "!i,~{lr}"() to label %return [label %return_early] return_early: @@ -151,7 +151,7 @@ ; PPC64BE-NEXT: extsw r3, r3 ; PPC64BE-NEXT: blr entry: - callbr void asm sideeffect "nop", "i,~{r5}"(i8* blockaddress(@ClobberR5_BR, %return_early)) + callbr void asm sideeffect "nop", "!i,~{r5}"() to label %return [label %return_early] return_early: Index: llvm/test/CodeGen/ARM/speculation-hardening-sls.ll =================================================================== --- llvm/test/CodeGen/ARM/speculation-hardening-sls.ll +++ llvm/test/CodeGen/ARM/speculation-hardening-sls.ll @@ -89,7 +89,7 @@ define i32 @asmgoto() { entry: ; CHECK-LABEL: asmgoto: - callbr void asm sideeffect "B $0", "i"(i8* blockaddress(@asmgoto, %d)) + callbr void asm sideeffect "B $0", "!i"() to label %asm.fallthrough [label %d] ; The asm goto above produces a direct branch: ; CHECK: @APP Index: llvm/test/CodeGen/AArch64/speculation-hardening-sls.ll =================================================================== --- llvm/test/CodeGen/AArch64/speculation-hardening-sls.ll +++ llvm/test/CodeGen/AArch64/speculation-hardening-sls.ll @@ -89,7 +89,7 @@ define i32 @asmgoto() { entry: ; CHECK-LABEL: asmgoto: - callbr void asm sideeffect "B $0", "i"(i8* blockaddress(@asmgoto, %d)) + callbr void asm sideeffect "B $0", "!i"() to label %asm.fallthrough [label %d] ; The asm goto above produces a direct branch: ; CHECK: //APP Index: llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll =================================================================== --- llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll +++ llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll @@ -20,7 +20,7 @@ br i1 %2, label %3, label %5 3: ; preds = %0 - callbr void asm sideeffect "1: nop\0A\09.quad a\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,i"(i32* null, i8* blockaddress(@test1, %7)) + callbr void asm sideeffect "1: nop\0A\09.quad a\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,!i"(i32* null) to label %4 [label %7] 4: ; preds = %3 @@ -55,7 +55,7 @@ br i1 %5, label %6, label %7 6: ; preds = %3 - callbr void asm sideeffect "1: nop\0A\09.quad b\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,i"(i32* null, i8* blockaddress(@test2, %7)) + callbr void asm sideeffect "1: nop\0A\09.quad b\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,!i"(i32* null) to label %10 [label %7] 7: ; preds = %3 @@ -83,7 +83,7 @@ br i1 %2, label %3, label %5 3: ; preds = %0 - callbr void asm sideeffect "1: nop\0A\09.quad c\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,i"(i32* null, i8* blockaddress(@test3, %8)) + callbr void asm sideeffect "1: nop\0A\09.quad c\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,!i"(i32* null) to label %4 [label %8] 4: ; preds = %3 Index: llvm/test/CodeGen/AArch64/callbr-asm-label.ll =================================================================== --- llvm/test/CodeGen/AArch64/callbr-asm-label.ll +++ llvm/test/CodeGen/AArch64/callbr-asm-label.ll @@ -10,7 +10,7 @@ ; CHECK: .Ltmp0: ; CHECK: .LBB0_2: // %indirect entry: - callbr void asm sideeffect "1:\0A\09.word b, ${0:l}\0A\09", "i"(i8* blockaddress(@test1, %indirect)) + callbr void asm sideeffect "1:\0A\09.word b, ${0:l}\0A\09", "!i"() to label %cleanup [label %indirect] indirect: @@ -34,7 +34,7 @@ ; CHECK-NEXT: .word .Ltmp2 ; CHECK: .Ltmp2: ; CHECK-NEXT: .LBB1_3: // %if.end6 - callbr void asm sideeffect "1:\0A\09.word b, ${0:l}\0A\09", "i"(i8* blockaddress(@test2, %if.end6)) + callbr void asm sideeffect "1:\0A\09.word b, ${0:l}\0A\09", "!i"() to label %if.then4 [label %if.end6] if.then4: @@ -50,7 +50,7 @@ if.then9: ; CHECK: .Ltmp4: ; CHECK-NEXT: .LBB1_5: // %l_yes - callbr void asm sideeffect "", "i"(i8* blockaddress(@test2, %l_yes)) + callbr void asm sideeffect "", "!i"() to label %if.end10 [label %l_yes] if.end10: Index: llvm/test/Bitcode/callbr.ll =================================================================== --- llvm/test/Bitcode/callbr.ll +++ llvm/test/Bitcode/callbr.ll @@ -6,10 +6,9 @@ define i32 @test_asm_goto(i32 %x){ entry: -; CHECK-TYPED: callbr void asm "", "r,i"(i32 %x, i8* blockaddress(@test_asm_goto, %fail)) -; CHECK-OPAQUE: callbr void asm "", "r,i"(i32 %x, ptr blockaddress(@test_asm_goto, %fail)) +; CHECK: callbr void asm "", "r,!i"(i32 %x) ; CHECK-NEXT: to label %normal [label %fail] - callbr void asm "", "r,i"(i32 %x, i8* blockaddress(@test_asm_goto, %fail)) to label %normal [label %fail] + callbr void asm "", "r,!i"(i32 %x) to label %normal [label %fail] normal: ret i32 1 fail: @@ -18,10 +17,9 @@ define i32 @test_asm_goto2(i32 %x){ entry: -; CHECK-TYPED: callbr void asm "", "r,i,i"(i32 %x, i8* blockaddress(@test_asm_goto2, %fail), i8* blockaddress(@test_asm_goto2, %fail2)) -; CHECK-OPAQUE: callbr void asm "", "r,i,i"(i32 %x, ptr blockaddress(@test_asm_goto2, %fail), ptr blockaddress(@test_asm_goto2, %fail2)) +; CHECK: callbr void asm "", "r,!i,!i"(i32 %x) ; CHECK-NEXT: to label %normal [label %fail, label %fail2] - callbr void asm "", "r,i,i"(i32 %x, i8* blockaddress(@test_asm_goto2, %fail), i8* blockaddress(@test_asm_goto2, %fail2)) to label %normal [label %fail, label %fail2] + callbr void asm "", "r,!i,!i"(i32 %x) to label %normal [label %fail, label %fail2] normal: ret i32 1 fail: @@ -32,10 +30,10 @@ define i32 @test_asm_goto3(i32 %x){ entry: -; CHECK-TYPED: callbr void asm "", "r,i,i"(i32 %x, i8* blockaddress(@test_asm_goto3, %unrelated), i8* blockaddress(@test_asm_goto3, %fail)) -; CHECK-OPAQUE: callbr void asm "", "r,i,i"(i32 %x, ptr blockaddress(@test_asm_goto3, %unrelated), ptr blockaddress(@test_asm_goto3, %fail)) +; CHECK-TYPED: callbr void asm "", "r,i,!i"(i32 %x, i8* blockaddress(@test_asm_goto3, %unrelated)) +; CHECK-OPAQUE: callbr void asm "", "r,i,!i"(i32 %x, ptr blockaddress(@test_asm_goto3, %unrelated)) ; CHECK-NEXT: to label %normal [label %fail] - callbr void asm "", "r,i,i"(i32 %x, i8* blockaddress(@test_asm_goto3, %unrelated), i8* blockaddress(@test_asm_goto3, %fail)) to label %normal [label %fail] + callbr void asm "", "r,i,!i"(i32 %x, i8* blockaddress(@test_asm_goto3, %unrelated)) to label %normal [label %fail] normal: ret i32 1 fail: Index: llvm/test/Assembler/inline-asm-constraint-error.ll =================================================================== --- llvm/test/Assembler/inline-asm-constraint-error.ll +++ llvm/test/Assembler/inline-asm-constraint-error.ll @@ -6,6 +6,8 @@ ; RUN: not llvm-as < %t/cannot-be-struct.ll 2>&1 | FileCheck %s --check-prefix=CHECK-CANNOT-BE-STRUCT ; RUN: not llvm-as < %t/incorrect-struct-elements.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INCORRECT-STRUCT-ELEMENTS ; RUN: not llvm-as < %t/incorrect-arg-num.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INCORRECT-ARG-NUM +; RUN: not llvm-as < %t/label-after-clobber.ll 2>&1 | FileCheck %s --check-prefix=CHECK-LABEL-AFTER-CLOBBER +; RUN: not llvm-as < %t/output-after-label.ll 2>&1 | FileCheck %s --check-prefix=CHECK-OUTPUT-AFTER-LABEL ;--- parse-fail.ll ; CHECK-PARSE-FAIL: failed to parse constraints @@ -16,7 +18,7 @@ } ;--- input-before-output.ll -; CHECK-INPUT-BEFORE-OUTPUT: output constraint occurs after input or clobber constraint +; CHECK-INPUT-BEFORE-OUTPUT: output constraint occurs after input, clobber or label constraint define void @foo() { call void asm sideeffect "mov x0, #42", "r,=r"() ret void @@ -56,3 +58,25 @@ call void asm sideeffect "mov x0, #42", "r"() ret void } + +;--- label-after-clobber.ll +; CHECK-LABEL-AFTER-CLOBBER: label constraint occurs after clobber constraint +define void @foo() { + callbr void asm sideeffect "", "~{flags},!i"() + to label %1 [label %2] +1: + ret void +2: + ret void +} + +;--- output-after-label.ll +; CHECK-OUTPUT-AFTER-LABEL: output constraint occurs after input, clobber or label constraint +define void @foo() { + %res = callbr i32 asm sideeffect "", "!i,=r,~{flags}"() + to label %1 [label %2] +1: + ret void +2: + ret void +} Index: llvm/test/Assembler/call-arg-is-callee.ll =================================================================== --- llvm/test/Assembler/call-arg-is-callee.ll +++ llvm/test/Assembler/call-arg-is-callee.ll @@ -26,9 +26,7 @@ ; verifier prevents duplicating callbr destinations. define void @callbr() { entry: - callbr i32 asm "", "=r,r,i,i"(i32 0, - i8 *blockaddress(@callbr, %two), - i8 *blockaddress(@callbr, %three)) + callbr i32 asm "", "=r,r,!i,!i"(i32 0) to label %one [label %two, label %three] one: ret void Index: llvm/test/Analysis/BasicAA/pr52735.ll =================================================================== --- llvm/test/Analysis/BasicAA/pr52735.ll +++ llvm/test/Analysis/BasicAA/pr52735.ll @@ -11,14 +11,14 @@ target triple = "x86_64-unknown-linux-gnu" -; CHECK: Both ModRef: Ptr: i32* %v <-> callbr void asm "movl $$1, $0", "=*m,X,~{dirflag},~{fpsr},~{flags}"(i32* nonnull elementtype(i32) %v, i8* blockaddress(@foo, %out)) +; CHECK: Both ModRef: Ptr: i32* %v <-> callbr void asm "movl $$1, $0", "=*m,!i,~{dirflag},~{fpsr},~{flags}"(i32* nonnull elementtype(i32) %v) define dso_local i32 @foo() { entry: %v = alloca i32, align 4 %0 = bitcast i32* %v to i8* - callbr void asm "movl $$1, $0", "=*m,X,~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) nonnull %v, i8* blockaddress(@foo, %out)) + callbr void asm "movl $$1, $0", "=*m,!i,~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) nonnull %v) to label %asm.fallthrough [label %out] asm.fallthrough: Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -2200,7 +2200,13 @@ void Verifier::verifyInlineAsmCall(const CallBase &Call) { const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand()); unsigned ArgNo = 0; + unsigned LabelNo = 0; for (const InlineAsm::ConstraintInfo &CI : IA->ParseConstraints()) { + if (CI.Type == InlineAsm::isLabel) { + ++LabelNo; + continue; + } + // Only deal with constraints that correspond to call arguments. if (!CI.hasArg()) continue; @@ -2222,6 +2228,15 @@ ArgNo++; } + + if (auto *CallBr = dyn_cast<CallBrInst>(&Call)) { + Check(LabelNo == CallBr->getNumIndirectDests(), + "Number of label constraints does not match number of callbr dests", + &Call); + } else { + Check(LabelNo == 0, "Label constraints can only be used with callbr", + &Call); + } } /// Verify that statepoint intrinsic is well formed. @@ -2839,25 +2854,6 @@ Check(CBI.isInlineAsm(), "Callbr is currently only used for asm-goto!", &CBI); const InlineAsm *IA = cast<InlineAsm>(CBI.getCalledOperand()); Check(!IA->canThrow(), "Unwinding from Callbr is not allowed"); - for (unsigned i = 0, e = CBI.getNumSuccessors(); i != e; ++i) - Check(CBI.getSuccessor(i)->getType()->isLabelTy(), - "Callbr successors must all have pointer type!", &CBI); - for (unsigned i = 0, e = CBI.getNumOperands(); i != e; ++i) { - Check(i >= CBI.arg_size() || !isa<BasicBlock>(CBI.getOperand(i)), - "Using an unescaped label as a callbr argument!", &CBI); - if (isa<BasicBlock>(CBI.getOperand(i))) - for (unsigned j = i + 1; j != e; ++j) - Check(CBI.getOperand(i) != CBI.getOperand(j), - "Duplicate callbr destination!", &CBI); - } - { - SmallPtrSet<BasicBlock *, 4> ArgBBs; - for (Value *V : CBI.args()) - if (auto *BA = dyn_cast<BlockAddress>(V)) - ArgBBs.insert(BA->getBasicBlock()); - for (BasicBlock *BB : CBI.getIndirectDests()) - Check(ArgBBs.count(BB), "Indirect label missing from arglist.", &CBI); - } verifyInlineAsmCall(CBI); visitTerminator(CBI); Index: llvm/lib/IR/Instructions.cpp =================================================================== --- llvm/lib/IR/Instructions.cpp +++ llvm/lib/IR/Instructions.cpp @@ -960,15 +960,10 @@ setName(NameStr); } -void CallBrInst::updateArgBlockAddresses(unsigned i, BasicBlock *B) { - assert(getNumIndirectDests() > i && "IndirectDest # out of range for callbr"); - if (BasicBlock *OldBB = getIndirectDest(i)) { - BlockAddress *Old = BlockAddress::get(OldBB); - BlockAddress *New = BlockAddress::get(B); - for (unsigned ArgNo = 0, e = arg_size(); ArgNo != e; ++ArgNo) - if (dyn_cast<BlockAddress>(getArgOperand(ArgNo)) == Old) - setArgOperand(ArgNo, New); - } +BlockAddress * +CallBrInst::getBlockAddressForIndirectDest(unsigned DestNo) const { + return BlockAddress::get(const_cast<Function *>(getFunction()), + getIndirectDest(DestNo)); } CallBrInst::CallBrInst(const CallBrInst &CBI) Index: llvm/lib/IR/InlineAsm.cpp =================================================================== --- llvm/lib/IR/InlineAsm.cpp +++ llvm/lib/IR/InlineAsm.cpp @@ -93,6 +93,9 @@ } else if (*I == '=') { ++I; Type = isOutput; + } else if (*I == '!') { + ++I; + Type = isLabel; } if (*I == '*') { @@ -265,14 +268,14 @@ return makeStringError("failed to parse constraints"); unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0; - unsigned NumIndirect = 0; + unsigned NumIndirect = 0, NumLabels = 0; for (const ConstraintInfo &Constraint : Constraints) { switch (Constraint.Type) { case InlineAsm::isOutput: - if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0) - return makeStringError("output constraint occurs after input " - "or clobber constraint"); + if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0 || NumLabels != 0) + return makeStringError("output constraint occurs after input, " + "clobber or label constraint"); if (!Constraint.isIndirect) { ++NumOutputs; @@ -289,6 +292,13 @@ case InlineAsm::isClobber: ++NumClobbers; break; + case InlineAsm::isLabel: + if (NumClobbers) + return makeStringError("label constraint occurs after clobber " + "constraint"); + + ++NumLabels; + break; } } @@ -312,5 +322,7 @@ if (Ty->getNumParams() != NumInputs) return makeStringError("number of input constraints does not match number " "of parameters"); + + // We don't have access to labels here, NumLabels will be checked separately. return Error::success(); } Index: llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -5224,6 +5224,7 @@ // ConstraintOperands list. unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. unsigned ResNo = 0; // ResNo - The result number of the next output. + unsigned LabelNo = 0; // LabelNo - CallBr indirect dest number. for (InlineAsm::ConstraintInfo &CI : IA->ParseConstraints()) { ConstraintOperands.emplace_back(std::move(CI)); @@ -5260,6 +5261,14 @@ case InlineAsm::isInput: OpInfo.CallOperandVal = Call.getArgOperand(ArgNo); break; + case InlineAsm::isLabel: + OpInfo.CallOperandVal = + cast<CallBrInst>(&Call)->getBlockAddressForIndirectDest(LabelNo); + OpInfo.ConstraintVT = + getAsmOperandValueType(DL, OpInfo.CallOperandVal->getType()) + .getSimpleVT(); + ++LabelNo; + continue; case InlineAsm::isClobber: // Nothing to do. break; Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2990,14 +2990,20 @@ CopyToExportRegsIfNeeded(&I); // Retrieve successors. + SmallPtrSet<BasicBlock *, 8> Dests; + Dests.insert(I.getDefaultDest()); MachineBasicBlock *Return = FuncInfo.MBBMap[I.getDefaultDest()]; // Update successor info. addSuccessorWithProb(CallBrMBB, Return, BranchProbability::getOne()); for (unsigned i = 0, e = I.getNumIndirectDests(); i < e; ++i) { - MachineBasicBlock *Target = FuncInfo.MBBMap[I.getIndirectDest(i)]; - addSuccessorWithProb(CallBrMBB, Target, BranchProbability::getZero()); + BasicBlock *Dest = I.getIndirectDest(i); + MachineBasicBlock *Target = FuncInfo.MBBMap[Dest]; Target->setIsInlineAsmBrIndirectTarget(); + Target->setHasAddressTaken(); + // Don't add duplicate machine successors. + if (Dests.insert(Dest).second) + addSuccessorWithProb(CallBrMBB, Target, BranchProbability::getZero()); } CallBrMBB->normalizeSuccProbs(); @@ -8855,7 +8861,8 @@ } break; - case InlineAsm::isInput: { + case InlineAsm::isInput: + case InlineAsm::isLabel: { SDValue InOperandVal = OpInfo.CallOperand; if (OpInfo.isMatchingInputConstraint()) { Index: llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp +++ llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp @@ -332,6 +332,8 @@ } ++ResNo; } else { + assert(OpInfo.Type != InlineAsm::isLabel && + "GlobalISel currently doesn't support callbr"); OpInfo.ConstraintVT = MVT::Other; } @@ -427,7 +429,8 @@ } break; - case InlineAsm::isInput: { + case InlineAsm::isInput: + case InlineAsm::isLabel: { if (OpInfo.isMatchingInputConstraint()) { unsigned DefIdx = OpInfo.getMatchedOperand(); // Find operand with register def that corresponds to DefIdx. Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -5510,6 +5510,61 @@ if (!OperandBundles.empty()) UpgradeOperandBundles(OperandBundles); + if (auto *IA = dyn_cast<InlineAsm>(Callee)) { + InlineAsm::ConstraintInfoVector ConstraintInfo = IA->ParseConstraints(); + auto IsLabelConstraint = [](const InlineAsm::ConstraintInfo &CI) { + return CI.Type == InlineAsm::isLabel; + }; + if (none_of(ConstraintInfo, IsLabelConstraint)) { + // Upgrade explicit blockaddress arguments to label constraints. + // Verify that the last arguments are blockaddress arguments that + // match the indirect destinations. Clang always generates callbr + // in this form. We could support reordering with more effort. + unsigned FirstBlockArg = Args.size() - IndirectDests.size(); + for (unsigned ArgNo = FirstBlockArg; ArgNo < Args.size(); ++ArgNo) { + unsigned LabelNo = ArgNo - FirstBlockArg; + auto *BA = dyn_cast<BlockAddress>(Args[ArgNo]); + if (!BA || BA->getFunction() != F || + LabelNo > IndirectDests.size() || + BA->getBasicBlock() != IndirectDests[LabelNo]) + return error("callbr argument does not match indirect dest"); + } + + // Remove blockaddress arguments. + Args.erase(Args.begin() + FirstBlockArg, Args.end()); + ArgTyIDs.erase(ArgTyIDs.begin() + FirstBlockArg, ArgTyIDs.end()); + + // Recreate the function type with less arguments. + SmallVector<Type *> ArgTys; + for (Value *Arg : Args) + ArgTys.push_back(Arg->getType()); + FTy = + FunctionType::get(FTy->getReturnType(), ArgTys, FTy->isVarArg()); + + // Update constraint string to use label constraints. + std::string Constraints = IA->getConstraintString(); + unsigned ArgNo = 0; + size_t Pos = 0; + for (const auto &CI : ConstraintInfo) { + if (CI.hasArg()) { + if (ArgNo >= FirstBlockArg) + Constraints.insert(Pos, "!"); + ++ArgNo; + } + + // Go to next constraint in string. + Pos = Constraints.find(',', Pos); + if (Pos == std::string::npos) + break; + ++Pos; + } + + Callee = InlineAsm::get(FTy, IA->getAsmString(), Constraints, + IA->hasSideEffects(), IA->isAlignStack(), + IA->getDialect(), IA->canThrow()); + } + } + I = CallBrInst::Create(FTy, Callee, DefaultDest, IndirectDests, Args, OperandBundles); ResTypeID = getContainedTypeID(FTyID); Index: llvm/include/llvm/IR/Instructions.h =================================================================== --- llvm/include/llvm/IR/Instructions.h +++ llvm/include/llvm/IR/Instructions.h @@ -44,6 +44,7 @@ class APFloat; class APInt; class BasicBlock; +class BlockAddress; class ConstantInt; class DataLayout; class StringRef; @@ -4004,9 +4005,6 @@ ArrayRef<BasicBlock *> IndirectDests, ArrayRef<Value *> Args, ArrayRef<OperandBundleDef> Bundles, const Twine &NameStr); - /// Should the Indirect Destinations change, scan + update the Arg list. - void updateArgBlockAddresses(unsigned i, BasicBlock *B); - /// Compute the number of operands to allocate. static int ComputeNumOperands(int NumArgs, int NumIndirectDests, int NumBundleInputs = 0) { @@ -4154,7 +4152,6 @@ *(&Op<-1>() - getNumIndirectDests() - 1) = reinterpret_cast<Value *>(B); } void setIndirectDest(unsigned i, BasicBlock *B) { - updateArgBlockAddresses(i, B); *(&Op<-1>() - getNumIndirectDests() + i) = reinterpret_cast<Value *>(B); } @@ -4172,6 +4169,8 @@ unsigned getNumSuccessors() const { return getNumIndirectDests() + 1; } + BlockAddress *getBlockAddressForIndirectDest(unsigned DestNo) const; + // Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::CallBr); Index: llvm/include/llvm/IR/InlineAsm.h =================================================================== --- llvm/include/llvm/IR/InlineAsm.h +++ llvm/include/llvm/IR/InlineAsm.h @@ -92,7 +92,8 @@ enum ConstraintPrefix { isInput, // 'x' isOutput, // '=x' - isClobber // '~x' + isClobber, // '~x' + isLabel, // '!x' }; using ConstraintCodeVector = std::vector<std::string>; @@ -117,7 +118,7 @@ using ConstraintInfoVector = std::vector<ConstraintInfo>; struct ConstraintInfo { - /// Type - The basic type of the constraint: input/output/clobber + /// Type - The basic type of the constraint: input/output/clobber/label /// ConstraintPrefix Type = isInput; Index: llvm/docs/ReleaseNotes.rst =================================================================== --- llvm/docs/ReleaseNotes.rst +++ llvm/docs/ReleaseNotes.rst @@ -84,6 +84,18 @@ * Added the support for ``fmax`` and ``fmin`` in ``atomicrmw`` instruction. The comparison is expected to match the behavior of ``llvm.maxnum.*`` and ``llvm.minnum.*`` respectively. +* ``callbr`` instructions no longer use ``blockaddress`` arguments for labels. + Instead, label constraints starting with ``!`` refer directly to entries in + the ``callbr`` indirect destination list. + +.. code-block:: llvm + + ; Old representation + %res = callbr i32 asm "", "=r,r,i"(i32 %x, i8 *blockaddress(@foo, %indirect)) + to label %fallthrough [label %indirect] + ; New representation + %res = callbr i32 asm "", "=r,r,!i"(i32 %x) + to label %fallthrough [label %indirect] Changes to building LLVM ------------------------ Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -4695,6 +4695,17 @@ Note that clobbering named registers that are also present in output constraints is not legal. +Label constraints +""""""""""""""""" + +A label constraint is indicated by a "``!``" prefix and typically used in the +form ``"!i"``. Instead of consuming call arguments, label constraints consume +indirect destination labels of ``callbr`` instructions. + +Label constraints can only be used in conjunction with ``callbr`` and the +number of label constraints must match the number of indirect destination +labels in the ``callbr`` instruction. + Constraint Codes """""""""""""""" @@ -8416,8 +8427,8 @@ #. '``fallthrough label``': the label reached when the inline assembly's execution exits the bottom. #. '``indirect labels``': the labels reached when a callee transfers control - to a location other than the '``fallthrough label``'. The blockaddress - constant for these should also be in the list of '``function args``'. + to a location other than the '``fallthrough label``'. Label constraints + refer to these destinations. #. The optional :ref:`function attributes <fnattrs>` list. #. The optional :ref:`operand bundles <opbundles>` list. @@ -8442,11 +8453,11 @@ .. code-block:: llvm ; "asm goto" without output constraints. - callbr void asm "", "r,X"(i32 %x, i8 *blockaddress(@foo, %indirect)) + callbr void asm "", "r,!i"(i32 %x) to label %fallthrough [label %indirect] ; "asm goto" with output constraints. - <result> = callbr i32 asm "", "=r,r,X"(i32 %x, i8 *blockaddress(@foo, %indirect)) + <result> = callbr i32 asm "", "=r,r,!i"(i32 %x) to label %fallthrough [label %indirect] .. _i_resume: Index: clang/test/Modules/asm-goto.c =================================================================== --- clang/test/Modules/asm-goto.c +++ clang/test/Modules/asm-goto.c @@ -4,7 +4,7 @@ #include "a.h" // CHECK-LABEL: define {{.*}} @foo( -// CHECK: callbr {{.*}} "=r,i{{.*}} blockaddress(@foo, %indirect)) +// CHECK: callbr {{.*}} "=r,!i{{.*}}() // CHECK-NEXT: to label %asm.fallthrough [label %indirect] int bar(void) { Index: clang/test/CodeGen/asm.c =================================================================== --- clang/test/CodeGen/asm.c +++ clang/test/CodeGen/asm.c @@ -267,7 +267,8 @@ int t32(int cond) { asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop); - // CHECK: callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@t32, %label_true), i8* blockaddress(@t32, %loop)) #1 + // CHECK: callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) #1 + // CHECK-NEXT: to label %asm.fallthrough [label %label_true, label %loop] return 0; loop: return 0; Index: clang/test/CodeGen/asm-goto.c =================================================================== --- clang/test/CodeGen/asm-goto.c +++ clang/test/CodeGen/asm-goto.c @@ -55,14 +55,14 @@ int test4(int out1, int out2) { // CHECK-LABEL: define{{.*}} i32 @test4( - // CHECK: callbr { i32, i32 } asm sideeffect "jne ${5:l}", "={si},={di},r,0,1,i,i + // CHECK: callbr { i32, i32 } asm sideeffect "jne ${5:l}", "={si},={di},r,0,1,!i,!i // CHECK: to label %asm.fallthrough [label %label_true, label %loop] // CHECK-LABEL: asm.fallthrough: if (out1 < out2) asm volatile goto("jne %l5" : "+S"(out1), "+D"(out2) : "r"(out1) :: label_true, loop); else asm volatile goto("jne %l7" : "+S"(out1), "+D"(out2) : "r"(out1), "r"(out2) :: label_true, loop); - // CHECK: callbr { i32, i32 } asm sideeffect "jne ${7:l}", "={si},={di},r,r,0,1,i,i + // CHECK: callbr { i32, i32 } asm sideeffect "jne ${7:l}", "={si},={di},r,r,0,1,!i,!i // CHECK: to label %asm.fallthrough2 [label %label_true, label %loop] // CHECK-LABEL: asm.fallthrough2: return out1 + out2; @@ -74,7 +74,7 @@ int test5(int addr, int size, int limit) { // CHECK-LABEL: define{{.*}} i32 @test5( - // CHECK: callbr i32 asm "add $1,$0 ; jc ${4:l} ; cmp $2,$0 ; ja ${4:l} ; ", "=r,imr,imr,0,i + // CHECK: callbr i32 asm "add $1,$0 ; jc ${4:l} ; cmp $2,$0 ; ja ${4:l} ; ", "=r,imr,imr,0,!i // CHECK: to label %asm.fallthrough [label %t_err] // CHECK-LABEL: asm.fallthrough: asm goto( @@ -92,7 +92,7 @@ int test6(int out1) { // CHECK-LABEL: define{{.*}} i32 @test6( - // CHECK: callbr i32 asm sideeffect "testl $0, $0; testl $1, $1; jne ${3:l}", "={si},r,0,i,i,{{.*}} i8* blockaddress(@test6, %label_true), i8* blockaddress(@test6, %landing) + // CHECK: callbr i32 asm sideeffect "testl $0, $0; testl $1, $1; jne ${3:l}", "={si},r,0,!i,!i,{{.*}} // CHECK: to label %asm.fallthrough [label %label_true, label %landing] // CHECK-LABEL: asm.fallthrough: // CHECK-LABEL: landing: @@ -110,7 +110,7 @@ // string, not $1. void *test7(void) { // CHECK-LABEL: define{{.*}} i8* @test7( - // CHECK: %1 = callbr i8* asm "# $0\0A\09# ${2:l}", "=r,0,i,~{dirflag},~{fpsr},~{flags}"(i8* %0, i8* blockaddress(@test7, %foo)) + // CHECK: %1 = callbr i8* asm "# $0\0A\09# ${2:l}", "=r,0,!i,~{dirflag},~{fpsr},~{flags}"(i8* %0) // CHECK-NEXT: to label %asm.fallthrough [label %foo] void *p = &&foo; asm goto ("# %0\n\t# %l2":"+r"(p):::foo); @@ -122,7 +122,7 @@ // numbered outputs. void *test8(void) { // CHECK-LABEL: define{{.*}} i8* @test8( - // CHECK: %1 = callbr i8* asm "# $0\0A\09# ${2:l}", "=r,0,i,~{dirflag},~{fpsr},~{flags}"(i8* %0, i8* blockaddress(@test8, %foo)) + // CHECK: %1 = callbr i8* asm "# $0\0A\09# ${2:l}", "=r,0,!i,~{dirflag},~{fpsr},~{flags}"(i8* %0) // CHECK-NEXT: to label %asm.fallthrough [label %foo] void *p = &&foo; asm goto ("# %0\n\t# %l[foo]":"+r"(p):::foo); Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -2603,14 +2603,9 @@ for (const auto *E : GS->labels()) { JumpDest Dest = getJumpDestForLabel(E->getLabel()); Transfer.push_back(Dest.getBlock()); - llvm::BlockAddress *BA = - llvm::BlockAddress::get(CurFn, Dest.getBlock()); - Args.push_back(BA); - ArgTypes.push_back(BA->getType()); - ArgElemTypes.push_back(nullptr); if (!Constraints.empty()) Constraints += ','; - Constraints += 'i'; + Constraints += "!i"; } Fallthrough = createBasicBlock("asm.fallthrough"); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits