forked from OSchip/llvm-project
[ARM] Fix AAPCS-VFP non-compliance when returning HFA from variadic functions.
Arguments and return values must always be marshalled as for the base AAPCS when the callee is a variadic function. Patch by Oliver Stannard! llvm-svn: 200307
This commit is contained in:
parent
4162034bb5
commit
9dc7878ac5
|
@ -3099,10 +3099,10 @@ public:
|
||||||
ABIKind getABIKind() const { return Kind; }
|
ABIKind getABIKind() const { return Kind; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ABIArgInfo classifyReturnType(QualType RetTy) const;
|
ABIArgInfo classifyReturnType(QualType RetTy, bool isVariadic) const;
|
||||||
ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs,
|
ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs,
|
||||||
unsigned &AllocatedVFP,
|
unsigned &AllocatedVFP,
|
||||||
bool &IsHA) const;
|
bool &IsHA, bool isVariadic) const;
|
||||||
bool isIllegalVectorType(QualType Ty) const;
|
bool isIllegalVectorType(QualType Ty) const;
|
||||||
|
|
||||||
virtual void computeInfo(CGFunctionInfo &FI) const;
|
virtual void computeInfo(CGFunctionInfo &FI) const;
|
||||||
|
@ -3198,7 +3198,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
||||||
// unallocated are marked as unavailable.
|
// unallocated are marked as unavailable.
|
||||||
unsigned AllocatedVFP = 0;
|
unsigned AllocatedVFP = 0;
|
||||||
int VFPRegs[16] = { 0 };
|
int VFPRegs[16] = { 0 };
|
||||||
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
|
FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic());
|
||||||
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
|
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
|
||||||
it != ie; ++it) {
|
it != ie; ++it) {
|
||||||
unsigned PreAllocation = AllocatedVFP;
|
unsigned PreAllocation = AllocatedVFP;
|
||||||
|
@ -3206,10 +3206,12 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
||||||
// 6.1.2.3 There is one VFP co-processor register class using registers
|
// 6.1.2.3 There is one VFP co-processor register class using registers
|
||||||
// s0-s15 (d0-d7) for passing arguments.
|
// s0-s15 (d0-d7) for passing arguments.
|
||||||
const unsigned NumVFPs = 16;
|
const unsigned NumVFPs = 16;
|
||||||
it->info = classifyArgumentType(it->type, VFPRegs, AllocatedVFP, IsHA);
|
it->info = classifyArgumentType(it->type, VFPRegs, AllocatedVFP, IsHA, FI.isVariadic());
|
||||||
// If we do not have enough VFP registers for the HA, any VFP registers
|
// If we do not have enough VFP registers for the HA, any VFP registers
|
||||||
// that are unallocated are marked as unavailable. To achieve this, we add
|
// that are unallocated are marked as unavailable. To achieve this, we add
|
||||||
// padding of (NumVFPs - PreAllocation) floats.
|
// padding of (NumVFPs - PreAllocation) floats.
|
||||||
|
// Note that IsHA will only be set when using the AAPCS-VFP calling convention,
|
||||||
|
// and the callee is not variadic.
|
||||||
if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) {
|
if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) {
|
||||||
llvm::Type *PaddingTy = llvm::ArrayType::get(
|
llvm::Type *PaddingTy = llvm::ArrayType::get(
|
||||||
llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation);
|
llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation);
|
||||||
|
@ -3360,7 +3362,7 @@ static void markAllocatedVFPs(int *VFPRegs, unsigned &AllocatedVFP,
|
||||||
|
|
||||||
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
|
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
|
||||||
unsigned &AllocatedVFP,
|
unsigned &AllocatedVFP,
|
||||||
bool &IsHA) const {
|
bool &IsHA, bool isVariadic) const {
|
||||||
// We update number of allocated VFPs according to
|
// We update number of allocated VFPs according to
|
||||||
// 6.1.2.1 The following argument types are VFP CPRCs:
|
// 6.1.2.1 The following argument types are VFP CPRCs:
|
||||||
// A single-precision floating-point type (including promoted
|
// A single-precision floating-point type (including promoted
|
||||||
|
@ -3424,7 +3426,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
|
||||||
if (isEmptyRecord(getContext(), Ty, true))
|
if (isEmptyRecord(getContext(), Ty, true))
|
||||||
return ABIArgInfo::getIgnore();
|
return ABIArgInfo::getIgnore();
|
||||||
|
|
||||||
if (getABIKind() == ARMABIInfo::AAPCS_VFP) {
|
if (getABIKind() == ARMABIInfo::AAPCS_VFP && !isVariadic) {
|
||||||
// Homogeneous Aggregates need to be expanded when we can fit the aggregate
|
// Homogeneous Aggregates need to be expanded when we can fit the aggregate
|
||||||
// into VFP registers.
|
// into VFP registers.
|
||||||
const Type *Base = 0;
|
const Type *Base = 0;
|
||||||
|
@ -3566,7 +3568,7 @@ static bool isIntegerLikeType(QualType Ty, ASTContext &Context,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
|
ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic) const {
|
||||||
if (RetTy->isVoidType())
|
if (RetTy->isVoidType())
|
||||||
return ABIArgInfo::getIgnore();
|
return ABIArgInfo::getIgnore();
|
||||||
|
|
||||||
|
@ -3622,7 +3624,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
|
||||||
return ABIArgInfo::getIgnore();
|
return ABIArgInfo::getIgnore();
|
||||||
|
|
||||||
// Check for homogeneous aggregates with AAPCS-VFP.
|
// Check for homogeneous aggregates with AAPCS-VFP.
|
||||||
if (getABIKind() == AAPCS_VFP) {
|
if (getABIKind() == AAPCS_VFP && !isVariadic) {
|
||||||
const Type *Base = 0;
|
const Type *Base = 0;
|
||||||
if (isHomogeneousAggregate(RetTy, Base, getContext())) {
|
if (isHomogeneousAggregate(RetTy, Base, getContext())) {
|
||||||
assert(Base && "Base class should be set for homogeneous aggregate");
|
assert(Base && "Base class should be set for homogeneous aggregate");
|
||||||
|
|
|
@ -25,6 +25,11 @@ struct homogeneous_struct test_struct(struct homogeneous_struct arg) {
|
||||||
return struct_callee(arg);
|
return struct_callee(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: define arm_aapcs_vfpcc void @test_struct_variadic(%struct.homogeneous_struct* {{.*}}, [4 x i32] %{{.*}}, ...)
|
||||||
|
struct homogeneous_struct test_struct_variadic(struct homogeneous_struct arg, ...) {
|
||||||
|
return struct_callee(arg);
|
||||||
|
}
|
||||||
|
|
||||||
struct nested_array {
|
struct nested_array {
|
||||||
double d[4];
|
double d[4];
|
||||||
};
|
};
|
||||||
|
|
|
@ -173,6 +173,14 @@ void test_struct_of_four_doubles(void) {
|
||||||
takes_struct_of_four_doubles(3.0, g_s4d, g_s4d, 4.0);
|
takes_struct_of_four_doubles(3.0, g_s4d, g_s4d, 4.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void takes_struct_of_four_doubles_variadic(double a, struct_of_four_doubles b, struct_of_four_doubles c, double d, ...);
|
||||||
|
|
||||||
|
void test_struct_of_four_doubles_variadic(void) {
|
||||||
|
// CHECK: test_struct_of_four_doubles_variadic
|
||||||
|
// CHECK: call arm_aapcs_vfpcc void (double, [4 x i64], [4 x i64], double, ...)* @takes_struct_of_four_doubles_variadic(double {{.*}}, [4 x i64] {{.*}}, [4 x i64] {{.*}}, double {{.*}})
|
||||||
|
takes_struct_of_four_doubles_variadic(3.0, g_s4d, g_s4d, 4.0);
|
||||||
|
}
|
||||||
|
|
||||||
extern void takes_struct_with_backfill(float f1, double a, float f2, struct_of_four_doubles b, struct_of_four_doubles c, double d);
|
extern void takes_struct_with_backfill(float f1, double a, float f2, struct_of_four_doubles b, struct_of_four_doubles c, double d);
|
||||||
void test_struct_with_backfill(void) {
|
void test_struct_with_backfill(void) {
|
||||||
// CHECK: test_struct_with_backfill
|
// CHECK: test_struct_with_backfill
|
||||||
|
|
Loading…
Reference in New Issue