mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-14 07:09:08 +00:00
[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
This commit is contained in:
parent
a773cb1281
commit
4e5aa08380
@ -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:
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
50
test/Verifier/callbr.ll
Normal file
50
test/Verifier/callbr.ll
Normal file
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user