Fix AAPCS compliance for HFAs containing doubles and long doubles

An HFA is defined as a struct containing floating point values of the
same machine type. In the 32-bit ABI, double and long double have the
same machine type, so a struct with a mixture of these types must be an
HFA (assuming it meets the other criteria).

llvm-svn: 200971
This commit is contained in:
Oliver Stannard 2014-02-07 11:25:57 +00:00
parent 1dc1034218
commit 5e8558fce0
3 changed files with 40 additions and 5 deletions

View File

@ -3415,10 +3415,29 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
const Type *TyPtr = Ty.getTypePtr();
if (!Base)
Base = TyPtr;
if (Base != TyPtr &&
(!Base->isVectorType() || !TyPtr->isVectorType() ||
Context.getTypeSize(Base) != Context.getTypeSize(TyPtr)))
return false;
if (Base != TyPtr) {
// Homogeneous aggregates are defined as containing members with the
// same machine type. There are two cases in which two members have
// different TypePtrs but the same machine type:
// 1) Vectors of the same length, regardless of the type and number
// of their members.
const bool SameLengthVectors = Base->isVectorType() && TyPtr->isVectorType()
&& (Context.getTypeSize(Base) == Context.getTypeSize(TyPtr));
// 2) In the 32-bit AAPCS, `double' and `long double' have the same
// machine type. This is not the case for the 64-bit AAPCS.
const bool SameSizeDoubles =
( ( Base->isSpecificBuiltinType(BuiltinType::Double)
&& TyPtr->isSpecificBuiltinType(BuiltinType::LongDouble))
|| ( Base->isSpecificBuiltinType(BuiltinType::LongDouble)
&& TyPtr->isSpecificBuiltinType(BuiltinType::Double)))
&& (Context.getTypeSize(Base) == Context.getTypeSize(TyPtr));
if (!SameLengthVectors && !SameSizeDoubles)
return false;
}
}
// Homogeneous Aggregates can have at most 4 members of the base type.

View File

@ -190,5 +190,10 @@ void f42(int x0, int x1, int x2, int x3, int x4, __int128 x6_7, __int128 stacked
void variadic(int a, ...);
void f43(__fp16 *in) {
variadic(42, *in);
// CHECK: call void @variadic(i32 42, double
// PCS: call void (i32, ...)* @variadic(i32 42, double
}
// Checking: `double' and `long double' have different machine types, so cannot both be in an HFA
struct s44 { long double a; double b; };
// PCS: define void @f44(%struct.s44*
struct s44 f44() {}

View File

@ -205,6 +205,17 @@ void test_struct_of_vecs(void) {
takes_struct_of_vecs(3.0, g_vec, g_vec, 4.0);
}
typedef struct {
double a;
long double b;
} struct_of_double_and_long_double;
struct_of_double_and_long_double g_dld;
struct_of_double_and_long_double test_struct_of_double_and_long_double(void) {
return g_dld;
}
// CHECK: define arm_aapcs_vfpcc %struct.struct_of_double_and_long_double @test_struct_of_double_and_long_double()
// FIXME: Tests necessary:
// - Vectors
// - C++ stuff