320 lines · cpp
1// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fstrict-vtable-pointers -o - %s \2// RUN: | FileCheck --check-prefixes=CHECK,CHECK-STRICT %s3// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s \4// RUN: | FileCheck --check-prefixes=CHECK,CHECK-NONSTRICT %s5 6//===----------------------------------------------------------------------===//7// Positive Cases8//===----------------------------------------------------------------------===//9 10struct TestVirtualFn {11 virtual void foo() {}12};13 14// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_fn15extern "C" void test_builtin_launder_virtual_fn(TestVirtualFn *p) {16 // CHECK: store ptr %p, ptr %p.addr17 // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr %p.addr18 19 // CHECK-NONSTRICT-NEXT: store ptr [[TMP0]], ptr %d20 21 // CHECK-STRICT-NEXT: [[TMP2:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[TMP0]])22 // CHECK-STRICT-NEXT: store ptr [[TMP2]], ptr %d23 24 // CHECK-NEXT: ret void25 TestVirtualFn *d = __builtin_launder(p);26}27 28struct TestPolyBase : TestVirtualFn {29};30 31// CHECK-LABEL: define{{.*}} void @test_builtin_launder_poly_base32extern "C" void test_builtin_launder_poly_base(TestPolyBase *p) {33 // CHECK-STRICT-NOT: ret void34 // CHECK-STRICT: @llvm.launder.invariant.group35 36 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group37 38 // CHECK: ret void39 TestPolyBase *d = __builtin_launder(p);40}41 42struct TestBase {};43struct TestVirtualBase : virtual TestBase {};44 45// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_base46extern "C" void test_builtin_launder_virtual_base(TestVirtualBase *p) {47 // CHECK-STRICT-NOT: ret void48 // CHECK-STRICT: @llvm.launder.invariant.group49 50 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group51 52 // CHECK: ret void53 TestVirtualBase *d = __builtin_launder(p);54}55 56//===----------------------------------------------------------------------===//57// Negative Cases58//===----------------------------------------------------------------------===//59 60// CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_one61extern "C" void test_builtin_launder_ommitted_one(int *p) {62 // CHECK: entry63 // CHECK-NEXT: %p.addr = alloca ptr64 // CHECK-NEXT: %d = alloca ptr65 // CHECK-NEXT: store ptr %p, ptr %p.addr, align 866 // CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr %p.addr67 // CHECK-NEXT: store ptr [[TMP]], ptr %d68 // CHECK-NEXT: ret void69 int *d = __builtin_launder(p);70}71 72struct TestNoInvariant {73 int x;74};75 76// CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_two77extern "C" void test_builtin_launder_ommitted_two(TestNoInvariant *p) {78 // CHECK: entry79 // CHECK-NOT: llvm.launder.invariant.group80 // CHECK-NEXT: %p.addr = alloca ptr, align 881 // CHECK-NEXT: %d = alloca ptr82 // CHECK-NEXT: store ptr %p, ptr %p.addr83 // CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr %p.addr84 // CHECK-NEXT: store ptr [[TMP]], ptr %d85 // CHECK-NEXT: ret void86 TestNoInvariant *d = __builtin_launder(p);87}88 89struct TestVirtualMember {90 TestVirtualFn member;91};92 93// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_member94extern "C" void test_builtin_launder_virtual_member(TestVirtualMember *p) {95 // CHECK: entry96 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group97 // CHECK-STRICT: @llvm.launder.invariant.group98 // CHECK: ret void99 TestVirtualMember *d = __builtin_launder(p);100}101 102struct TestVirtualMemberDepth2 {103 TestVirtualMember member;104};105 106// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_member_depth_2107extern "C" void test_builtin_launder_virtual_member_depth_2(TestVirtualMemberDepth2 *p) {108 // CHECK: entry109 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group110 // CHECK-STRICT: @llvm.launder.invariant.group111 // CHECK: ret void112 TestVirtualMemberDepth2 *d = __builtin_launder(p);113}114 115struct TestVirtualReferenceMember {116 TestVirtualFn &member;117};118 119// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_reference_member120extern "C" void test_builtin_launder_virtual_reference_member(TestVirtualReferenceMember *p) {121 // CHECK: entry122 // CHECK-NOT: @llvm.launder.invariant.group123 // CHECK: ret void124 TestVirtualReferenceMember *d = __builtin_launder(p);125}126 127struct TestRecursiveMember {128 TestRecursiveMember() : member(*this) {}129 TestRecursiveMember &member;130};131 132// CHECK-LABEL: define{{.*}} void @test_builtin_launder_recursive_member133extern "C" void test_builtin_launder_recursive_member(TestRecursiveMember *p) {134 // CHECK: entry135 // CHECK-NOT: @llvm.launder.invariant.group136 // CHECK: ret void137 TestRecursiveMember *d = __builtin_launder(p);138}139 140struct TestVirtualRecursiveMember {141 TestVirtualRecursiveMember() : member(*this) {}142 TestVirtualRecursiveMember &member;143 virtual void foo();144};145 146// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_recursive_member147extern "C" void test_builtin_launder_virtual_recursive_member(TestVirtualRecursiveMember *p) {148 // CHECK: entry149 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group150 // CHECK-STRICT: @llvm.launder.invariant.group151 // CHECK: ret void152 TestVirtualRecursiveMember *d = __builtin_launder(p);153}154 155// CHECK-LABEL: define{{.*}} void @test_builtin_launder_array(156extern "C" void test_builtin_launder_array(TestVirtualFn (&Arr)[5]) {157 // CHECK: entry158 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group159 // CHECK-STRICT: @llvm.launder.invariant.group160 // CHECK: ret void161 TestVirtualFn *d = __builtin_launder(Arr);162}163 164// CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_nested(165extern "C" void test_builtin_launder_array_nested(TestVirtualFn (&Arr)[5][2]) {166 // CHECK: entry167 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group168 // CHECK-STRICT: @llvm.launder.invariant.group169 // CHECK: ret void170 using RetTy = TestVirtualFn(*)[2];171 RetTy d = __builtin_launder(Arr);172}173 174// CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_no_invariant(175extern "C" void test_builtin_launder_array_no_invariant(TestNoInvariant (&Arr)[5]) {176 // CHECK: entry177 // CHECK-NOT: @llvm.launder.invariant.group178 // CHECK: ret void179 TestNoInvariant *d = __builtin_launder(Arr);180}181 182// CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_nested_no_invariant(183extern "C" void test_builtin_launder_array_nested_no_invariant(TestNoInvariant (&Arr)[5][2]) {184 // CHECK: entry185 // CHECK-NOT: @llvm.launder.invariant.group186 // CHECK: ret void187 using RetTy = TestNoInvariant(*)[2];188 RetTy d = __builtin_launder(Arr);189}190 191template <class Member>192struct WithMember {193 Member mem;194};195 196template struct WithMember<TestVirtualFn[5]>;197 198// CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array(199extern "C" void test_builtin_launder_member_array(WithMember<TestVirtualFn[5]> *p) {200 // CHECK: entry201 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group202 // CHECK-STRICT: @llvm.launder.invariant.group203 // CHECK: ret void204 auto *d = __builtin_launder(p);205}206 207template struct WithMember<TestVirtualFn[5][2]>;208 209// CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_nested(210extern "C" void test_builtin_launder_member_array_nested(WithMember<TestVirtualFn[5][2]> *p) {211 // CHECK: entry212 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group213 // CHECK-STRICT: @llvm.launder.invariant.group214 // CHECK: ret void215 auto *d = __builtin_launder(p);216}217 218template struct WithMember<TestNoInvariant[5]>;219 220// CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_no_invariant(221extern "C" void test_builtin_launder_member_array_no_invariant(WithMember<TestNoInvariant[5]> *p) {222 // CHECK: entry223 // CHECK-NOT: @llvm.launder.invariant.group224 // CHECK: ret void225 auto *d = __builtin_launder(p);226}227 228template struct WithMember<TestNoInvariant[5][2]>;229 230// CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_nested_no_invariant(231extern "C" void test_builtin_launder_member_array_nested_no_invariant(WithMember<TestNoInvariant[5][2]> *p) {232 // CHECK: entry233 // CHECK-NOT: @llvm.launder.invariant.group234 // CHECK: ret void235 auto *d = __builtin_launder(p);236}237 238template <class T>239struct WithBase : T {};240 241template struct WithBase<TestNoInvariant>;242 243// CHECK-LABEL: define{{.*}} void @test_builtin_launder_base_no_invariant(244extern "C" void test_builtin_launder_base_no_invariant(WithBase<TestNoInvariant> *p) {245 // CHECK: entry246 // CHECK-NOT: @llvm.launder.invariant.group247 // CHECK: ret void248 auto *d = __builtin_launder(p);249}250 251template struct WithBase<TestVirtualFn>;252 253// CHECK-LABEL: define{{.*}} void @test_builtin_launder_base(254extern "C" void test_builtin_launder_base(WithBase<TestVirtualFn> *p) {255 // CHECK: entry256 // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group257 // CHECK-STRICT: @llvm.launder.invariant.group258 // CHECK: ret void259 auto *d = __builtin_launder(p);260}261 262/// The test cases in this namespace technically need to be laundered according263/// 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 emits265/// __builtin_launder as a nop.266///267/// NOTE: Adding optimizations for these cases later is an LTO ABI break. That's268/// probably OK for now -- but is something to keep in mind.269namespace pessimizing_cases {270 271struct TestConstMember {272 const int x;273};274 275// CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_member276extern "C" void test_builtin_launder_const_member(TestConstMember *p) {277 // CHECK: entry278 // CHECK-NOT: @llvm.launder.invariant.group279 // CHECK: ret void280 TestConstMember *d = __builtin_launder(p);281}282 283struct TestConstSubobject {284 TestConstMember x;285};286 287// CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_subobject288extern "C" void test_builtin_launder_const_subobject(TestConstSubobject *p) {289 // CHECK: entry290 // CHECK-NOT: @llvm.launder.invariant.group291 // CHECK: ret void292 TestConstSubobject *d = __builtin_launder(p);293}294 295struct TestConstObject {296 const struct TestConstMember x;297};298 299// CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_object300extern "C" void test_builtin_launder_const_object(TestConstObject *p) {301 // CHECK: entry302 // CHECK-NOT: @llvm.launder.invariant.group303 // CHECK: ret void304 TestConstObject *d = __builtin_launder(p);305}306 307struct TestReferenceMember {308 int &x;309};310 311// CHECK-LABEL: define{{.*}} void @test_builtin_launder_reference_member312extern "C" void test_builtin_launder_reference_member(TestReferenceMember *p) {313 // CHECK: entry314 // CHECK-NOT: @llvm.launder.invariant.group315 // CHECK: ret void316 TestReferenceMember *d = __builtin_launder(p);317}318 319} // namespace pessimizing_cases320