From: Chris Lattner Date: Wed, 28 Jul 2010 23:06:14 +0000 (+0000) Subject: use Get8ByteTypeAtOffset for the return value path as well so we X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=519f68cd26777c755763a644a7f7ed7ac389beb9;p=clang use Get8ByteTypeAtOffset for the return value path as well so we don't get errors similar to PR7714 on the return path. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109689 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 0df657070f..4bc37775b8 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -1198,6 +1198,62 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const { return ABIArgInfo::getIndirect(0); } +/// Get8ByteTypeAtOffset - The ABI specifies that a value should be passed in an +/// 8-byte GPR. This means that we either have a scalar or we are talking about +/// the high or low part of an up-to-16-byte struct. This routine picks the +/// best LLVM IR type to represent this, which may be i64 or may be anything +/// else that the backend will pass in a GPR that works better (e.g. i8, %foo*, +/// etc). +/// +/// PrefType is an LLVM IR type that corresponds to (part of) the IR type for +/// the source type. IROffset is an offset in bytes into the LLVM IR type that +/// the 8-byte value references. PrefType may be null. +/// +/// SourceTy is the source level type for the entire argument. SourceOffset is +/// an offset into this that we're processing (which is always either 0 or 8). +/// +static const llvm::Type *Get8ByteTypeAtOffset(const llvm::Type *PrefType, + unsigned IROffset, + QualType SourceTy, + unsigned SourceOffset, + const llvm::TargetData &TD, + llvm::LLVMContext &VMContext, + ASTContext &Context) { + // Pointers are always 8-bytes at offset 0. + if (IROffset == 0 && PrefType && isa(PrefType)) + return PrefType; + + // TODO: 1/2/4/8 byte integers are also interesting, but we have to know that + // the "hole" is not used in the containing struct (just undef padding). + + if (const llvm::StructType *STy = + dyn_cast_or_null(PrefType)) { + // If this is a struct, recurse into the field at the specified offset. + const llvm::StructLayout *SL = TD.getStructLayout(STy); + if (IROffset < SL->getSizeInBytes()) { + unsigned FieldIdx = SL->getElementContainingOffset(IROffset); + IROffset -= SL->getElementOffset(FieldIdx); + + return Get8ByteTypeAtOffset(STy->getElementType(FieldIdx), IROffset, + SourceTy, SourceOffset, TD,VMContext,Context); + } + } + + // Okay, we don't have any better idea of what to pass, so we pass this in an + // integer register that isn't too big to fit the rest of the struct. + uint64_t TySizeInBytes = Context.getTypeSizeInChars(SourceTy).getQuantity(); + + // It is always safe to classify this as an integer type up to i64 that + // isn't larger than the structure. + switch (unsigned(TySizeInBytes-SourceOffset)) { + case 1: return llvm::Type::getInt8Ty(VMContext); + case 2: return llvm::Type::getInt16Ty(VMContext); + case 3: + case 4: return llvm::Type::getInt32Ty(VMContext); + default: return llvm::Type::getInt64Ty(VMContext); + } +} + ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the @@ -1227,7 +1283,8 @@ classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next // available register of the sequence %rax, %rdx is used. case Integer: - ResType = llvm::Type::getInt64Ty(VMContext); break; + ResType = Get8ByteTypeAtOffset(0, 0, RetTy, 0, TD, VMContext, Context); + break; // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next // available SSE register of the sequence %xmm0, %xmm1 is used. @@ -1261,10 +1318,12 @@ classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { case ComplexX87: // Previously handled. case NoClass: break; - case Integer: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getInt64Ty(VMContext), NULL); + case Integer: { + const llvm::Type *HiType = + Get8ByteTypeAtOffset(0, 8, RetTy, 8, TD, VMContext, Context); + ResType = llvm::StructType::get(VMContext, ResType, HiType, NULL); break; + } case SSE: ResType = llvm::StructType::get(VMContext, ResType, llvm::Type::getDoubleTy(VMContext), NULL); @@ -1295,62 +1354,6 @@ classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { return getCoerceResult(RetTy, ResType); } -/// Get8ByteTypeAtOffset - The ABI specifies that a value should be passed in an -/// 8-byte GPR. This means that we either have a scalar or we are talking about -/// the high or low part of an up-to-16-byte struct. This routine picks the -/// best LLVM IR type to represent this, which may be i64 or may be anything -/// else that the backend will pass in a GPR that works better (e.g. i8, %foo*, -/// etc). -/// -/// PrefType is an LLVM IR type that corresponds to (part of) the IR type for -/// the source type. IROffset is an offset in bytes into the LLVM IR type that -/// the 8-byte value references. PrefType may be null. -/// -/// SourceTy is the source level type for the entire argument. SourceOffset is -/// an offset into this that we're processing (which is always either 0 or 8). -/// -static const llvm::Type *Get8ByteTypeAtOffset(const llvm::Type *PrefType, - unsigned IROffset, - QualType SourceTy, - unsigned SourceOffset, - const llvm::TargetData &TD, - llvm::LLVMContext &VMContext, - ASTContext &Context) { - // Pointers are always 8-bytes at offset 0. - if (IROffset == 0 && PrefType && isa(PrefType)) - return PrefType; - - // TODO: 1/2/4/8 byte integers are also interesting, but we have to know that - // the "hole" is not used in the containing struct (just undef padding). - - if (const llvm::StructType *STy = - dyn_cast_or_null(PrefType)) { - // If this is a struct, recurse into the field at the specified offset. - const llvm::StructLayout *SL = TD.getStructLayout(STy); - if (IROffset < SL->getSizeInBytes()) { - unsigned FieldIdx = SL->getElementContainingOffset(IROffset); - IROffset -= SL->getElementOffset(FieldIdx); - - return Get8ByteTypeAtOffset(STy->getElementType(FieldIdx), IROffset, - SourceTy, SourceOffset, TD,VMContext,Context); - } - } - - // Okay, we don't have any better idea of what to pass, so we pass this in an - // integer register that isn't too big to fit the rest of the struct. - uint64_t TySizeInBytes = Context.getTypeSizeInChars(SourceTy).getQuantity(); - - // It is always safe to classify this as an integer type up to i64 that - // isn't larger than the structure. - switch (unsigned(TySizeInBytes-SourceOffset)) { - case 1: return llvm::Type::getInt8Ty(VMContext); - case 2: return llvm::Type::getInt16Ty(VMContext); - case 3: - case 4: return llvm::Type::getInt32Ty(VMContext); - default: return llvm::Type::getInt64Ty(VMContext); - } -} - ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, llvm::LLVMContext &VMContext, unsigned &neededInt, diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c index 35a4754cb1..1b7967d0de 100644 --- a/test/CodeGen/x86_64-arguments.c +++ b/test/CodeGen/x86_64-arguments.c @@ -139,9 +139,16 @@ struct f23S { int f2; }; + void f23(int A, struct f23S B) { // CHECK: define void @f23(i32 %A, i64 %B.coerce0, i32 %B.coerce1) } +struct f24s { long a; int b; }; +struct f23S f24(struct f23S *X, struct f24s *P2) { + return *X; + + // CHECK: define %struct.f24s @f24(%struct.f23S* %X, %struct.f24s* %P2) +}