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 //===----------------------------------------------------------------------===//
8 //===----------------------------------------------------------------------===//
10 struct TestVirtualFn
{
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
39 TestPolyBase
*d
= __builtin_launder(p
);
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
53 TestVirtualBase
*d
= __builtin_launder(p
);
56 //===----------------------------------------------------------------------===//
58 //===----------------------------------------------------------------------===//
60 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_one
61 extern "C" void test_builtin_launder_ommitted_one(int *p
) {
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
{
76 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_two
77 extern "C" void test_builtin_launder_ommitted_two(TestNoInvariant
*p
) {
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
{
93 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_member
94 extern "C" void test_builtin_launder_virtual_member(TestVirtualMember
*p
) {
96 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
97 // CHECK-STRICT: @llvm.launder.invariant.group
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
) {
109 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
110 // CHECK-STRICT: @llvm.launder.invariant.group
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
) {
122 // CHECK-NOT: @llvm.launder.invariant.group
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
) {
135 // CHECK-NOT: @llvm.launder.invariant.group
137 TestRecursiveMember
*d
= __builtin_launder(p
);
140 struct TestVirtualRecursiveMember
{
141 TestVirtualRecursiveMember() : member(*this) {}
142 TestVirtualRecursiveMember
&member
;
146 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_recursive_member
147 extern "C" void test_builtin_launder_virtual_recursive_member(TestVirtualRecursiveMember
*p
) {
149 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
150 // CHECK-STRICT: @llvm.launder.invariant.group
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]) {
158 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
159 // CHECK-STRICT: @llvm.launder.invariant.group
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]) {
167 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
168 // CHECK-STRICT: @llvm.launder.invariant.group
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]) {
177 // CHECK-NOT: @llvm.launder.invariant.group
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]) {
185 // CHECK-NOT: @llvm.launder.invariant.group
187 using RetTy
= TestNoInvariant(*)[2];
188 RetTy d
= __builtin_launder(Arr
);
191 template <class Member
>
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
) {
201 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
202 // CHECK-STRICT: @llvm.launder.invariant.group
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
) {
212 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
213 // CHECK-STRICT: @llvm.launder.invariant.group
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
) {
223 // CHECK-NOT: @llvm.launder.invariant.group
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
) {
233 // CHECK-NOT: @llvm.launder.invariant.group
235 auto *d
= __builtin_launder(p
);
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
) {
246 // CHECK-NOT: @llvm.launder.invariant.group
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
) {
256 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
257 // CHECK-STRICT: @llvm.launder.invariant.group
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
{
275 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_member
276 extern "C" void test_builtin_launder_const_member(TestConstMember
*p
) {
278 // CHECK-NOT: @llvm.launder.invariant.group
280 TestConstMember
*d
= __builtin_launder(p
);
283 struct TestConstSubobject
{
287 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_subobject
288 extern "C" void test_builtin_launder_const_subobject(TestConstSubobject
*p
) {
290 // CHECK-NOT: @llvm.launder.invariant.group
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
) {
302 // CHECK-NOT: @llvm.launder.invariant.group
304 TestConstObject
*d
= __builtin_launder(p
);
307 struct TestReferenceMember
{
311 // CHECK-LABEL: define{{.*}} void @test_builtin_launder_reference_member
312 extern "C" void test_builtin_launder_reference_member(TestReferenceMember
*p
) {
314 // CHECK-NOT: @llvm.launder.invariant.group
316 TestReferenceMember
*d
= __builtin_launder(p
);
319 } // namespace pessimizing_cases