]> granicus.if.org Git - llvm/commitdiff
[Verifier] add invariant check for callbr
authorNick Desaulniers <ndesaulniers@google.com>
Wed, 25 Sep 2019 22:28:27 +0000 (22:28 +0000)
committerNick Desaulniers <ndesaulniers@google.com>
Wed, 25 Sep 2019 22:28:27 +0000 (22:28 +0000)
Summary:
The list of indirect labels should ALWAYS have their blockaddresses as
argument operands to the callbr (but not necessarily the other way
around).  Add an invariant that checks this.

The verifier catches a bad test case that was added recently in r368478.
I think that was a simple mistake, and the test was made less strict in
regards to the precise addresses (as those weren't specifically the
point of the test).

This invariant will be used to find a reported bug.

Link: https://www.spinics.net/lists/arm-kernel/msg753473.html
Link: https://github.com/ClangBuiltLinux/linux/issues/649
Reviewers: craig.topper, void, chandlerc

Reviewed By: void

Subscribers: ychen, lebedev.ri, javed.absar, kristof.beyls, hiraditya, llvm-commits, srhines

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D67196

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@372923 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LangRef.rst
lib/IR/Verifier.cpp
test/CodeGen/AArch64/callbr-asm-obj-file.ll
test/Verifier/callbr.ll [new file with mode: 0644]

index ac1db593ac8ffb1680fdb37c6c49a4abeb509b6f..59c4469fb9fd4baa09575c7b3f1d8e3dbf374d78 100644 (file)
@@ -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:
 
index 4cd8b367d53ec7a6e6206f9ae1dd3ffc15dc20ae..6739ef26ed4139f41265953e80ec09e80c5e5f28 100644 (file)
@@ -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);
 }
index 579158568b6fd5f93c4650b9e9f2817e618fd509..5806794661403939135e104ae05b3f76d0ade417 100644 (file)
@@ -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/test/Verifier/callbr.ll b/test/Verifier/callbr.ll
new file mode 100644 (file)
index 0000000..403cc57
--- /dev/null
@@ -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
+}