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