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