xref: /llvm-project/llvm/test/ThinLTO/X86/devirt_vcall_vis_public.ll (revision 1228becf7df28c68579f2b9b390b74aa41149a0a)
1; REQUIRES: x86-registered-target
2
3; Test devirtualization through the thin link and backend, when vtables
4; have vcall_visibility metadata with public visibility.
5
6; Index based WPD
7; Generate unsplit module with summary for ThinLTO index-based WPD.
8; RUN: opt -thinlto-bc -o %t2.o %s
9; RUN: llvm-lto2 run %t2.o -save-temps -pass-remarks=. \
10; RUN:   -whole-program-visibility \
11; RUN:   -o %t3 \
12; RUN:   -r=%t2.o,test,px \
13; RUN:   -r=%t2.o,test_public,px \
14; RUN:   -r=%t2.o,_ZN1A1nEi,p \
15; RUN:   -r=%t2.o,_ZN1B1fEi,p \
16; RUN:   -r=%t2.o,_ZN1C1fEi,p \
17; RUN:   -r=%t2.o,_ZN1D1mEi,p \
18; RUN:   -r=%t2.o,_ZTV1B,px \
19; RUN:   -r=%t2.o,_ZTV1C,px \
20; RUN:   -r=%t2.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK
21; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=CHECK-TT
22; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
23
24; Hybrid WPD
25; Generate split module with summary for hybrid Thin/Regular LTO WPD.
26; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s
27; RUN: llvm-lto2 run %t.o -save-temps -pass-remarks=. \
28; RUN:   -whole-program-visibility \
29; RUN:   -o %t3 \
30; RUN:   -r=%t.o,test,px \
31; RUN:   -r=%t.o,test_public,px \
32; RUN:   -r=%t.o,_ZN1A1nEi,p \
33; RUN:   -r=%t.o,_ZN1B1fEi,p \
34; RUN:   -r=%t.o,_ZN1C1fEi,p \
35; RUN:   -r=%t.o,_ZN1D1mEi,p \
36; RUN:   -r=%t.o,_ZTV1B, \
37; RUN:   -r=%t.o,_ZTV1C, \
38; RUN:   -r=%t.o,_ZTV1D, \
39; RUN:   -r=%t.o,_ZN1A1nEi, \
40; RUN:   -r=%t.o,_ZN1B1fEi, \
41; RUN:   -r=%t.o,_ZN1C1fEi, \
42; RUN:   -r=%t.o,_ZN1D1mEi, \
43; RUN:   -r=%t.o,_ZTV1B,px \
44; RUN:   -r=%t.o,_ZTV1C,px \
45; RUN:   -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK --dump-input=fail
46; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=CHECK-TT
47; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
48
49; Regular LTO WPD
50; RUN: opt -o %t4.o %s
51; RUN: llvm-lto2 run %t4.o -save-temps -pass-remarks=. \
52; RUN:   -whole-program-visibility \
53; RUN:   -o %t5 \
54; RUN:   -r=%t4.o,test,px \
55; RUN:   -r=%t4.o,test_public,px \
56; RUN:   -r=%t4.o,_ZN1A1nEi,p \
57; RUN:   -r=%t4.o,_ZN1B1fEi,p \
58; RUN:   -r=%t4.o,_ZN1C1fEi,p \
59; RUN:   -r=%t4.o,_ZN1D1mEi,p \
60; RUN:   -r=%t4.o,_ZTV1B,px \
61; RUN:   -r=%t4.o,_ZTV1C,px \
62; RUN:   -r=%t4.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK
63; RUN: llvm-dis %t5.0.0.preopt.bc -o - | FileCheck %s --check-prefix=CHECK-TT
64; RUN: llvm-dis %t5.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
65
66; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
67; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
68; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
69; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
70
71; Try everything again but without -whole-program-visibility to confirm
72; WPD fails
73
74; Index based WPD
75; RUN: llvm-lto2 run %t2.o -save-temps -pass-remarks=. \
76; RUN:   -o %t3 \
77; RUN:   -r=%t2.o,test,px \
78; RUN:   -r=%t2.o,test_public,px \
79; RUN:   -r=%t2.o,_ZN1A1nEi,p \
80; RUN:   -r=%t2.o,_ZN1B1fEi,p \
81; RUN:   -r=%t2.o,_ZN1C1fEi,p \
82; RUN:   -r=%t2.o,_ZN1D1mEi,p \
83; RUN:   -r=%t2.o,_ZTV1B,px \
84; RUN:   -r=%t2.o,_ZTV1C,px \
85; RUN:   -r=%t2.o,_ZTV1D,px 2>&1 | FileCheck %s --implicit-check-not single-impl --allow-empty
86; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=CHECK-TT
87; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
88
89; Hybrid WPD
90; RUN: llvm-lto2 run %t.o -save-temps -pass-remarks=. \
91; RUN:   -o %t3 \
92; RUN:   -r=%t.o,test,px \
93; RUN:   -r=%t.o,test_public,px \
94; RUN:   -r=%t.o,_ZN1A1nEi,p \
95; RUN:   -r=%t.o,_ZN1B1fEi,p \
96; RUN:   -r=%t.o,_ZN1C1fEi,p \
97; RUN:   -r=%t.o,_ZN1D1mEi,p \
98; RUN:   -r=%t.o,_ZTV1B, \
99; RUN:   -r=%t.o,_ZTV1C, \
100; RUN:   -r=%t.o,_ZTV1D, \
101; RUN:   -r=%t.o,_ZN1A1nEi, \
102; RUN:   -r=%t.o,_ZN1B1fEi, \
103; RUN:   -r=%t.o,_ZN1C1fEi, \
104; RUN:   -r=%t.o,_ZN1D1mEi, \
105; RUN:   -r=%t.o,_ZTV1B,px \
106; RUN:   -r=%t.o,_ZTV1C,px \
107; RUN:   -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s --implicit-check-not single-impl --allow-empty
108; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=CHECK-TT
109; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
110
111; Regular LTO WPD
112; RUN: llvm-lto2 run %t4.o -save-temps -pass-remarks=. \
113; RUN:   -o %t5 \
114; RUN:   -r=%t4.o,test,px \
115; RUN:   -r=%t4.o,test_public,px \
116; RUN:   -r=%t4.o,_ZN1A1nEi,p \
117; RUN:   -r=%t4.o,_ZN1B1fEi,p \
118; RUN:   -r=%t4.o,_ZN1C1fEi,p \
119; RUN:   -r=%t4.o,_ZN1D1mEi,p \
120; RUN:   -r=%t4.o,_ZTV1B,px \
121; RUN:   -r=%t4.o,_ZTV1C,px \
122; RUN:   -r=%t4.o,_ZTV1D,px 2>&1 | FileCheck %s --implicit-check-not single-impl --allow-empty
123; RUN: llvm-dis %t5.0.0.preopt.bc -o - | FileCheck %s --check-prefix=CHECK-TT
124; RUN: llvm-dis %t5.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
125
126; Try index-based WPD again with both -whole-program-visibility and
127; -disable-whole-program-visibility to confirm the latter overrides
128; the former and that WPD fails.
129; RUN: llvm-lto2 run %t2.o -save-temps -pass-remarks=. \
130; RUN:   -whole-program-visibility \
131; RUN:   -disable-whole-program-visibility \
132; RUN:   -o %t3 \
133; RUN:   -r=%t2.o,test,px \
134; RUN:   -r=%t2.o,test_public,px \
135; RUN:   -r=%t2.o,_ZN1A1nEi,p \
136; RUN:   -r=%t2.o,_ZN1B1fEi,p \
137; RUN:   -r=%t2.o,_ZN1C1fEi,p \
138; RUN:   -r=%t2.o,_ZN1D1mEi,p \
139; RUN:   -r=%t2.o,_ZTV1B,px \
140; RUN:   -r=%t2.o,_ZTV1C,px \
141; RUN:   -r=%t2.o,_ZTV1D,px 2>&1 | FileCheck %s --implicit-check-not single-impl --allow-empty
142; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=CHECK-TT
143; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
144
145; CHECK-TT-NOT: call {{.*}}@llvm.public.type.test
146
147target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
148target triple = "x86_64-grtev4-linux-gnu"
149
150%struct.A = type { ptr }
151%struct.B = type { %struct.A }
152%struct.C = type { %struct.A }
153%struct.D = type { ptr }
154
155@_ZTV1B = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr undef, ptr @_ZN1B1fEi, ptr @_ZN1A1nEi] }, !type !0, !type !1, !vcall_visibility !5
156@_ZTV1C = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr undef, ptr @_ZN1C1fEi, ptr @_ZN1A1nEi] }, !type !0, !type !2, !vcall_visibility !5
157@_ZTV1D = constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr undef, ptr @_ZN1D1mEi] }, !type !3, !vcall_visibility !5
158
159
160; CHECK-IR-LABEL: define {{(noundef )?}}i32 @test
161define i32 @test(ptr %obj, ptr %obj2, i32 %a) {
162entry:
163  %vtable = load ptr, ptr %obj
164  %p = call i1 @llvm.type.test(ptr %vtable, metadata !"_ZTS1A")
165  call void @llvm.assume(i1 %p)
166  %fptrptr = getelementptr ptr, ptr %vtable, i32 1
167  %fptr1 = load ptr, ptr %fptrptr, align 8
168
169  ; Check that the call was devirtualized.
170  ; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
171  ; CHECK-NODEVIRT-IR: %call = tail call i32 %fptr1
172  %call = tail call i32 %fptr1(ptr nonnull %obj, i32 %a)
173
174  %fptr22 = load ptr, ptr %vtable, align 8
175
176  ; We still have to call it as virtual.
177  ; CHECK-IR: %call3 = tail call i32 %fptr22
178  ; CHECK-NODEVIRT-IR: %call3 = tail call i32 %fptr22
179  %call3 = tail call i32 %fptr22(ptr nonnull %obj, i32 %call)
180
181  %vtable2 = load ptr, ptr %obj2
182  %p2 = call i1 @llvm.type.test(ptr %vtable2, metadata !4)
183  call void @llvm.assume(i1 %p2)
184
185  %fptr33 = load ptr, ptr %vtable2, align 8
186
187  ; Check that the call was devirtualized.
188  ; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
189  ; CHECK-NODEVIRT-IR: %call4 = tail call i32 %fptr33
190  %call4 = tail call i32 %fptr33(ptr nonnull %obj2, i32 %call3)
191  ret i32 %call4
192}
193; CHECK-IR-LABEL: ret i32
194; CHECK-IR-LABEL: }
195
196; CHECK-IR-LABEL: define {{(noundef )?}}i32 @test_public
197define i32 @test_public(ptr %obj, ptr %obj2, i32 %a) {
198entry:
199  %vtable = load ptr, ptr %obj
200  %p = call i1 @llvm.public.type.test(ptr %vtable, metadata !"_ZTS1A")
201  call void @llvm.assume(i1 %p)
202  %fptrptr = getelementptr ptr, ptr %vtable, i32 1
203  %fptr1 = load ptr, ptr %fptrptr, align 8
204
205  ; Check that the call was devirtualized.
206  ; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
207  ; CHECK-NODEVIRT-IR: %call = tail call i32 %fptr1
208  %call = tail call i32 %fptr1(ptr nonnull %obj, i32 %a)
209
210  %fptr22 = load ptr, ptr %vtable, align 8
211
212  ; We still have to call it as virtual.
213  ; CHECK-IR: %call3 = tail call i32 %fptr22
214  ; CHECK-NODEVIRT-IR: %call3 = tail call i32 %fptr22
215  %call3 = tail call i32 %fptr22(ptr nonnull %obj, i32 %call)
216
217  %vtable2 = load ptr, ptr %obj2
218  %p2 = call i1 @llvm.public.type.test(ptr %vtable2, metadata !4)
219  call void @llvm.assume(i1 %p2)
220
221  %fptr33 = load ptr, ptr %vtable2, align 8
222
223  ; Check that the call was devirtualized.
224  ; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
225  ; CHECK-NODEVIRT-IR: %call4 = tail call i32 %fptr33
226  %call4 = tail call i32 %fptr33(ptr nonnull %obj2, i32 %call3)
227  ret i32 %call4
228}
229; CHECK-IR-LABEL: ret i32
230; CHECK-IR-LABEL: }
231
232declare i1 @llvm.type.test(ptr, metadata)
233declare i1 @llvm.public.type.test(ptr, metadata)
234declare void @llvm.assume(i1)
235
236define i32 @_ZN1B1fEi(ptr %this, i32 %a) #0 {
237   ret i32 0;
238}
239
240define i32 @_ZN1A1nEi(ptr %this, i32 %a) #0 {
241   ret i32 0;
242}
243
244define i32 @_ZN1C1fEi(ptr %this, i32 %a) #0 {
245   ret i32 0;
246}
247
248define i32 @_ZN1D1mEi(ptr %this, i32 %a) #0 {
249   ret i32 0;
250}
251
252; Make sure we don't inline or otherwise optimize out the direct calls.
253attributes #0 = { noinline optnone }
254
255!0 = !{i64 16, !"_ZTS1A"}
256!1 = !{i64 16, !"_ZTS1B"}
257!2 = !{i64 16, !"_ZTS1C"}
258!3 = !{i64 16, !4}
259!4 = distinct !{}
260!5 = !{i64 0}
261