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