forked from OSchip/llvm-project
ARM/APCS: Only "integer like" aggregates should be returned in r0 (following
gcc's interpretation of APCS' somewhat loose specification). llvm-svn: 81671
This commit is contained in:
parent
299d76e901
commit
626f1d8c3a
|
@ -50,26 +50,29 @@ void ABIArgInfo::dump() const {
|
|||
fprintf(stderr, ")\n");
|
||||
}
|
||||
|
||||
static bool isEmptyRecord(ASTContext &Context, QualType T);
|
||||
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
|
||||
|
||||
/// isEmptyField - Return true iff a the field is "empty", that is it
|
||||
/// is an unnamed bit-field or an (array of) empty record(s).
|
||||
static bool isEmptyField(ASTContext &Context, const FieldDecl *FD) {
|
||||
static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
|
||||
bool AllowArrays) {
|
||||
if (FD->isUnnamedBitfield())
|
||||
return true;
|
||||
|
||||
QualType FT = FD->getType();
|
||||
// Constant arrays of empty records count as empty, strip them off.
|
||||
while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
|
||||
FT = AT->getElementType();
|
||||
|
||||
return isEmptyRecord(Context, FT);
|
||||
// Constant arrays of empty records count as empty, strip them off.
|
||||
if (AllowArrays)
|
||||
while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
|
||||
FT = AT->getElementType();
|
||||
|
||||
return isEmptyRecord(Context, FT, AllowArrays);
|
||||
}
|
||||
|
||||
/// isEmptyRecord - Return true iff a structure contains only empty
|
||||
/// fields. Note that a structure with a flexible array member is not
|
||||
/// considered empty.
|
||||
static bool isEmptyRecord(ASTContext &Context, QualType T) {
|
||||
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
|
||||
const RecordType *RT = T->getAs<RecordType>();
|
||||
if (!RT)
|
||||
return 0;
|
||||
|
@ -78,7 +81,7 @@ static bool isEmptyRecord(ASTContext &Context, QualType T) {
|
|||
return false;
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i)
|
||||
if (!isEmptyField(Context, *i))
|
||||
if (!isEmptyField(Context, *i, AllowArrays))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -107,7 +110,7 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
|
|||
QualType FT = FD->getType();
|
||||
|
||||
// Ignore empty fields.
|
||||
if (isEmptyField(Context, FD))
|
||||
if (isEmptyField(Context, FD, true))
|
||||
continue;
|
||||
|
||||
// If we already found an element then this isn't a single-element
|
||||
|
@ -286,7 +289,7 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
|
|||
const FieldDecl *FD = *i;
|
||||
|
||||
// Empty fields are ignored.
|
||||
if (isEmptyField(Context, FD))
|
||||
if (isEmptyField(Context, FD, true))
|
||||
continue;
|
||||
|
||||
// Check fields recursively.
|
||||
|
@ -1388,10 +1391,10 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
|
|||
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
|
||||
ASTContext &Context,
|
||||
llvm::LLVMContext &VMContext) const {
|
||||
if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
|
||||
if (!CodeGenFunction::hasAggregateLLVMType(Ty))
|
||||
return (Ty->isPromotableIntegerType() ?
|
||||
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
|
||||
}
|
||||
|
||||
// FIXME: This is kind of nasty... but there isn't much choice because the ARM
|
||||
// backend doesn't support byval.
|
||||
// FIXME: This doesn't handle alignment > 64 bits.
|
||||
|
@ -1410,22 +1413,126 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
|
|||
return ABIArgInfo::getCoerce(STy);
|
||||
}
|
||||
|
||||
static bool isIntegerLikeType(QualType Ty,
|
||||
ASTContext &Context,
|
||||
llvm::LLVMContext &VMContext) {
|
||||
// APCS, C Language Calling Conventions, Non-Simple Return Values: A structure
|
||||
// is called integer-like if its size is less than or equal to one word, and
|
||||
// the offset of each of its addressable sub-fields is zero.
|
||||
|
||||
uint64_t Size = Context.getTypeSize(Ty);
|
||||
|
||||
// Check that the type fits in a word.
|
||||
if (Size > 32)
|
||||
return false;
|
||||
|
||||
// FIXME: Handle vector types!
|
||||
if (Ty->isVectorType())
|
||||
return false;
|
||||
|
||||
// If this is a builtin or pointer type then it is ok.
|
||||
if (Ty->getAsBuiltinType() || Ty->isPointerType())
|
||||
return true;
|
||||
|
||||
// Complex types "should" be ok by the definition above, but they are not.
|
||||
if (Ty->isAnyComplexType())
|
||||
return false;
|
||||
|
||||
// Single element and zero sized arrays should be allowed, by the definition
|
||||
// above, but they are not.
|
||||
|
||||
// Otherwise, it must be a record type.
|
||||
const RecordType *RT = Ty->getAs<RecordType>();
|
||||
if (!RT) return false;
|
||||
|
||||
// Ignore records with flexible arrays.
|
||||
const RecordDecl *RD = RT->getDecl();
|
||||
if (RD->hasFlexibleArrayMember())
|
||||
return false;
|
||||
|
||||
// Check that all sub-fields are at offset 0, and are themselves "integer
|
||||
// like".
|
||||
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
|
||||
|
||||
bool HadField = false;
|
||||
unsigned idx = 0;
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i, ++idx) {
|
||||
const FieldDecl *FD = *i;
|
||||
|
||||
// Check if this field is at offset 0.
|
||||
uint64_t Offset = Layout.getFieldOffset(idx);
|
||||
if (Offset != 0) {
|
||||
// Allow padding bit-fields, but only if they are all at the end of the
|
||||
// structure (despite the wording above, this matches gcc).
|
||||
if (FD->isBitField() &&
|
||||
!FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
|
||||
for (; i != e; ++i)
|
||||
if (!i->isBitField() ||
|
||||
i->getBitWidth()->EvaluateAsInt(Context).getZExtValue())
|
||||
return false;
|
||||
|
||||
// All remaining fields are padding, allow this.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isIntegerLikeType(FD->getType(), Context, VMContext))
|
||||
return false;
|
||||
|
||||
// Only allow at most one field in a structure. Again this doesn't match the
|
||||
// wording above, but follows gcc.
|
||||
if (!RD->isUnion()) {
|
||||
if (HadField)
|
||||
return false;
|
||||
|
||||
HadField = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
|
||||
ASTContext &Context,
|
||||
llvm::LLVMContext &VMContext) const {
|
||||
if (RetTy->isVoidType()) {
|
||||
if (RetTy->isVoidType())
|
||||
return ABIArgInfo::getIgnore();
|
||||
} else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
|
||||
// Aggregates <= 4 bytes are returned in r0; other aggregates
|
||||
// are returned indirectly.
|
||||
uint64_t Size = Context.getTypeSize(RetTy);
|
||||
if (Size <= 32)
|
||||
return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
|
||||
return ABIArgInfo::getIndirect(0);
|
||||
} else {
|
||||
|
||||
if (!CodeGenFunction::hasAggregateLLVMType(RetTy))
|
||||
return (RetTy->isPromotableIntegerType() ?
|
||||
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
|
||||
|
||||
// Are we following APCS?
|
||||
if (getABIKind() == APCS) {
|
||||
if (isEmptyRecord(Context, RetTy, false))
|
||||
return ABIArgInfo::getIgnore();
|
||||
|
||||
// Integer like structures are returned in r0.
|
||||
if (isIntegerLikeType(RetTy, Context, VMContext)) {
|
||||
// Return in the smallest viable integer type.
|
||||
uint64_t Size = Context.getTypeSize(RetTy);
|
||||
if (Size <= 8)
|
||||
return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
|
||||
if (Size <= 16)
|
||||
return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
|
||||
return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
|
||||
}
|
||||
|
||||
// Otherwise return in memory.
|
||||
return ABIArgInfo::getIndirect(0);
|
||||
}
|
||||
|
||||
// Otherwise this is an AAPCS variant.
|
||||
|
||||
// Aggregates <= 4 bytes are returned in r0; other aggregates
|
||||
// are returned indirectly.
|
||||
uint64_t Size = Context.getTypeSize(RetTy);
|
||||
if (Size <= 32)
|
||||
return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
|
||||
return ABIArgInfo::getIndirect(0);
|
||||
}
|
||||
|
||||
llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
||||
|
|
|
@ -1,6 +1,59 @@
|
|||
// RUN: clang-cc -triple armv7-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
|
||||
// RUX: iphone-llvm-gcc -arch armv7 -flto -S -o - %s | FileCheck %s
|
||||
// RUN: clang-cc -triple armv7-apple-darwin9 -emit-llvm -w -o - %s | FileCheck %s
|
||||
|
||||
// CHECK: define arm_apcscc signext i8 @f0()
|
||||
char f0(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// CHECK: define arm_apcscc i8 @f1()
|
||||
struct s1 { char f0; };
|
||||
struct s1 f1(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc i16 @f2()
|
||||
struct s2 { short f0; };
|
||||
struct s2 f2(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc i32 @f3()
|
||||
struct s3 { int f0; };
|
||||
struct s3 f3(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc i32 @f4()
|
||||
struct s4 { struct s4_0 { int f0; } f0; };
|
||||
struct s4 f4(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc void @f5(
|
||||
// CHECK: struct.s5* noalias sret
|
||||
struct s5 { struct { } f0; int f1; };
|
||||
struct s5 f5(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc void @f6(
|
||||
// CHECK: struct.s6* noalias sret
|
||||
struct s6 { int f0[1]; };
|
||||
struct s6 f6(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc void @f7()
|
||||
struct s7 { struct { int : 0; } f0; };
|
||||
struct s7 f7(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc void @f8(
|
||||
// CHECK: struct.s8* noalias sret
|
||||
struct s8 { struct { int : 0; } f0[1]; };
|
||||
struct s8 f8(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc i32 @f9()
|
||||
struct s9 { int f0; int : 0; };
|
||||
struct s9 f9(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc i32 @f10()
|
||||
struct s10 { int f0; int : 0; int : 0; };
|
||||
struct s10 f10(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc void @f11(
|
||||
// CHECK: struct.s10* noalias sret
|
||||
struct s11 { int : 0; int f0; };
|
||||
struct s11 f11(void) {}
|
||||
|
||||
// CHECK: define arm_apcscc i32 @f12()
|
||||
union u12 { char f0; short f1; int f2; };
|
||||
union u12 f12(void) {}
|
||||
|
|
Loading…
Reference in New Issue