diff options
author | Daniel Dunbar <daniel@zuster.org> | 2009-04-01 07:45:00 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2009-04-01 07:45:00 +0000 |
commit | cf6bde343ff5653744ca782e04d5a9c54b260042 (patch) | |
tree | 0299731a139cedf7dea1e3721eba404371cf3e69 /lib/CodeGen/CGCall.cpp | |
parent | dfc6b80ee13a9102cd67e0b2398fa999eebcbf8e (diff) |
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
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68197 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGCall.cpp')
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 945d52faa3..4db36d9140 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -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 { |