xref: /aosp_15_r20/external/clang/test/CodeGenCXX/vtable-assume-load.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li // RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o %t.ll -O1 -disable-llvm-optzns -fms-extensions -fstrict-vtable-pointers
2*67e74705SXin Li // RUN: %clang_cc1 %s -triple i686-pc-win32 -emit-llvm -o %t.ms.ll -O1 -disable-llvm-optzns -fms-extensions -fstrict-vtable-pointers
3*67e74705SXin Li // FIXME: Assume load should not require -fstrict-vtable-pointers
4*67e74705SXin Li 
5*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK1 --input-file=%t.ll %s
6*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK2 --input-file=%t.ll %s
7*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK3 --input-file=%t.ll %s
8*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK4 --input-file=%t.ll %s
9*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK-MS --input-file=%t.ms.ll %s
10*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK6 --input-file=%t.ll %s
11*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK7 --input-file=%t.ll %s
12*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK8 --input-file=%t.ll %s
13*67e74705SXin Li // RUN: FileCheck --check-prefix=CHECK9 --input-file=%t.ll %s
14*67e74705SXin Li namespace test1 {
15*67e74705SXin Li 
16*67e74705SXin Li struct A {
17*67e74705SXin Li   A();
18*67e74705SXin Li   virtual void foo();
19*67e74705SXin Li };
20*67e74705SXin Li 
21*67e74705SXin Li struct B : A {
22*67e74705SXin Li   virtual void foo();
23*67e74705SXin Li };
24*67e74705SXin Li 
g(A * a)25*67e74705SXin Li void g(A *a) { a->foo(); }
26*67e74705SXin Li 
27*67e74705SXin Li // CHECK1-LABEL: define void @_ZN5test14fooAEv()
28*67e74705SXin Li // CHECK1: call void @_ZN5test11AC1Ev(%"struct.test1::A"*
29*67e74705SXin Li // CHECK1: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
30*67e74705SXin Li // CHECK1: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([3 x i8*], [3 x i8*]* @_ZTVN5test11AE, i32 0, i32 2)
31*67e74705SXin Li // CHECK1: call void @llvm.assume(i1 %[[CMP]])
32*67e74705SXin Li // CHECK1-LABEL: }
33*67e74705SXin Li 
fooA()34*67e74705SXin Li void fooA() {
35*67e74705SXin Li   A a;
36*67e74705SXin Li   g(&a);
37*67e74705SXin Li }
38*67e74705SXin Li 
39*67e74705SXin Li // CHECK1-LABEL: define void @_ZN5test14fooBEv()
40*67e74705SXin Li // CHECK1: call void @_ZN5test11BC1Ev(%"struct.test1::B"* %{{.*}})
41*67e74705SXin Li // CHECK1: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
42*67e74705SXin Li // CHECK1: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([3 x i8*], [3 x i8*]* @_ZTVN5test11BE, i32 0, i32 2)
43*67e74705SXin Li // CHECK1: call void @llvm.assume(i1 %[[CMP]])
44*67e74705SXin Li // CHECK1-LABEL: }
45*67e74705SXin Li 
fooB()46*67e74705SXin Li void fooB() {
47*67e74705SXin Li   B b;
48*67e74705SXin Li   g(&b);
49*67e74705SXin Li }
50*67e74705SXin Li // there should not be any assumes in the ctor that calls base ctor
51*67e74705SXin Li // CHECK1-LABEL: define linkonce_odr void @_ZN5test11BC2Ev(%"struct.test1::B"*
52*67e74705SXin Li // CHECK1-NOT: @llvm.assume(
53*67e74705SXin Li // CHECK1-LABEL: }
54*67e74705SXin Li }
55*67e74705SXin Li namespace test2 {
56*67e74705SXin Li struct A {
57*67e74705SXin Li   A();
58*67e74705SXin Li   virtual void foo();
59*67e74705SXin Li };
60*67e74705SXin Li 
61*67e74705SXin Li struct B {
62*67e74705SXin Li   B();
63*67e74705SXin Li   virtual void bar();
64*67e74705SXin Li };
65*67e74705SXin Li 
66*67e74705SXin Li struct C : A, B {
67*67e74705SXin Li   C();
68*67e74705SXin Li   virtual void foo();
69*67e74705SXin Li };
g(A * a)70*67e74705SXin Li void g(A *a) { a->foo(); }
h(B * b)71*67e74705SXin Li void h(B *b) { b->bar(); }
72*67e74705SXin Li 
73*67e74705SXin Li // CHECK2-LABEL: define void @_ZN5test24testEv()
74*67e74705SXin Li // CHECK2: call void @_ZN5test21CC1Ev(%"struct.test2::C"*
75*67e74705SXin Li // CHECK2: %[[VTABLE:.*]] = load i8**, i8*** {{.*}}
76*67e74705SXin Li // CHECK2: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([6 x i8*], [6 x i8*]* @_ZTVN5test21CE, i32 0, i32 2)
77*67e74705SXin Li // CHECK2: call void @llvm.assume(i1 %[[CMP]])
78*67e74705SXin Li 
79*67e74705SXin Li // CHECK2: %[[V2:.*]] = bitcast %"struct.test2::C"* %{{.*}} to i8*
80*67e74705SXin Li // CHECK2: %[[ADD_PTR:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 8
81*67e74705SXin Li // CHECK2: %[[V3:.*]] = bitcast i8* %[[ADD_PTR]] to i8***
82*67e74705SXin Li // CHECK2: %[[VTABLE2:.*]] = load i8**, i8*** %[[V3]]
83*67e74705SXin Li // CHECK2: %[[CMP2:.*]] = icmp eq i8** %[[VTABLE2]], getelementptr inbounds ([6 x i8*], [6 x i8*]* @_ZTVN5test21CE, i32 0, i32 5)
84*67e74705SXin Li // CHECK2: call void @llvm.assume(i1 %[[CMP2]])
85*67e74705SXin Li 
86*67e74705SXin Li // CHECK2: call void @_ZN5test21gEPNS_1AE(
87*67e74705SXin Li // CHECK2-LABEL: }
88*67e74705SXin Li 
test()89*67e74705SXin Li void test() {
90*67e74705SXin Li   C c;
91*67e74705SXin Li   g(&c);
92*67e74705SXin Li   h(&c);
93*67e74705SXin Li }
94*67e74705SXin Li }
95*67e74705SXin Li 
96*67e74705SXin Li namespace test3 {
97*67e74705SXin Li struct A {
98*67e74705SXin Li   A();
99*67e74705SXin Li };
100*67e74705SXin Li 
101*67e74705SXin Li struct B : A {
102*67e74705SXin Li   B();
103*67e74705SXin Li   virtual void foo();
104*67e74705SXin Li };
105*67e74705SXin Li 
106*67e74705SXin Li struct C : virtual A, B {
107*67e74705SXin Li   C();
108*67e74705SXin Li   virtual void foo();
109*67e74705SXin Li };
g(B * a)110*67e74705SXin Li void g(B *a) { a->foo(); }
111*67e74705SXin Li 
112*67e74705SXin Li // CHECK3-LABEL: define void @_ZN5test34testEv()
113*67e74705SXin Li // CHECK3: call void @_ZN5test31CC1Ev(%"struct.test3::C"*
114*67e74705SXin Li // CHECK3: %[[CMP:.*]] = icmp eq i8** %{{.*}}, getelementptr inbounds ([4 x i8*], [4 x i8*]* @_ZTVN5test31CE, i32 0, i32 3)
115*67e74705SXin Li // CHECK3: call void @llvm.assume(i1 %[[CMP]])
116*67e74705SXin Li // CHECK3-LABLEL: }
test()117*67e74705SXin Li void test() {
118*67e74705SXin Li   C c;
119*67e74705SXin Li   g(&c);
120*67e74705SXin Li }
121*67e74705SXin Li } // test3
122*67e74705SXin Li 
123*67e74705SXin Li namespace test4 {
124*67e74705SXin Li struct A {
125*67e74705SXin Li   A();
126*67e74705SXin Li   virtual void foo();
127*67e74705SXin Li };
128*67e74705SXin Li 
129*67e74705SXin Li struct B : virtual A {
130*67e74705SXin Li   B();
131*67e74705SXin Li   virtual void foo();
132*67e74705SXin Li };
133*67e74705SXin Li struct C : B {
134*67e74705SXin Li   C();
135*67e74705SXin Li   virtual void foo();
136*67e74705SXin Li };
137*67e74705SXin Li 
g(C * c)138*67e74705SXin Li void g(C *c) { c->foo(); }
139*67e74705SXin Li 
140*67e74705SXin Li // CHECK4-LABEL: define void @_ZN5test44testEv()
141*67e74705SXin Li // CHECK4: call void @_ZN5test41CC1Ev(%"struct.test4::C"*
142*67e74705SXin Li // CHECK4: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
143*67e74705SXin Li // CHECK4: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([5 x i8*], [5 x i8*]* @_ZTVN5test41CE, i32 0, i32 4)
144*67e74705SXin Li // CHECK4: call void @llvm.assume(i1 %[[CMP]]
145*67e74705SXin Li 
146*67e74705SXin Li // CHECK4: %[[VTABLE2:.*]] = load i8**, i8*** %{{.*}}
147*67e74705SXin Li // CHECK4: %[[CMP2:.*]] = icmp eq i8** %[[VTABLE2]], getelementptr inbounds ([5 x i8*], [5 x i8*]* @_ZTVN5test41CE, i32 0, i32 4)
148*67e74705SXin Li // CHECK4: call void @llvm.assume(i1 %[[CMP2]])
149*67e74705SXin Li // CHECK4-LABEL: }
150*67e74705SXin Li 
test()151*67e74705SXin Li void test() {
152*67e74705SXin Li   C c;
153*67e74705SXin Li   g(&c);
154*67e74705SXin Li }
155*67e74705SXin Li } // test4
156*67e74705SXin Li 
157*67e74705SXin Li namespace testMS {
158*67e74705SXin Li 
159*67e74705SXin Li struct __declspec(novtable) S {
160*67e74705SXin Li   virtual void foo();
161*67e74705SXin Li };
162*67e74705SXin Li 
g(S & s)163*67e74705SXin Li void g(S &s) { s.foo(); }
164*67e74705SXin Li 
165*67e74705SXin Li // if struct has novtable specifier, then we can't generate assumes
166*67e74705SXin Li // CHECK-MS-LABEL: define void @"\01?test@testMS@@YAXXZ"()
167*67e74705SXin Li // CHECK-MS: call x86_thiscallcc %"struct.testMS::S"* @"\01??0S@testMS@@QAE@XZ"(
168*67e74705SXin Li // CHECK-MS-NOT: @llvm.assume
169*67e74705SXin Li // CHECK-MS-LABEL: }
170*67e74705SXin Li 
test()171*67e74705SXin Li void test() {
172*67e74705SXin Li   S s;
173*67e74705SXin Li   g(s);
174*67e74705SXin Li }
175*67e74705SXin Li 
176*67e74705SXin Li } // testMS
177*67e74705SXin Li 
178*67e74705SXin Li namespace test6 {
179*67e74705SXin Li struct A {
180*67e74705SXin Li   A();
181*67e74705SXin Li   virtual void foo();
~Atest6::A182*67e74705SXin Li   virtual ~A() {}
183*67e74705SXin Li };
184*67e74705SXin Li struct B : A {
185*67e74705SXin Li   B();
186*67e74705SXin Li };
187*67e74705SXin Li // FIXME: Because A's vtable is external, and no virtual functions are hidden,
188*67e74705SXin Li // it's safe to generate assumption loads.
189*67e74705SXin Li // CHECK6-LABEL: define void @_ZN5test61gEv()
190*67e74705SXin Li // CHECK6: call void @_ZN5test61AC1Ev(
191*67e74705SXin Li // CHECK6-NOT: call void @llvm.assume(
192*67e74705SXin Li 
193*67e74705SXin Li // We can't emit assumption loads for B, because if we would refer to vtable
194*67e74705SXin Li // it would refer to functions that will not be able to find (like implicit
195*67e74705SXin Li // inline destructor).
196*67e74705SXin Li 
197*67e74705SXin Li // CHECK6-LABEL:   call void @_ZN5test61BC1Ev(
198*67e74705SXin Li // CHECK6-NOT: call void @llvm.assume(
199*67e74705SXin Li // CHECK6-LABEL: }
g()200*67e74705SXin Li void g() {
201*67e74705SXin Li   A *a = new A;
202*67e74705SXin Li   B *b = new B;
203*67e74705SXin Li }
204*67e74705SXin Li }
205*67e74705SXin Li 
206*67e74705SXin Li namespace test7 {
207*67e74705SXin Li // Because A's key function is defined here, vtable is generated in this TU
208*67e74705SXin Li // CHECK7: @_ZTVN5test71AE = unnamed_addr constant
209*67e74705SXin Li struct A {
210*67e74705SXin Li   A();
211*67e74705SXin Li   virtual void foo();
212*67e74705SXin Li   virtual void bar();
213*67e74705SXin Li };
foo()214*67e74705SXin Li void A::foo() {}
215*67e74705SXin Li 
216*67e74705SXin Li // CHECK7-LABEL: define void @_ZN5test71gEv()
217*67e74705SXin Li // CHECK7: call void @_ZN5test71AC1Ev(
218*67e74705SXin Li // CHECK7: call void @llvm.assume(
219*67e74705SXin Li // CHECK7-LABEL: }
g()220*67e74705SXin Li void g() {
221*67e74705SXin Li   A *a = new A();
222*67e74705SXin Li   a->bar();
223*67e74705SXin Li }
224*67e74705SXin Li }
225*67e74705SXin Li 
226*67e74705SXin Li namespace test8 {
227*67e74705SXin Li 
228*67e74705SXin Li struct A {
229*67e74705SXin Li   virtual void foo();
230*67e74705SXin Li   virtual void bar();
231*67e74705SXin Li };
232*67e74705SXin Li 
233*67e74705SXin Li // CHECK8-DAG: @_ZTVN5test81BE = available_externally unnamed_addr constant
234*67e74705SXin Li struct B : A {
235*67e74705SXin Li   B();
236*67e74705SXin Li   void foo();
237*67e74705SXin Li   void bar();
238*67e74705SXin Li };
239*67e74705SXin Li 
240*67e74705SXin Li // CHECK8-DAG: @_ZTVN5test81CE = linkonce_odr unnamed_addr constant
241*67e74705SXin Li struct C : A {
242*67e74705SXin Li   C();
243*67e74705SXin Li   void bar();
footest8::C244*67e74705SXin Li   void foo() {}
245*67e74705SXin Li };
bar()246*67e74705SXin Li inline void C::bar() {}
247*67e74705SXin Li 
248*67e74705SXin Li struct D : A {
249*67e74705SXin Li   D();
250*67e74705SXin Li   void foo();
251*67e74705SXin Li   void inline bar();
252*67e74705SXin Li };
bar()253*67e74705SXin Li void D::bar() {}
254*67e74705SXin Li 
255*67e74705SXin Li // CHECK8-DAG: @_ZTVN5test81EE = linkonce_odr unnamed_addr constant
256*67e74705SXin Li struct E : A {
257*67e74705SXin Li   E();
258*67e74705SXin Li };
259*67e74705SXin Li 
260*67e74705SXin Li // CHECK8-LABEL: define void @_ZN5test81bEv()
261*67e74705SXin Li // CHECK8: call void @llvm.assume(
262*67e74705SXin Li // CHECK8-LABEL: }
b()263*67e74705SXin Li void b() {
264*67e74705SXin Li   B b;
265*67e74705SXin Li   b.bar();
266*67e74705SXin Li }
267*67e74705SXin Li 
268*67e74705SXin Li // FIXME: C has inline virtual functions which prohibits as from generating
269*67e74705SXin Li // assumption loads, but because vtable is generated in this TU (key function
270*67e74705SXin Li // defined here) it would be correct to refer to it.
271*67e74705SXin Li // CHECK8-LABEL: define void @_ZN5test81cEv()
272*67e74705SXin Li // CHECK8-NOT: call void @llvm.assume(
273*67e74705SXin Li // CHECK8-LABEL: }
c()274*67e74705SXin Li void c() {
275*67e74705SXin Li   C c;
276*67e74705SXin Li   c.bar();
277*67e74705SXin Li }
278*67e74705SXin Li 
279*67e74705SXin Li // FIXME: We could generate assumption loads here.
280*67e74705SXin Li // CHECK8-LABEL: define void @_ZN5test81dEv()
281*67e74705SXin Li // CHECK8-NOT: call void @llvm.assume(
282*67e74705SXin Li // CHECK8-LABEL: }
d()283*67e74705SXin Li void d() {
284*67e74705SXin Li   D d;
285*67e74705SXin Li   d.bar();
286*67e74705SXin Li }
287*67e74705SXin Li 
288*67e74705SXin Li // CHECK8-LABEL: define void @_ZN5test81eEv()
289*67e74705SXin Li // CHECK8: call void @llvm.assume(
290*67e74705SXin Li // CHECK8-LABEL: }
e()291*67e74705SXin Li void e() {
292*67e74705SXin Li   E e;
293*67e74705SXin Li   e.bar();
294*67e74705SXin Li }
295*67e74705SXin Li }
296*67e74705SXin Li 
297*67e74705SXin Li namespace test9 {
298*67e74705SXin Li 
299*67e74705SXin Li struct S {
300*67e74705SXin Li   S();
301*67e74705SXin Li   __attribute__((visibility("hidden"))) virtual void doStuff();
302*67e74705SXin Li };
303*67e74705SXin Li 
304*67e74705SXin Li // CHECK9-LABEL: define void @_ZN5test94testEv()
305*67e74705SXin Li // CHECK9-NOT: @llvm.assume(
306*67e74705SXin Li // CHECK9: }
test()307*67e74705SXin Li void test() {
308*67e74705SXin Li   S *s = new S();
309*67e74705SXin Li   s->doStuff();
310*67e74705SXin Li   delete s;
311*67e74705SXin Li }
312*67e74705SXin Li }
313*67e74705SXin Li 
314