forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			314 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			314 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o %t.ll -O1 -disable-llvm-optzns -fms-extensions -fstrict-vtable-pointers
 | 
						|
// RUN: %clang_cc1 %s -triple i686-pc-win32 -emit-llvm -o %t.ms.ll -O1 -disable-llvm-optzns -fms-extensions -fstrict-vtable-pointers
 | 
						|
// FIXME: Assume load should not require -fstrict-vtable-pointers
 | 
						|
 | 
						|
// 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
 | 
						|
// RUN: FileCheck --check-prefix=CHECK9 --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, i32 0, i32 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, i32 0, i32 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, i32 0, i32 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, i32 0, i32 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, i32 0, i32 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, i32 0, i32 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, i32 0, i32 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 {
 | 
						|
struct A {
 | 
						|
  A();
 | 
						|
  virtual void foo();
 | 
						|
  virtual ~A() {}
 | 
						|
};
 | 
						|
struct B : A {
 | 
						|
  B();
 | 
						|
};
 | 
						|
// FIXME: Because A's vtable is external, and no virtual functions are hidden,
 | 
						|
// it's safe to generate assumption loads.
 | 
						|
// CHECK6-LABEL: define void @_ZN5test61gEv()
 | 
						|
// CHECK6: call void @_ZN5test61AC1Ev(
 | 
						|
// CHECK6-NOT: 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() {}
 | 
						|
 | 
						|
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();
 | 
						|
}
 | 
						|
 | 
						|
// FIXME: We could generate assumption loads here.
 | 
						|
// CHECK8-LABEL: define void @_ZN5test81dEv()
 | 
						|
// CHECK8-NOT: 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();
 | 
						|
}
 | 
						|
}
 | 
						|
 | 
						|
namespace test9 {
 | 
						|
 | 
						|
struct S {
 | 
						|
  S();
 | 
						|
  __attribute__((visibility("hidden"))) virtual void doStuff();
 | 
						|
};
 | 
						|
 | 
						|
// CHECK9-LABEL: define void @_ZN5test94testEv()
 | 
						|
// CHECK9-NOT: @llvm.assume(
 | 
						|
// CHECK9: }
 | 
						|
void test() {
 | 
						|
  S *s = new S();
 | 
						|
  s->doStuff();
 | 
						|
  delete s;
 | 
						|
}
 | 
						|
}
 | 
						|
 |