Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / test / CodeGenCXX / builtin-launder.cpp
blob06a93d1c441d29662eb8de6c68a157c55436390d
1 // RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fstrict-vtable-pointers -o - %s \
2 // RUN: | FileCheck --check-prefixes=CHECK,CHECK-STRICT %s
3 // RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s \
4 // RUN: | FileCheck --check-prefixes=CHECK,CHECK-NONSTRICT %s
6 //===----------------------------------------------------------------------===//
7 // Positive Cases
8 //===----------------------------------------------------------------------===//
10 struct TestVirtualFn {
11 virtual void foo() {}
14 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_fn
15 extern "C" void test_builtin_launder_virtual_fn(TestVirtualFn *p) {
16 // CHECK: store ptr %p, ptr %p.addr
17 // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr %p.addr
19 // CHECK-NONSTRICT-NEXT: store ptr [[TMP0]], ptr %d
21 // CHECK-STRICT-NEXT: [[TMP2:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[TMP0]])
22 // CHECK-STRICT-NEXT: store ptr [[TMP2]], ptr %d
24 // CHECK-NEXT: ret void
25 TestVirtualFn *d = __builtin_launder(p);
28 struct TestPolyBase : TestVirtualFn {
31 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_poly_base
32 extern "C" void test_builtin_launder_poly_base(TestPolyBase *p) {
33 // CHECK-STRICT-NOT: ret void
34 // CHECK-STRICT: @llvm.launder.invariant.group
36 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
38 // CHECK: ret void
39 TestPolyBase *d = __builtin_launder(p);
42 struct TestBase {};
43 struct TestVirtualBase : virtual TestBase {};
45 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_base
46 extern "C" void test_builtin_launder_virtual_base(TestVirtualBase *p) {
47 // CHECK-STRICT-NOT: ret void
48 // CHECK-STRICT: @llvm.launder.invariant.group
50 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
52 // CHECK: ret void
53 TestVirtualBase *d = __builtin_launder(p);
56 //===----------------------------------------------------------------------===//
57 // Negative Cases
58 //===----------------------------------------------------------------------===//
60 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_one
61 extern "C" void test_builtin_launder_ommitted_one(int *p) {
62 // CHECK: entry
63 // CHECK-NEXT: %p.addr = alloca ptr
64 // CHECK-NEXT: %d = alloca ptr
65 // CHECK-NEXT: store ptr %p, ptr %p.addr, align 8
66 // CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr %p.addr
67 // CHECK-NEXT: store ptr [[TMP]], ptr %d
68 // CHECK-NEXT: ret void
69 int *d = __builtin_launder(p);
72 struct TestNoInvariant {
73 int x;
76 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_two
77 extern "C" void test_builtin_launder_ommitted_two(TestNoInvariant *p) {
78 // CHECK: entry
79 // CHECK-NOT: llvm.launder.invariant.group
80 // CHECK-NEXT: %p.addr = alloca ptr, align 8
81 // CHECK-NEXT: %d = alloca ptr
82 // CHECK-NEXT: store ptr %p, ptr %p.addr
83 // CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr %p.addr
84 // CHECK-NEXT: store ptr [[TMP]], ptr %d
85 // CHECK-NEXT: ret void
86 TestNoInvariant *d = __builtin_launder(p);
89 struct TestVirtualMember {
90 TestVirtualFn member;
93 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_member
94 extern "C" void test_builtin_launder_virtual_member(TestVirtualMember *p) {
95 // CHECK: entry
96 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
97 // CHECK-STRICT: @llvm.launder.invariant.group
98 // CHECK: ret void
99 TestVirtualMember *d = __builtin_launder(p);
102 struct TestVirtualMemberDepth2 {
103 TestVirtualMember member;
106 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_member_depth_2
107 extern "C" void test_builtin_launder_virtual_member_depth_2(TestVirtualMemberDepth2 *p) {
108 // CHECK: entry
109 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
110 // CHECK-STRICT: @llvm.launder.invariant.group
111 // CHECK: ret void
112 TestVirtualMemberDepth2 *d = __builtin_launder(p);
115 struct TestVirtualReferenceMember {
116 TestVirtualFn &member;
119 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_reference_member
120 extern "C" void test_builtin_launder_virtual_reference_member(TestVirtualReferenceMember *p) {
121 // CHECK: entry
122 // CHECK-NOT: @llvm.launder.invariant.group
123 // CHECK: ret void
124 TestVirtualReferenceMember *d = __builtin_launder(p);
127 struct TestRecursiveMember {
128 TestRecursiveMember() : member(*this) {}
129 TestRecursiveMember &member;
132 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_recursive_member
133 extern "C" void test_builtin_launder_recursive_member(TestRecursiveMember *p) {
134 // CHECK: entry
135 // CHECK-NOT: @llvm.launder.invariant.group
136 // CHECK: ret void
137 TestRecursiveMember *d = __builtin_launder(p);
140 struct TestVirtualRecursiveMember {
141 TestVirtualRecursiveMember() : member(*this) {}
142 TestVirtualRecursiveMember &member;
143 virtual void foo();
146 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_recursive_member
147 extern "C" void test_builtin_launder_virtual_recursive_member(TestVirtualRecursiveMember *p) {
148 // CHECK: entry
149 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
150 // CHECK-STRICT: @llvm.launder.invariant.group
151 // CHECK: ret void
152 TestVirtualRecursiveMember *d = __builtin_launder(p);
155 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_array(
156 extern "C" void test_builtin_launder_array(TestVirtualFn (&Arr)[5]) {
157 // CHECK: entry
158 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
159 // CHECK-STRICT: @llvm.launder.invariant.group
160 // CHECK: ret void
161 TestVirtualFn *d = __builtin_launder(Arr);
164 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_nested(
165 extern "C" void test_builtin_launder_array_nested(TestVirtualFn (&Arr)[5][2]) {
166 // CHECK: entry
167 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
168 // CHECK-STRICT: @llvm.launder.invariant.group
169 // CHECK: ret void
170 using RetTy = TestVirtualFn(*)[2];
171 RetTy d = __builtin_launder(Arr);
174 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_no_invariant(
175 extern "C" void test_builtin_launder_array_no_invariant(TestNoInvariant (&Arr)[5]) {
176 // CHECK: entry
177 // CHECK-NOT: @llvm.launder.invariant.group
178 // CHECK: ret void
179 TestNoInvariant *d = __builtin_launder(Arr);
182 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_nested_no_invariant(
183 extern "C" void test_builtin_launder_array_nested_no_invariant(TestNoInvariant (&Arr)[5][2]) {
184 // CHECK: entry
185 // CHECK-NOT: @llvm.launder.invariant.group
186 // CHECK: ret void
187 using RetTy = TestNoInvariant(*)[2];
188 RetTy d = __builtin_launder(Arr);
191 template <class Member>
192 struct WithMember {
193 Member mem;
196 template struct WithMember<TestVirtualFn[5]>;
198 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array(
199 extern "C" void test_builtin_launder_member_array(WithMember<TestVirtualFn[5]> *p) {
200 // CHECK: entry
201 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
202 // CHECK-STRICT: @llvm.launder.invariant.group
203 // CHECK: ret void
204 auto *d = __builtin_launder(p);
207 template struct WithMember<TestVirtualFn[5][2]>;
209 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_nested(
210 extern "C" void test_builtin_launder_member_array_nested(WithMember<TestVirtualFn[5][2]> *p) {
211 // CHECK: entry
212 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
213 // CHECK-STRICT: @llvm.launder.invariant.group
214 // CHECK: ret void
215 auto *d = __builtin_launder(p);
218 template struct WithMember<TestNoInvariant[5]>;
220 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_no_invariant(
221 extern "C" void test_builtin_launder_member_array_no_invariant(WithMember<TestNoInvariant[5]> *p) {
222 // CHECK: entry
223 // CHECK-NOT: @llvm.launder.invariant.group
224 // CHECK: ret void
225 auto *d = __builtin_launder(p);
228 template struct WithMember<TestNoInvariant[5][2]>;
230 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_nested_no_invariant(
231 extern "C" void test_builtin_launder_member_array_nested_no_invariant(WithMember<TestNoInvariant[5][2]> *p) {
232 // CHECK: entry
233 // CHECK-NOT: @llvm.launder.invariant.group
234 // CHECK: ret void
235 auto *d = __builtin_launder(p);
238 template <class T>
239 struct WithBase : T {};
241 template struct WithBase<TestNoInvariant>;
243 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_base_no_invariant(
244 extern "C" void test_builtin_launder_base_no_invariant(WithBase<TestNoInvariant> *p) {
245 // CHECK: entry
246 // CHECK-NOT: @llvm.launder.invariant.group
247 // CHECK: ret void
248 auto *d = __builtin_launder(p);
251 template struct WithBase<TestVirtualFn>;
253 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_base(
254 extern "C" void test_builtin_launder_base(WithBase<TestVirtualFn> *p) {
255 // CHECK: entry
256 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
257 // CHECK-STRICT: @llvm.launder.invariant.group
258 // CHECK: ret void
259 auto *d = __builtin_launder(p);
262 /// The test cases in this namespace technically need to be laundered according
263 /// to the language in the standard (ie they have const or reference subobjects)
264 /// but LLVM doesn't currently optimize on these cases -- so Clang emits
265 /// __builtin_launder as a nop.
267 /// NOTE: Adding optimizations for these cases later is an LTO ABI break. That's
268 /// probably OK for now -- but is something to keep in mind.
269 namespace pessimizing_cases {
271 struct TestConstMember {
272 const int x;
275 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_member
276 extern "C" void test_builtin_launder_const_member(TestConstMember *p) {
277 // CHECK: entry
278 // CHECK-NOT: @llvm.launder.invariant.group
279 // CHECK: ret void
280 TestConstMember *d = __builtin_launder(p);
283 struct TestConstSubobject {
284 TestConstMember x;
287 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_subobject
288 extern "C" void test_builtin_launder_const_subobject(TestConstSubobject *p) {
289 // CHECK: entry
290 // CHECK-NOT: @llvm.launder.invariant.group
291 // CHECK: ret void
292 TestConstSubobject *d = __builtin_launder(p);
295 struct TestConstObject {
296 const struct TestConstMember x;
299 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_object
300 extern "C" void test_builtin_launder_const_object(TestConstObject *p) {
301 // CHECK: entry
302 // CHECK-NOT: @llvm.launder.invariant.group
303 // CHECK: ret void
304 TestConstObject *d = __builtin_launder(p);
307 struct TestReferenceMember {
308 int &x;
311 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_reference_member
312 extern "C" void test_builtin_launder_reference_member(TestReferenceMember *p) {
313 // CHECK: entry
314 // CHECK-NOT: @llvm.launder.invariant.group
315 // CHECK: ret void
316 TestReferenceMember *d = __builtin_launder(p);
319 } // namespace pessimizing_cases