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