1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
; RUN: opt -inline -S < %s | FileCheck %s
; RUN: opt -passes='cgscc(inline)' -S < %s | FileCheck %s
; PR10162
; Make sure doit is not inlined since the blockaddress is taken
; which could be unsafe
; CHECK: store i8* blockaddress(@doit, %here), i8** %pptr, align 8
@i = global i32 1, align 4
@ptr1 = common global i8* null, align 8
define void @doit(i8** nocapture %pptr, i32 %cond) nounwind uwtable {
entry:
%tobool = icmp eq i32 %cond, 0
br i1 %tobool, label %if.end, label %here
here:
store i8* blockaddress(@doit, %here), i8** %pptr, align 8
br label %if.end
if.end:
ret void
}
define void @f(i32 %cond) nounwind uwtable {
entry:
call void @doit(i8** @ptr1, i32 %cond)
ret void
}
; PR27233: We can inline @run into @init. Don't crash on it.
;
; CHECK-LABEL: define void @init
; CHECK: store i8* blockaddress(@run, %bb)
; CHECK-SAME: @run.bb
define void @init() {
entry:
call void @run()
ret void
}
define void @run() {
entry:
store i8* blockaddress(@run, %bb), i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @run.bb, i64 0, i64 0), align 8
ret void
bb:
unreachable
}
@run.bb = global [1 x i8*] zeroinitializer
; Check that a function referenced by a global blockaddress wont be inlined,
; even if it contains a callbr. We might be able to relax this in the future
; as long as the global blockaddress is updated correctly.
@ba = internal global i8* blockaddress(@foo, %7), align 8
define internal i32 @foo(i32) {
%2 = alloca i32, align 4
%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
to label %5 [label %7, label %6]
; <label>:5: ; preds = %1
store i32 0, i32* %2, align 4
br label %8
; <label>:6: ; preds = %1
store i32 1, i32* %2, align 4
br label %8
; <label>:7: ; preds = %1
store i32 2, i32* %2, align 4
br label %8
; <label>:8: ; preds = %7, %6, %5
%9 = load i32, i32* %2, align 4
ret i32 %9
}
define dso_local i32 @bar() {
%1 = call i32 @foo(i32 0)
ret i32 %1
}
; CHECK: define dso_local i32 @bar() {
; CHECK: %1 = call i32 @foo(i32 0)
; CHECK: ret i32 %1
; CHECK: }
; Triple check that even with a global aggregate whose member is a blockaddress,
; we still don't inline referred to functions.
%struct.foo = type { i8* }
@my_foo = dso_local global %struct.foo { i8* blockaddress(@baz, %7) }
define internal i32 @baz(i32) {
%2 = alloca i32, align 4
%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
to label %5 [label %7, label %6]
; <label>:5: ; preds = %1
store i32 0, i32* %2, align 4
br label %8
; <label>:6: ; preds = %1
store i32 1, i32* %2, align 4
br label %8
; <label>:7: ; preds = %1
store i32 2, i32* %2, align 4
br label %8
; <label>:8: ; preds = %7, %6, %5
%9 = load i32, i32* %2, align 4
ret i32 %9
}
define dso_local i32 @quux() {
%1 = call i32 @baz(i32 0)
ret i32 %1
}
; CHECK: define dso_local i32 @quux() {
; CHECK: %1 = call i32 @baz(i32 0)
; CHECK: ret i32 %1
; CHECK: }
|