summaryrefslogtreecommitdiffstats
path: root/test/CodeGenCXX/vtable-assume-load.cpp
diff options
context:
space:
mode:
authorPiotr Padlewski <prazek@google.com>2015-09-09 22:20:28 +0000
committerPiotr Padlewski <prazek@google.com>2015-09-09 22:20:28 +0000
commit982bb7d966947812d216489b3c519c9825cacbf2 (patch)
treea5f1d33eaeba73405bac45876d93625415f38b5c /test/CodeGenCXX/vtable-assume-load.cpp
parent1694b9d193ea9f50314856b0f2d769ba20e92778 (diff)
Generating assumption loads of vptr after ctor call (fixed)
Generating call assume(icmp %vtable, %global_vtable) after constructor call for devirtualization purposes. For more info go to: http://lists.llvm.org/pipermail/cfe-dev/2015-July/044227.html Edit: Fixed version because of PR24479. After this patch got reverted because of ScalarEvolution bug (D12719) Merged after John McCall big patch (Added Address). http://reviews.llvm.org/D11859 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247199 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CodeGenCXX/vtable-assume-load.cpp')
-rw-r--r--test/CodeGenCXX/vtable-assume-load.cpp293
1 files changed, 293 insertions, 0 deletions
diff --git a/test/CodeGenCXX/vtable-assume-load.cpp b/test/CodeGenCXX/vtable-assume-load.cpp
new file mode 100644
index 0000000000..d527ab0a1a
--- /dev/null
+++ b/test/CodeGenCXX/vtable-assume-load.cpp
@@ -0,0 +1,293 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o %t.ll -O1 -disable-llvm-optzns -fms-extensions
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -emit-llvm -o %t.ms.ll -O1 -disable-llvm-optzns -fms-extensions
+
+// RUN: FileCheck --check-prefix=CHECK1 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK2 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK3 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK4 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK-MS --input-file=%t.ms.ll %s
+// RUN: FileCheck --check-prefix=CHECK6 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK7 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK8 --input-file=%t.ll %s
+namespace test1 {
+
+struct A {
+ A();
+ virtual void foo();
+};
+
+struct B : A {
+ virtual void foo();
+};
+
+void g(A *a) { a->foo(); }
+
+// CHECK1-LABEL: define void @_ZN5test14fooAEv()
+// CHECK1: call void @_ZN5test11AC1Ev(%"struct.test1::A"*
+// CHECK1: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
+// CHECK1: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([3 x i8*], [3 x i8*]* @_ZTVN5test11AE, i64 0, i64 2)
+// CHECK1: call void @llvm.assume(i1 %[[CMP]])
+// CHECK1-LABEL: }
+
+void fooA() {
+ A a;
+ g(&a);
+}
+
+// CHECK1-LABEL: define void @_ZN5test14fooBEv()
+// CHECK1: call void @_ZN5test11BC1Ev(%"struct.test1::B"* %{{.*}})
+// CHECK1: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
+// CHECK1: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([3 x i8*], [3 x i8*]* @_ZTVN5test11BE, i64 0, i64 2)
+// CHECK1: call void @llvm.assume(i1 %[[CMP]])
+// CHECK1-LABEL: }
+
+void fooB() {
+ B b;
+ g(&b);
+}
+// there should not be any assumes in the ctor that calls base ctor
+// CHECK1-LABEL: define linkonce_odr void @_ZN5test11BC2Ev(%"struct.test1::B"*
+// CHECK1-NOT: @llvm.assume(
+// CHECK1-LABEL: }
+}
+namespace test2 {
+struct A {
+ A();
+ virtual void foo();
+};
+
+struct B {
+ B();
+ virtual void bar();
+};
+
+struct C : A, B {
+ C();
+ virtual void foo();
+};
+void g(A *a) { a->foo(); }
+void h(B *b) { b->bar(); }
+
+// CHECK2-LABEL: define void @_ZN5test24testEv()
+// CHECK2: call void @_ZN5test21CC1Ev(%"struct.test2::C"*
+// CHECK2: %[[VTABLE:.*]] = load i8**, i8*** {{.*}}
+// CHECK2: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([6 x i8*], [6 x i8*]* @_ZTVN5test21CE, i64 0, i64 2)
+// CHECK2: call void @llvm.assume(i1 %[[CMP]])
+
+// CHECK2: %[[V2:.*]] = bitcast %"struct.test2::C"* %{{.*}} to i8*
+// CHECK2: %[[ADD_PTR:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 8
+// CHECK2: %[[V3:.*]] = bitcast i8* %[[ADD_PTR]] to i8***
+// CHECK2: %[[VTABLE2:.*]] = load i8**, i8*** %[[V3]]
+// CHECK2: %[[CMP2:.*]] = icmp eq i8** %[[VTABLE2]], getelementptr inbounds ([6 x i8*], [6 x i8*]* @_ZTVN5test21CE, i64 0, i64 5)
+// CHECK2: call void @llvm.assume(i1 %[[CMP2]])
+
+// CHECK2: call void @_ZN5test21gEPNS_1AE(
+// CHECK2-LABEL: }
+
+void test() {
+ C c;
+ g(&c);
+ h(&c);
+}
+}
+
+namespace test3 {
+struct A {
+ A();
+};
+
+struct B : A {
+ B();
+ virtual void foo();
+};
+
+struct C : virtual A, B {
+ C();
+ virtual void foo();
+};
+void g(B *a) { a->foo(); }
+
+// CHECK3-LABEL: define void @_ZN5test34testEv()
+// CHECK3: call void @_ZN5test31CC1Ev(%"struct.test3::C"*
+// CHECK3: %[[CMP:.*]] = icmp eq i8** %{{.*}}, getelementptr inbounds ([4 x i8*], [4 x i8*]* @_ZTVN5test31CE, i64 0, i64 3)
+// CHECK3: call void @llvm.assume(i1 %[[CMP]])
+// CHECK3-LABLEL: }
+void test() {
+ C c;
+ g(&c);
+}
+} // test3
+
+namespace test4 {
+struct A {
+ A();
+ virtual void foo();
+};
+
+struct B : virtual A {
+ B();
+ virtual void foo();
+};
+struct C : B {
+ C();
+ virtual void foo();
+};
+
+void g(C *c) { c->foo(); }
+
+// CHECK4-LABEL: define void @_ZN5test44testEv()
+// CHECK4: call void @_ZN5test41CC1Ev(%"struct.test4::C"*
+// CHECK4: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
+// CHECK4: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([5 x i8*], [5 x i8*]* @_ZTVN5test41CE, i64 0, i64 4)
+// CHECK4: call void @llvm.assume(i1 %[[CMP]]
+
+// CHECK4: %[[VTABLE2:.*]] = load i8**, i8*** %{{.*}}
+// CHECK4: %[[CMP2:.*]] = icmp eq i8** %[[VTABLE2]], getelementptr inbounds ([5 x i8*], [5 x i8*]* @_ZTVN5test41CE, i64 0, i64 4)
+// CHECK4: call void @llvm.assume(i1 %[[CMP2]])
+// CHECK4-LABEL: }
+
+void test() {
+ C c;
+ g(&c);
+}
+} // test4
+
+namespace testMS {
+
+struct __declspec(novtable) S {
+ virtual void foo();
+};
+
+void g(S &s) { s.foo(); }
+
+// if struct has novtable specifier, then we can't generate assumes
+// CHECK-MS-LABEL: define void @"\01?test@testMS@@YAXXZ"()
+// CHECK-MS: call x86_thiscallcc %"struct.testMS::S"* @"\01??0S@testMS@@QAE@XZ"(
+// CHECK-MS-NOT: @llvm.assume
+// CHECK-MS-LABEL: }
+
+void test() {
+ S s;
+ g(s);
+}
+
+} // testMS
+
+namespace test6 {
+// CHECK6: @_ZTVN5test61AE = external
+struct A {
+ A();
+ virtual void foo();
+ virtual ~A() {}
+};
+struct B : A {
+ B();
+};
+// Because A's vtable is external, it's safe to generate assumption loads.
+// CHECK6-LABEL: define void @_ZN5test61gEv()
+// CHECK6: call void @_ZN5test61AC1Ev(
+// CHECK6: call void @llvm.assume(
+
+// We can't emit assumption loads for B, because if we would refer to vtable
+// it would refer to functions that will not be able to find (like implicit
+// inline destructor).
+
+// CHECK6-LABEL: call void @_ZN5test61BC1Ev(
+// CHECK6-NOT: call void @llvm.assume(
+// CHECK6-LABEL: }
+void g() {
+ A *a = new A;
+ B *b = new B;
+}
+}
+
+namespace test7 {
+// Because A's key function is defined here, vtable is generated in this TU
+// CHECK7: @_ZTVN5test71AE = unnamed_addr constant
+struct A {
+ A();
+ virtual void foo();
+ virtual void bar();
+};
+void A::foo() {}
+
+// CHECK7-LABEL: define void @_ZN5test71gEv()
+// CHECK7: call void @_ZN5test71AC1Ev(
+// CHECK7: call void @llvm.assume(
+// CHECK7-LABEL: }
+void g() {
+ A *a = new A();
+ a->bar();
+}
+}
+
+namespace test8 {
+
+struct A {
+ virtual void foo();
+ virtual void bar();
+};
+
+// CHECK8-DAG: @_ZTVN5test81BE = available_externally unnamed_addr constant
+struct B : A {
+ B();
+ void foo();
+ void bar();
+};
+
+// CHECK8-DAG: @_ZTVN5test81CE = linkonce_odr unnamed_addr constant
+struct C : A {
+ C();
+ void bar();
+ void foo() {}
+};
+inline void C::bar() {}
+
+// CHECK8-DAG: @_ZTVN5test81DE = external unnamed_addr constant
+struct D : A {
+ D();
+ void foo();
+ void inline bar();
+};
+void D::bar() {}
+
+// CHECK8-DAG: @_ZTVN5test81EE = linkonce_odr unnamed_addr constant
+struct E : A {
+ E();
+};
+
+// CHECK8-LABEL: define void @_ZN5test81bEv()
+// CHECK8: call void @llvm.assume(
+// CHECK8-LABEL: }
+void b() {
+ B b;
+ b.bar();
+}
+
+// FIXME: C has inline virtual functions which prohibits as from generating
+// assumption loads, but because vtable is generated in this TU (key function
+// defined here) it would be correct to refer to it.
+// CHECK8-LABEL: define void @_ZN5test81cEv()
+// CHECK8-NOT: call void @llvm.assume(
+// CHECK8-LABEL: }
+void c() {
+ C c;
+ c.bar();
+}
+
+// CHECK8-LABEL: define void @_ZN5test81dEv()
+// CHECK8: call void @llvm.assume(
+// CHECK8-LABEL: }
+void d() {
+ D d;
+ d.bar();
+}
+
+// CHECK8-LABEL: define void @_ZN5test81eEv()
+// CHECK8: call void @llvm.assume(
+// CHECK8-LABEL: }
+void e() {
+ E e;
+ e.bar();
+}
+}