forked from OSchip/llvm-project
x86-32 Darwin ABI: Handle small structures correctly.
- Small structures are returned in a register if: 1. They fit nicely in a register. 2. All fields fit nicely in a register. (more or less) - We now pass the first 5000 ABITests if unions are disabled. - <rdar://problem/6497882> [irgen] x86-32 ABI compatibility with small structs llvm-svn: 68197
This commit is contained in:
parent
58e2971bb0
commit
e80bd1897c
|
@ -262,6 +262,8 @@ class X86_32ABIInfo : public ABIInfo {
|
|||
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
|
||||
}
|
||||
|
||||
static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
|
||||
|
||||
public:
|
||||
ABIArgInfo classifyReturnType(QualType RetTy,
|
||||
ASTContext &Context) const;
|
||||
|
@ -283,6 +285,60 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
/// shouldReturnTypeInRegister - Determine if the given type should be
|
||||
/// passed in a register (for the Darwin ABI).
|
||||
bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
|
||||
ASTContext &Context) {
|
||||
uint64_t Size = Context.getTypeSize(Ty);
|
||||
|
||||
// Type must be register sized.
|
||||
if (!isRegisterSize(Size))
|
||||
return false;
|
||||
|
||||
if (Ty->isVectorType()) {
|
||||
// 64- and 128- bit vectors inside structures are not returned in
|
||||
// registers.
|
||||
if (Size == 64 || Size == 128)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this is a builtin, pointer, or complex type, it is ok.
|
||||
if (Ty->getAsBuiltinType() || Ty->isPointerType() || Ty->isAnyComplexType())
|
||||
return true;
|
||||
|
||||
// Arrays are treated like records.
|
||||
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
|
||||
return shouldReturnTypeInRegister(AT->getElementType(), Context);
|
||||
|
||||
// Otherwise, it must be a record type.
|
||||
const RecordType *RT = Ty->getAsRecordType();
|
||||
if (!RT) return false;
|
||||
|
||||
// Structure types are passed in register if all fields would be
|
||||
// passed in a register.
|
||||
for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
|
||||
e = RT->getDecl()->field_end(); i != e; ++i) {
|
||||
const FieldDecl *FD = *i;
|
||||
|
||||
// FIXME: Reject bitfields wholesale for now; this is incorrect.
|
||||
if (FD->isBitField())
|
||||
return false;
|
||||
|
||||
// Empty structures are ignored.
|
||||
if (isEmptyRecord(FD->getType()))
|
||||
continue;
|
||||
|
||||
// Check fields recursively.
|
||||
if (!shouldReturnTypeInRegister(FD->getType(), Context))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
|
||||
ASTContext &Context) const {
|
||||
if (RetTy->isVoidType()) {
|
||||
|
@ -345,8 +401,18 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
|
|||
}
|
||||
|
||||
uint64_t Size = Context.getTypeSize(RetTy);
|
||||
if (isRegisterSize(Size))
|
||||
return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
|
||||
if (isRegisterSize(Size)) {
|
||||
// Always return in register for unions for now.
|
||||
// FIXME: This is wrong, but better than treating as a
|
||||
// structure.
|
||||
if (RetTy->isUnionType())
|
||||
return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
|
||||
|
||||
// Small structures which are register sized are generally returned
|
||||
// in a register.
|
||||
if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context))
|
||||
return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
|
||||
}
|
||||
|
||||
return ABIArgInfo::getIndirect(0);
|
||||
} else {
|
||||
|
|
|
@ -9,11 +9,6 @@
|
|||
// RUN: grep 'define void @f7(i32 %a0)' %t &&
|
||||
// RUN: grep 'define i64 @f8_1()' %t &&
|
||||
// RUN: grep 'define void @f8_2(i32 %a0.0, i32 %a0.1)' %t &&
|
||||
// RUN: grep 'define i64 @f9_1()' %t &&
|
||||
|
||||
// FIXME: This is wrong, but we want the coverage of the other
|
||||
// tests. This should be the same as @f8_2.
|
||||
// RUN: grep 'define void @f9_2(%.truct.s9\* byval %a0)' %t &&
|
||||
|
||||
char f0(void) {
|
||||
}
|
||||
|
@ -52,8 +47,13 @@ void f8_2(struct s8 a0) {
|
|||
|
||||
// This should be passed just as s8.
|
||||
|
||||
// FIXME: This is currently broken, but the test case is accepting it
|
||||
// so we get coverage of the other cases.
|
||||
// FIXME: This is wrong, but we want the coverage of the other
|
||||
// tests. This should be the same as @f8_1.
|
||||
// RUN: grep 'define void @f9_1(%.truct.s9\* noalias sret %agg.result)' %t &&
|
||||
|
||||
// FIXME: This is wrong, but we want the coverage of the other
|
||||
// tests. This should be the same as @f8_2.
|
||||
// RUN: grep 'define void @f9_2(%.truct.s9\* byval %a0)' %t &&
|
||||
struct s9 {
|
||||
int a : 17;
|
||||
int b;
|
||||
|
@ -96,11 +96,11 @@ T16 f16(void) {}
|
|||
// 128-bits).
|
||||
|
||||
// RUN: grep 'i32 @f17()' %t &&
|
||||
// RUN: grep -F 'void @f18(%0* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f19(%1* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f20(%2* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f21(%3* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f22(%4* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f18(%3* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f19(%4* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f20(%5* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f21(%6* noalias sret %agg.result)' %t &&
|
||||
// RUN: grep -F 'void @f22(%7* noalias sret %agg.result)' %t &&
|
||||
struct { T11 a; } f17(void) {}
|
||||
struct { T12 a; } f18(void) {}
|
||||
struct { T13 a; } f19(void) {}
|
||||
|
@ -117,4 +117,10 @@ struct { float a; } f23(void) {}
|
|||
struct { float a[1]; } f24(void) {}
|
||||
struct { struct {} a; struct { float a[1]; } b; } f25(void) {}
|
||||
|
||||
// Small structures are handled recursively
|
||||
// RUN: grep -F 'i32 @f26()' %t &&
|
||||
// RUN: grep 'void @f27(%.truct.s27\* noalias sret %agg.result)' %t &&
|
||||
struct s26 { struct { char a, b; } a; struct { char a, b } b; } f26(void) {}
|
||||
struct s27 { struct { char a, b, c; } a; struct { char a } b; } f27(void) {}
|
||||
|
||||
// RUN: true
|
||||
|
|
Loading…
Reference in New Issue