2009-12-16 04:14:24 +08:00
|
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
|
2009-09-16 23:53:40 +08:00
|
|
|
|
2009-11-23 07:01:23 +08:00
|
|
|
// Basic base class test.
|
|
|
|
struct f0_s0 { unsigned a; };
|
|
|
|
struct f0_s1 : public f0_s0 { void *b; };
|
2011-04-18 05:56:13 +08:00
|
|
|
// CHECK: define void @_Z2f05f0_s1(i32 %a0.coerce0, i8* %a0.coerce1)
|
2009-11-23 07:01:23 +08:00
|
|
|
void f0(f0_s1 a0) { }
|
|
|
|
|
|
|
|
// Check with two eight-bytes in base class.
|
|
|
|
struct f1_s0 { unsigned a; unsigned b; float c; };
|
|
|
|
struct f1_s1 : public f1_s0 { float d;};
|
2011-04-18 05:56:13 +08:00
|
|
|
// CHECK: define void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1)
|
2009-11-23 07:01:23 +08:00
|
|
|
void f1(f1_s1 a0) { }
|
|
|
|
|
|
|
|
// Check with two eight-bytes in base class and merge.
|
|
|
|
struct f2_s0 { unsigned a; unsigned b; float c; };
|
|
|
|
struct f2_s1 : public f2_s0 { char d;};
|
2010-06-29 08:14:52 +08:00
|
|
|
// CHECK: define void @_Z2f25f2_s1(i64 %a0.coerce0, i64 %a0.coerce1)
|
2009-11-23 07:01:23 +08:00
|
|
|
void f2(f2_s1 a0) { }
|
2009-09-16 23:53:40 +08:00
|
|
|
|
2009-12-22 09:19:25 +08:00
|
|
|
// PR5831
|
2010-07-30 12:02:24 +08:00
|
|
|
// CHECK: define void @_Z2f34s3_1(i64 %x.coerce)
|
2009-12-22 09:19:25 +08:00
|
|
|
struct s3_0 {};
|
|
|
|
struct s3_1 { struct s3_0 a; long b; };
|
|
|
|
void f3(struct s3_1 x) {}
|
2010-05-15 08:00:37 +08:00
|
|
|
|
Kill off the 'coerce' ABI passing form. Now 'direct' and 'extend' always
have a "coerce to" type which often matches the default lowering of Clang
type to LLVM IR type, but the coerce case can be handled by making them
not be the same.
This simplifies things and fixes issues where X86-64 abi lowering would
return coerce after making preferred types exactly match up. This caused
us to compile:
typedef float v4f32 __attribute__((__vector_size__(16)));
v4f32 foo(v4f32 X) {
return X+X;
}
into this code at -O0:
define <4 x float> @foo(<4 x float> %X.coerce) nounwind {
entry:
%retval = alloca <4 x float>, align 16 ; <<4 x float>*> [#uses=2]
%coerce = alloca <4 x float>, align 16 ; <<4 x float>*> [#uses=2]
%X.addr = alloca <4 x float>, align 16 ; <<4 x float>*> [#uses=3]
store <4 x float> %X.coerce, <4 x float>* %coerce
%X = load <4 x float>* %coerce ; <<4 x float>> [#uses=1]
store <4 x float> %X, <4 x float>* %X.addr
%tmp = load <4 x float>* %X.addr ; <<4 x float>> [#uses=1]
%tmp1 = load <4 x float>* %X.addr ; <<4 x float>> [#uses=1]
%add = fadd <4 x float> %tmp, %tmp1 ; <<4 x float>> [#uses=1]
store <4 x float> %add, <4 x float>* %retval
%0 = load <4 x float>* %retval ; <<4 x float>> [#uses=1]
ret <4 x float> %0
}
Now we get:
define <4 x float> @foo(<4 x float> %X) nounwind {
entry:
%X.addr = alloca <4 x float>, align 16 ; <<4 x float>*> [#uses=3]
store <4 x float> %X, <4 x float>* %X.addr
%tmp = load <4 x float>* %X.addr ; <<4 x float>> [#uses=1]
%tmp1 = load <4 x float>* %X.addr ; <<4 x float>> [#uses=1]
%add = fadd <4 x float> %tmp, %tmp1 ; <<4 x float>> [#uses=1]
ret <4 x float> %add
}
This implements rdar://8248065
llvm-svn: 109733
2010-07-29 14:26:06 +08:00
|
|
|
// CHECK: define i64 @_Z4f4_0M2s4i(i64 %a)
|
Change X86_64ABIInfo to have ASTContext and TargetData ivars to
avoid passing ASTContext down through all the methods it has.
When classifying an argument, or argument piece, as INTEGER, check
to see if we have a pointer at exactly the same offset in the
preferred type. If so, use that pointer type instead of i64. This
allows us to compile A function taking a stringref into something
like this:
define i8* @foo(i64 %D.coerce0, i8* %D.coerce1) nounwind ssp {
entry:
%D = alloca %struct.DeclGroup, align 8 ; <%struct.DeclGroup*> [#uses=4]
%0 = getelementptr %struct.DeclGroup* %D, i32 0, i32 0 ; <i64*> [#uses=1]
store i64 %D.coerce0, i64* %0
%1 = getelementptr %struct.DeclGroup* %D, i32 0, i32 1 ; <i8**> [#uses=1]
store i8* %D.coerce1, i8** %1
%tmp = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 0 ; <i64*> [#uses=1]
%tmp1 = load i64* %tmp ; <i64> [#uses=1]
%tmp2 = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 1 ; <i8**> [#uses=1]
%tmp3 = load i8** %tmp2 ; <i8*> [#uses=1]
%add.ptr = getelementptr inbounds i8* %tmp3, i64 %tmp1 ; <i8*> [#uses=1]
ret i8* %add.ptr
}
instead of this:
define i8* @foo(i64 %D.coerce0, i64 %D.coerce1) nounwind ssp {
entry:
%D = alloca %struct.DeclGroup, align 8 ; <%struct.DeclGroup*> [#uses=3]
%0 = insertvalue %0 undef, i64 %D.coerce0, 0 ; <%0> [#uses=1]
%1 = insertvalue %0 %0, i64 %D.coerce1, 1 ; <%0> [#uses=1]
%2 = bitcast %struct.DeclGroup* %D to %0* ; <%0*> [#uses=1]
store %0 %1, %0* %2, align 1
%tmp = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 0 ; <i64*> [#uses=1]
%tmp1 = load i64* %tmp ; <i64> [#uses=1]
%tmp2 = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 1 ; <i8**> [#uses=1]
%tmp3 = load i8** %tmp2 ; <i8*> [#uses=1]
%add.ptr = getelementptr inbounds i8* %tmp3, i64 %tmp1 ; <i8*> [#uses=1]
ret i8* %add.ptr
}
This implements rdar://7375902 - [codegen quality] clang x86-64 ABI lowering code punishing StringRef
llvm-svn: 107123
2010-06-29 14:01:59 +08:00
|
|
|
// CHECK: define {{.*}} @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1)
|
2010-05-15 08:00:37 +08:00
|
|
|
struct s4 {};
|
|
|
|
typedef int s4::* s4_mdp;
|
|
|
|
typedef int (s4::*s4_mfp)();
|
|
|
|
s4_mdp f4_0(s4_mdp a) { return a; }
|
|
|
|
s4_mfp f4_1(s4_mfp a) { return a; }
|
2010-07-01 03:14:05 +08:00
|
|
|
|
|
|
|
|
|
|
|
namespace PR7523 {
|
|
|
|
struct StringRef {
|
|
|
|
char *a;
|
|
|
|
};
|
|
|
|
|
|
|
|
void AddKeyword(StringRef, int x);
|
|
|
|
|
|
|
|
void foo() {
|
|
|
|
// CHECK: define void @_ZN6PR75233fooEv()
|
|
|
|
// CHECK: call void @_ZN6PR752310AddKeywordENS_9StringRefEi(i8* {{.*}}, i32 4)
|
|
|
|
AddKeyword(StringRef(), 4);
|
|
|
|
}
|
2010-07-30 01:04:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace PR7742 { // Also rdar://8250764
|
|
|
|
struct s2 {
|
|
|
|
float a[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct c2 : public s2 {};
|
|
|
|
|
2011-04-18 05:56:13 +08:00
|
|
|
// CHECK: define <2 x float> @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P)
|
2010-07-30 01:04:54 +08:00
|
|
|
c2 foo(c2 *P) {
|
2012-05-03 09:34:46 +08:00
|
|
|
return c2();
|
2010-07-30 01:04:54 +08:00
|
|
|
}
|
|
|
|
|
2010-07-30 12:02:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace PR5179 {
|
|
|
|
struct B {};
|
|
|
|
|
|
|
|
struct B1 : B {
|
|
|
|
int* pa;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct B2 : B {
|
|
|
|
B1 b1;
|
|
|
|
};
|
|
|
|
|
|
|
|
// CHECK: define i8* @_ZN6PR51793barENS_2B2E(i32* %b2.coerce)
|
|
|
|
const void *bar(B2 b2) {
|
|
|
|
return b2.b1.pa;
|
|
|
|
}
|
|
|
|
}
|
2010-08-23 13:26:13 +08:00
|
|
|
|
|
|
|
namespace test5 {
|
|
|
|
struct Xbase { };
|
|
|
|
struct Empty { };
|
|
|
|
struct Y;
|
|
|
|
struct X : public Xbase {
|
|
|
|
Empty empty;
|
|
|
|
Y f();
|
|
|
|
};
|
|
|
|
struct Y : public X {
|
|
|
|
Empty empty;
|
|
|
|
};
|
|
|
|
X getX();
|
|
|
|
int takeY(const Y&, int y);
|
|
|
|
void g() {
|
|
|
|
// rdar://8340348 - The temporary for the X object needs to have a defined
|
|
|
|
// address when passed into X::f as 'this'.
|
|
|
|
takeY(getX().f(), 42);
|
|
|
|
}
|
|
|
|
// CHECK: void @_ZN5test51gEv()
|
|
|
|
// CHECK: alloca %"struct.test5::Y"
|
|
|
|
// CHECK: alloca %"struct.test5::X"
|
|
|
|
// CHECK: alloca %"struct.test5::Y"
|
|
|
|
}
|
2010-09-01 08:50:20 +08:00
|
|
|
|
|
|
|
|
|
|
|
// rdar://8360877
|
|
|
|
namespace test6 {
|
|
|
|
struct outer {
|
|
|
|
int x;
|
|
|
|
struct epsilon_matcher {} e;
|
|
|
|
int f;
|
|
|
|
};
|
|
|
|
|
|
|
|
int test(outer x) {
|
|
|
|
return x.x + x.f;
|
|
|
|
}
|
|
|
|
// CHECK: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1)
|
|
|
|
}
|
2011-06-29 15:04:55 +08:00
|
|
|
|
|
|
|
namespace test7 {
|
|
|
|
struct StringRef {char* ptr; long len; };
|
|
|
|
class A { public: ~A(); };
|
|
|
|
A x(A, A, long, long, StringRef) { return A(); }
|
|
|
|
// Check that the StringRef is passed byval instead of expanded
|
|
|
|
// (which would split it between registers and memory).
|
|
|
|
// rdar://problem/9686430
|
2013-02-15 13:25:49 +08:00
|
|
|
// CHECK: define void @_ZN5test71xENS_1AES0_llNS_9StringRefE({{.*}} byval align 8)
|
2011-06-29 15:04:55 +08:00
|
|
|
|
|
|
|
// And a couple extra related tests:
|
|
|
|
A y(A, long double, long, long, StringRef) { return A(); }
|
|
|
|
// CHECK: define void @_ZN5test71yENS_1AEellNS_9StringRefE({{.*}} i8*
|
|
|
|
struct StringDouble {char * ptr; double d;};
|
|
|
|
A z(A, A, A, A, A, StringDouble) { return A(); }
|
|
|
|
A zz(A, A, A, A, StringDouble) { return A(); }
|
2013-02-15 13:25:49 +08:00
|
|
|
// CHECK: define void @_ZN5test71zENS_1AES0_S0_S0_S0_NS_12StringDoubleE({{.*}} byval align 8)
|
2011-06-29 15:04:55 +08:00
|
|
|
// CHECK: define void @_ZN5test72zzENS_1AES0_S0_S0_NS_12StringDoubleE({{.*}} i8*
|
|
|
|
}
|
2011-07-14 05:58:55 +08:00
|
|
|
|
|
|
|
namespace test8 {
|
2013-02-15 13:25:49 +08:00
|
|
|
// CHECK: declare void @_ZN5test83fooENS_1BE(%"class.test8::B"* byval align 8)
|
2011-07-14 05:58:55 +08:00
|
|
|
class A {
|
|
|
|
char big[17];
|
|
|
|
};
|
|
|
|
|
|
|
|
class B : public A {};
|
|
|
|
|
|
|
|
void foo(B b);
|
|
|
|
void bar() {
|
|
|
|
B b;
|
|
|
|
foo(b);
|
|
|
|
}
|
|
|
|
}
|
2012-05-03 09:34:46 +08:00
|
|
|
|
|
|
|
// PR4242
|
|
|
|
namespace test9 {
|
|
|
|
// Large enough to be passed indirectly.
|
|
|
|
struct S { void *data[3]; };
|
|
|
|
|
|
|
|
struct T { void *data[2]; };
|
|
|
|
|
|
|
|
// CHECK: define void @_ZN5test93fooEPNS_1SEPNS_1TE([[S:%.*]]*, [[T:%.*]]*)
|
|
|
|
void foo(S*, T*) {}
|
|
|
|
|
2013-02-15 13:25:49 +08:00
|
|
|
// CHECK: define void @_ZN5test91aEiiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32, i32, i32, i32, [[T]]* byval align 8, i8*)
|
2012-05-03 09:34:46 +08:00
|
|
|
S a(int, int, int, int, T, void*) {
|
|
|
|
return S();
|
|
|
|
}
|
|
|
|
|
2013-02-15 13:25:49 +08:00
|
|
|
// CHECK: define [[S]]* @_ZN5test91bEPNS_1SEiiiiNS_1TEPv([[S]]* {{%.*}}, i32, i32, i32, i32, [[T:%.*]]* byval align 8, i8*)
|
2012-05-03 09:34:46 +08:00
|
|
|
S* b(S* sret, int, int, int, int, T, void*) {
|
|
|
|
return sret;
|
|
|
|
}
|
|
|
|
|
2013-02-01 07:17:12 +08:00
|
|
|
// CHECK: define void @_ZN5test91cEiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32, i32, i32, i8* {{%.*}}, i8* {{%.*}}, i8*)
|
2012-05-03 09:34:46 +08:00
|
|
|
S c(int, int, int, T, void*) {
|
|
|
|
return S();
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: define [[S]]* @_ZN5test91dEPNS_1SEiiiNS_1TEPv([[S]]* {{%.*}}, i32, i32, i32, i8* {{%.*}}, i8* {{%.*}}, i8*)
|
|
|
|
S* d(S* sret, int, int, int, T, void*) {
|
|
|
|
return sret;
|
|
|
|
}
|
|
|
|
}
|