xref: /llvm-project/llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll (revision 58c5f50f4c73945fdc5440dee2fba03267a460d4)
1; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility %s | FileCheck --check-prefixes=CHECK,RETP %s
2; RUN: sed -e 's,+retpoline,-retpoline,g' %s | opt -S -passes=wholeprogramdevirt -whole-program-visibility | FileCheck --check-prefixes=CHECK,NORETP %s
3
4; RUN: opt -passes=wholeprogramdevirt -whole-program-visibility -wholeprogramdevirt-summary-action=export -wholeprogramdevirt-read-summary=%S/Inputs/export.yaml -wholeprogramdevirt-write-summary=%t -S -o - %s | FileCheck --check-prefixes=CHECK,RETP %s
5
6; RUN: opt -passes='wholeprogramdevirt,default<O3>' -whole-program-visibility -wholeprogramdevirt-summary-action=export -wholeprogramdevirt-read-summary=%S/Inputs/export.yaml -wholeprogramdevirt-write-summary=%t  -S -o - %s | FileCheck --check-prefixes=CHECK %s
7
8; RUN: FileCheck --check-prefix=SUMMARY %s < %t
9
10; SUMMARY:      TypeIdMap:
11; SUMMARY-NEXT:  typeid1_rv:
12; SUMMARY-NEXT:    TTRes:
13; SUMMARY-NEXT:      Kind:            Unknown
14; SUMMARY-NEXT:      SizeM1BitWidth:  0
15; SUMMARY-NEXT:      AlignLog2:       0
16; SUMMARY-NEXT:      SizeM1:          0
17; SUMMARY-NEXT:      BitMask:         0
18; SUMMARY-NEXT:      InlineBits:      0
19; SUMMARY-NEXT:    WPDRes:
20; SUMMARY-NEXT:      0:
21; SUMMARY-NEXT:        Kind:            BranchFunnel
22; SUMMARY-NEXT:        SingleImplName:  ''
23; SUMMARY-NEXT:        ResByArg:
24; SUMMARY-NEXT:  typeid2_rv:
25; SUMMARY-NEXT:    TTRes:
26; SUMMARY-NEXT:      Kind:            Unknown
27; SUMMARY-NEXT:      SizeM1BitWidth:  0
28; SUMMARY-NEXT:      AlignLog2:       0
29; SUMMARY-NEXT:      SizeM1:          0
30; SUMMARY-NEXT:      BitMask:         0
31; SUMMARY-NEXT:      InlineBits:      0
32; SUMMARY-NEXT:    WPDRes:
33; SUMMARY-NEXT:      0:
34; SUMMARY-NEXT:        Kind:            Indir
35; SUMMARY-NEXT:        SingleImplName:  ''
36; SUMMARY-NEXT:        ResByArg:
37; SUMMARY-NEXT:   typeid3_rv:
38; SUMMARY-NEXT:     TTRes:
39; SUMMARY-NEXT:       Kind:            Unknown
40; SUMMARY-NEXT:       SizeM1BitWidth:  0
41; SUMMARY-NEXT:       AlignLog2:       0
42; SUMMARY-NEXT:       SizeM1:          0
43; SUMMARY-NEXT:       BitMask:         0
44; SUMMARY-NEXT:       InlineBits:      0
45; SUMMARY-NEXT:     WPDRes:
46; SUMMARY-NEXT:       0:
47; SUMMARY-NEXT:         Kind:            BranchFunnel
48; SUMMARY-NEXT:         SingleImplName:  ''
49; SUMMARY-NEXT:         ResByArg:
50; SUMMARY-NEXT:   typeid3:
51; SUMMARY-NEXT:     TTRes:
52; SUMMARY-NEXT:       Kind:            Unknown
53; SUMMARY-NEXT:       SizeM1BitWidth:  0
54; SUMMARY-NEXT:       AlignLog2:       0
55; SUMMARY-NEXT:       SizeM1:          0
56; SUMMARY-NEXT:       BitMask:         0
57; SUMMARY-NEXT:       InlineBits:      0
58; SUMMARY-NEXT:     WPDRes:
59; SUMMARY-NEXT:       0:
60; SUMMARY-NEXT:         Kind:            BranchFunnel
61; SUMMARY-NEXT:         SingleImplName:  ''
62; SUMMARY-NEXT:         ResByArg:
63; SUMMARY-NEXT:   typeid1:
64; SUMMARY-NEXT:     TTRes:
65; SUMMARY-NEXT:       Kind:            Unknown
66; SUMMARY-NEXT:       SizeM1BitWidth:  0
67; SUMMARY-NEXT:       AlignLog2:       0
68; SUMMARY-NEXT:       SizeM1:          0
69; SUMMARY-NEXT:       BitMask:         0
70; SUMMARY-NEXT:       InlineBits:      0
71; SUMMARY-NEXT:     WPDRes:
72; SUMMARY-NEXT:       0:
73; SUMMARY-NEXT:         Kind:            BranchFunnel
74; SUMMARY-NEXT:         SingleImplName:  ''
75; SUMMARY-NEXT:         ResByArg:
76; SUMMARY-NEXT:   typeid2:
77; SUMMARY-NEXT:     TTRes:
78; SUMMARY-NEXT:       Kind:            Unknown
79; SUMMARY-NEXT:       SizeM1BitWidth:  0
80; SUMMARY-NEXT:       AlignLog2:       0
81; SUMMARY-NEXT:       SizeM1:          0
82; SUMMARY-NEXT:       BitMask:         0
83; SUMMARY-NEXT:       InlineBits:      0
84; SUMMARY-NEXT:     WPDRes:
85; SUMMARY-NEXT:       0:
86; SUMMARY-NEXT:         Kind:            Indir
87; SUMMARY-NEXT:         SingleImplName:  ''
88; SUMMARY-NEXT:         ResByArg:
89
90target datalayout = "e-p:64:64"
91target triple = "x86_64-unknown-linux-gnu"
92
93@vt1_1 = constant [1 x ptr] [ptr @vf1_1], !type !0
94@vt1_2 = constant [1 x ptr] [ptr @vf1_2], !type !0
95
96declare i32 @vf1_1(ptr %this, i32 %arg)
97declare i32 @vf1_2(ptr %this, i32 %arg)
98
99@vt2_1 = constant [1 x ptr] [ptr @vf2_1], !type !1
100@vt2_2 = constant [1 x ptr] [ptr @vf2_2], !type !1
101@vt2_3 = constant [1 x ptr] [ptr @vf2_3], !type !1
102@vt2_4 = constant [1 x ptr] [ptr @vf2_4], !type !1
103@vt2_5 = constant [1 x ptr] [ptr @vf2_5], !type !1
104@vt2_6 = constant [1 x ptr] [ptr @vf2_6], !type !1
105@vt2_7 = constant [1 x ptr] [ptr @vf2_7], !type !1
106@vt2_8 = constant [1 x ptr] [ptr @vf2_8], !type !1
107@vt2_9 = constant [1 x ptr] [ptr @vf2_9], !type !1
108@vt2_10 = constant [1 x ptr] [ptr @vf2_10], !type !1
109@vt2_11 = constant [1 x ptr] [ptr @vf2_11], !type !1
110
111declare i32 @vf2_1(ptr %this, i32 %arg)
112declare i32 @vf2_2(ptr %this, i32 %arg)
113declare i32 @vf2_3(ptr %this, i32 %arg)
114declare i32 @vf2_4(ptr %this, i32 %arg)
115declare i32 @vf2_5(ptr %this, i32 %arg)
116declare i32 @vf2_6(ptr %this, i32 %arg)
117declare i32 @vf2_7(ptr %this, i32 %arg)
118declare i32 @vf2_8(ptr %this, i32 %arg)
119declare i32 @vf2_9(ptr %this, i32 %arg)
120declare i32 @vf2_10(ptr %this, i32 %arg)
121declare i32 @vf2_11(ptr %this, i32 %arg)
122
123@vt3_1 = constant [1 x ptr] [ptr @vf3_1], !type !2
124@vt3_2 = constant [1 x ptr] [ptr @vf3_2], !type !2
125
126declare i32 @vf3_1(ptr %this, i32 %arg)
127declare i32 @vf3_2(ptr %this, i32 %arg)
128
129@vt4_1 = constant [1 x ptr] [ptr @vf4_1], !type !3
130@vt4_2 = constant [1 x ptr] [ptr @vf4_2], !type !3
131
132declare i32 @vf4_1(ptr %this, i32 %arg)
133declare i32 @vf4_2(ptr %this, i32 %arg)
134
135declare ptr @llvm.load.relative.i32(ptr, i32)
136
137;; These are relative vtables equivalent to the ones above.
138@vt1_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1_1 to i64), i64 ptrtoint (ptr @vt1_1_rv to i64)) to i32)], !type !5
139@vt1_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1_2 to i64), i64 ptrtoint (ptr @vt1_2_rv to i64)) to i32)], !type !5
140
141@vt2_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_1 to i64), i64 ptrtoint (ptr @vt2_1_rv to i64)) to i32)], !type !6
142@vt2_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_2 to i64), i64 ptrtoint (ptr @vt2_2_rv to i64)) to i32)], !type !6
143@vt2_3_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_3 to i64), i64 ptrtoint (ptr @vt2_3_rv to i64)) to i32)], !type !6
144@vt2_4_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_4 to i64), i64 ptrtoint (ptr @vt2_4_rv to i64)) to i32)], !type !6
145@vt2_5_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_5 to i64), i64 ptrtoint (ptr @vt2_5_rv to i64)) to i32)], !type !6
146@vt2_6_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_6 to i64), i64 ptrtoint (ptr @vt2_6_rv to i64)) to i32)], !type !6
147@vt2_7_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_7 to i64), i64 ptrtoint (ptr @vt2_7_rv to i64)) to i32)], !type !6
148@vt2_8_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_8 to i64), i64 ptrtoint (ptr @vt2_8_rv to i64)) to i32)], !type !6
149@vt2_9_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_9 to i64), i64 ptrtoint (ptr @vt2_9_rv to i64)) to i32)], !type !6
150@vt2_10_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_10 to i64), i64 ptrtoint (ptr @vt2_10_rv to i64)) to i32)], !type !6
151@vt2_11_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_11 to i64), i64 ptrtoint (ptr @vt2_11_rv to i64)) to i32)], !type !6
152
153@vt3_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf3_1 to i64), i64 ptrtoint (ptr @vt3_1_rv to i64)) to i32)], !type !7
154@vt3_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf3_2 to i64), i64 ptrtoint (ptr @vt3_2_rv to i64)) to i32)], !type !7
155
156@vt4_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4_1 to i64), i64 ptrtoint (ptr @vt4_1_rv to i64)) to i32)], !type !8
157@vt4_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4_2 to i64), i64 ptrtoint (ptr @vt4_2_rv to i64)) to i32)], !type !8
158
159
160; CHECK-LABEL: define i32 @fn1
161; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
162define i32 @fn1(ptr %obj) #0 {
163  %vtable = load ptr, ptr %obj
164  %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid1")
165  call void @llvm.assume(i1 %p)
166  %fptr = load ptr, ptr %vtable
167  ; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest %vtable, ptr %obj, i32 1)
168  %result = call i32 %fptr(ptr %obj, i32 1)
169  ; NORETP: call i32 %
170  ret i32 %result
171}
172
173; CHECK-LABEL: define i32 @fn1_rv
174; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
175define i32 @fn1_rv(ptr %obj) #0 {
176  %vtable = load ptr, ptr %obj
177  %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid1_rv")
178  call void @llvm.assume(i1 %p)
179  %fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
180  ; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest %vtable, ptr %obj, i32 1)
181  %result = call i32 %fptr(ptr %obj, i32 1)
182  ; NORETP: call i32 %
183  ret i32 %result
184}
185
186; CHECK-LABEL: define i32 @fn2
187; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
188define i32 @fn2(ptr %obj) #0 {
189  %vtable = load ptr, ptr %obj
190  %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
191  call void @llvm.assume(i1 %p)
192  %fptr = load ptr, ptr %vtable
193  ; CHECK: call i32 %
194  %result = call i32 %fptr(ptr %obj, i32 1)
195  ret i32 %result
196}
197
198; CHECK-LABEL: define i32 @fn2_rv
199; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
200define i32 @fn2_rv(ptr %obj) #0 {
201  %vtable = load ptr, ptr %obj
202  %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2_rv")
203  call void @llvm.assume(i1 %p)
204  %fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
205  ; CHECK: call i32 %
206  %result = call i32 %fptr(ptr %obj, i32 1)
207  ret i32 %result
208}
209
210; CHECK-LABEL: define i32 @fn3
211; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
212define i32 @fn3(ptr %obj) #0 {
213  %vtable = load ptr, ptr %obj
214  %p = call i1 @llvm.type.test(ptr %vtable, metadata !4)
215  call void @llvm.assume(i1 %p)
216  %fptr = load ptr, ptr %vtable
217  ; RETP: call i32 @branch_funnel(ptr
218  ; NORETP: call i32 %
219  %result = call i32 %fptr(ptr %obj, i32 1)
220  ret i32 %result
221}
222
223; CHECK-LABEL: define i32 @fn3_rv
224; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
225define i32 @fn3_rv(ptr %obj) #0 {
226  %vtable = load ptr, ptr %obj
227  %p = call i1 @llvm.type.test(ptr %vtable, metadata !9)
228  call void @llvm.assume(i1 %p)
229  %fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
230  ; RETP: call i32 @branch_funnel.1(ptr
231  ; NORETP: call i32 %
232  %result = call i32 %fptr(ptr %obj, i32 1)
233  ret i32 %result
234}
235
236; CHECK-LABEL: define i32 @fn4
237; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
238define i32 @fn4(ptr %obj) #0 {
239  %p = call i1 @llvm.type.test(ptr @vt1_1, metadata !"typeid1")
240  call void @llvm.assume(i1 %p)
241  %fptr = load ptr, ptr @vt1_1
242  ; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest @vt1_1, ptr %obj, i32 1)
243  %result = call i32 %fptr(ptr %obj, i32 1)
244  ; NORETP: call i32 %
245  ret i32 %result
246}
247
248; CHECK-LABEL: define i32 @fn4_cpy
249; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
250define i32 @fn4_cpy(ptr %obj) #0 {
251  %p = call i1 @llvm.type.test(ptr @vt1_1, metadata !"typeid1")
252  call void @llvm.assume(i1 %p)
253  %fptr = load ptr, ptr @vt1_1
254  ; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest @vt1_1, ptr %obj, i32 1)
255  %result = call i32 %fptr(ptr %obj, i32 1)
256  ; NORETP: call i32 %
257  ret i32 %result
258}
259
260; CHECK-LABEL: define i32 @fn4_rv
261; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
262define i32 @fn4_rv(ptr %obj) #0 {
263  %p = call i1 @llvm.type.test(ptr @vt1_1_rv, metadata !"typeid1_rv")
264  call void @llvm.assume(i1 %p)
265  %fptr = call ptr @llvm.load.relative.i32(ptr @vt1_1_rv, i32 0)
266  ; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest @vt1_1_rv, ptr %obj, i32 1)
267  %result = call i32 %fptr(ptr %obj, i32 1)
268  ; NORETP: call i32 %
269  ret i32 %result
270}
271
272; CHECK-LABEL: define i32 @fn4_rv_cpy
273; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
274define i32 @fn4_rv_cpy(ptr %obj) #0 {
275  %p = call i1 @llvm.type.test(ptr @vt1_1_rv, metadata !"typeid1_rv")
276  call void @llvm.assume(i1 %p)
277  %fptr = call ptr @llvm.load.relative.i32(ptr @vt1_1_rv, i32 0)
278  ; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest @vt1_1_rv, ptr %obj, i32 1)
279  %result = call i32 %fptr(ptr %obj, i32 1)
280  ; NORETP: call i32 %
281  ret i32 %result
282}
283
284; CHECK-LABEL: define hidden void @__typeid_typeid1_0_branch_funnel(ptr nest %0, ...)
285; CHECK-NEXT: musttail call void (...) @llvm.icall.branch.funnel(ptr %0, ptr {{(nonnull )?}}@vt1_1, ptr {{(nonnull )?}}@vf1_1, ptr {{(nonnull )?}}@vt1_2, ptr {{(nonnull )?}}@vf1_2, ...)
286
287; CHECK-LABEL: define hidden void @__typeid_typeid1_rv_0_branch_funnel(ptr nest %0, ...)
288; CHECK-NEXT: musttail call void (...) @llvm.icall.branch.funnel(ptr %0, ptr {{(nonnull )?}}@vt1_1_rv, ptr {{(nonnull )?}}@vf1_1, ptr {{(nonnull )?}}@vt1_2_rv, ptr {{(nonnull )?}}@vf1_2, ...)
289
290; CHECK: define internal void @branch_funnel(ptr
291; CHECK: define internal void @branch_funnel.1(ptr
292
293declare i1 @llvm.type.test(ptr, metadata)
294declare void @llvm.assume(i1)
295
296!0 = !{i32 0, !"typeid1"}
297!1 = !{i32 0, !"typeid2"}
298!2 = !{i32 0, !"typeid3"}
299!3 = !{i32 0, !4}
300!4 = distinct !{}
301!5 = !{i32 0, !"typeid1_rv"}
302!6 = !{i32 0, !"typeid2_rv"}
303!7 = !{i32 0, !"typeid3_rv"}
304!8 = !{i32 0, !9}
305!9 = distinct !{}
306
307attributes #0 = { "target-features"="+retpoline" }
308