summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/docs/LangRef.rst7
-rw-r--r--llvm/lib/IR/Verifier.cpp9
-rw-r--r--llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll28
-rw-r--r--llvm/test/Verifier/callbr.ll50
4 files changed, 77 insertions, 17 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index ac1db593ac8..59c4469fb9f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -7070,7 +7070,7 @@ Syntax:
::
<result> = callbr [cconv] [ret attrs] [addrspace(<num>)] <ty>|<fnty> <fnptrval>(<function args>) [fn attrs]
- [operand bundles] to label <normal label> or jump [other labels]
+ [operand bundles] to label <normal label> [other labels]
Overview:
"""""""""
@@ -7114,7 +7114,8 @@ This instruction requires several arguments:
#. '``normal label``': the label reached when the called function
executes a '``ret``' instruction.
#. '``other labels``': the labels reached when a callee transfers control
- to a location other than the normal '``normal label``'
+ to a location other than the normal '``normal label``'. The blockaddress
+ constant for these should also be in the list of '``function args``'.
#. The optional :ref:`function attributes <fnattrs>` list.
#. The optional :ref:`operand bundles <opbundles>` list.
@@ -7136,7 +7137,7 @@ Example:
.. code-block:: text
callbr void asm "", "r,x"(i32 %x, i8 *blockaddress(@foo, %fail))
- to label %normal or jump [label %fail]
+ to label %normal [label %fail]
.. _i_resume:
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 4cd8b367d53..6739ef26ed4 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2504,6 +2504,15 @@ void Verifier::visitCallBrInst(CallBrInst &CBI) {
Assert(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())
+ Assert(ArgBBs.find(BB) != ArgBBs.end(),
+ "Indirect label missing from arglist.", &CBI);
+ }
visitTerminator(CBI);
}
diff --git a/llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll b/llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll
index 579158568b6..58067946614 100644
--- a/llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll
+++ b/llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll
@@ -6,11 +6,11 @@
@l = common hidden local_unnamed_addr global i32 0, align 4
-; CHECK-LABEL: 0000000000000000 test1:
-; CHECK-LABEL: 0000000000000018 $d.1:
-; CHECK-LABEL: 0000000000000020 $x.2:
+; CHECK-LABEL: test1:
+; CHECK-LABEL: $d.1:
+; CHECK-LABEL: $x.2:
; CHECK-NEXT: b #16 <$x.4+0x4>
-; CHECK-LABEL: 000000000000002c $x.4:
+; CHECK-LABEL: $x.4:
; CHECK-NEXT: b #4 <$x.4+0x4>
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ldr x30, [sp], #16
@@ -40,11 +40,11 @@ declare dso_local i32 @g(...) local_unnamed_addr
declare dso_local i32 @i(...) local_unnamed_addr
-; CHECK-LABEL: 000000000000003c test2:
-; CHECK: bl #0 <test2+0x18>
-; CHECK-LABEL: 0000000000000064 $d.5:
-; CHECK-LABEL: 000000000000006c $x.6:
-; CHECK-NEXT: b #-24 <test2+0x18>
+; CHECK-LABEL: test2:
+; CHECK: bl #0 <test2+0x10>
+; CHECK-LABEL: $d.5:
+; CHECK-LABEL: $x.6:
+; CHECK-NEXT: b #16 <$x.8+0x4>
define hidden i32 @test2() local_unnamed_addr {
%1 = load i32, i32* @l, align 4
%2 = icmp eq i32 %1, 0
@@ -57,7 +57,7 @@ define hidden i32 @test2() local_unnamed_addr {
6: ; preds = %3
callbr void asm sideeffect "1: nop\0A\09.quad b\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,X"(i32* null, i8* blockaddress(@test2, %7))
- to label %10 [label %9]
+ to label %10 [label %7]
7: ; preds = %3
%8 = tail call i32 bitcast (i32 (...)* @i to i32 ()*)()
@@ -70,11 +70,11 @@ define hidden i32 @test2() local_unnamed_addr {
ret i32 undef
}
-; CHECK-LABEL: 0000000000000084 test3:
-; CHECK-LABEL: 00000000000000a8 $d.9:
-; CHECK-LABEL: 00000000000000b0 $x.10:
+; CHECK-LABEL: test3:
+; CHECK-LABEL: $d.9:
+; CHECK-LABEL: $x.10:
; CHECK-NEXT: b #20 <$x.12+0x8>
-; CHECK-LABEL: 00000000000000bc $x.12:
+; CHECK-LABEL: $x.12:
; CHECK-NEXT: b #4 <$x.12+0x4>
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ldr x30, [sp], #16
diff --git a/llvm/test/Verifier/callbr.ll b/llvm/test/Verifier/callbr.ll
new file mode 100644
index 00000000000..403cc573d0d
--- /dev/null
+++ b/llvm/test/Verifier/callbr.ll
@@ -0,0 +1,50 @@
+; RUN: not opt -S %s -verify 2>&1 | FileCheck %s
+
+; CHECK: Indirect label missing from arglist.
+define void @foo() {
+ ; The %4 in the indirect label list is not found in the blockaddresses in the
+ ; arg list (bad).
+ callbr void asm sideeffect "${0:l} {1:l}", "X,X"(i8* blockaddress(@foo, %3), i8* blockaddress(@foo, %2))
+ to label %1 [label %4, label %2]
+1:
+ ret void
+2:
+ ret void
+3:
+ ret void
+4:
+ ret void
+}
+
+; CHECK-NOT: Indirect label missing from arglist.
+define void @bar() {
+ ; %4 and %2 are both in the indirect label list and the arg list (good).
+ callbr void asm sideeffect "${0:l} ${1:l}", "X,X"(i8* blockaddress(@bar, %4), i8* blockaddress(@bar, %2))
+ to label %1 [label %4, label %2]
+1:
+ ret void
+2:
+ ret void
+3:
+ ret void
+4:
+ ret void
+}
+
+; CHECK-NOT: Indirect label missing from arglist.
+define void @baz() {
+ ; 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}", "X,X,X"(i8* blockaddress(@baz, %4), i8* blockaddress(@baz, %2), i8* blockaddress(@baz, %3))
+ to label %1 [label %3, label %4]
+1:
+ ret void
+2:
+ ret void
+3:
+ ret void
+4:
+ ret void
+}
OpenPOWER on IntegriCloud