From 93d87260f1f7b5ec6775fe88891e47a57e6392d6 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Wed, 25 Sep 2019 22:28:27 +0000 Subject: [PATCH] [Verifier] add invariant check for callbr 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 llvm-svn: 372923 --- llvm/docs/LangRef.rst | 7 ++-- llvm/lib/IR/Verifier.cpp | 9 +++++ llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll | 28 ++++++------- llvm/test/Verifier/callbr.ll | 50 ++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 llvm/test/Verifier/callbr.ll diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index ac1db59..59c4469 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7070,7 +7070,7 @@ Syntax: :: = callbr [cconv] [ret attrs] [addrspace()] | () [fn attrs] - [operand bundles] to label or jump [other labels] + [operand bundles] to 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 ` list. #. The optional :ref:`operand bundles ` 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 4cd8b36..6739ef2 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 ArgBBs; + for (Value *V : CBI.args()) + if (auto *BA = dyn_cast(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 5791585..5806794 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 -; CHECK-LABEL: 0000000000000064 $d.5: -; CHECK-LABEL: 000000000000006c $x.6: -; CHECK-NEXT: b #-24 +; CHECK-LABEL: test2: +; CHECK: bl #0 +; 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 0000000..403cc57 --- /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 +} -- 2.7.4