From 91338cf4129cfdb85af7e9ef396ab09621da10ec Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 11 May 2012 21:56:58 +0000 Subject: [PATCH] Coerce byval aggregate arguments to integers whose size matches the integer register size of the target architecture. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156650 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/TargetInfo.cpp | 79 ++++++++++++++++------------ test/CodeGen/mips-byval-arg.c | 15 ++++++ test/CodeGen/mips64-class-return.cpp | 2 +- 3 files changed, 60 insertions(+), 36 deletions(-) create mode 100644 test/CodeGen/mips-byval-arg.c diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 9016d8c93a..3ee6c785d6 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -3156,7 +3156,8 @@ namespace { class MipsABIInfo : public ABIInfo { bool IsO32; unsigned MinABIStackAlignInBytes; - llvm::Type* HandleAggregates(QualType Ty) const; + llvm::Type* CoerceToIntArgs(uint64_t TySize) const; + llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const; llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const; llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const; public: @@ -3190,11 +3191,29 @@ public: }; } +llvm::Type* MipsABIInfo::CoerceToIntArgs(uint64_t TySize) const { + SmallVector ArgList; + llvm::IntegerType *IntTy = llvm::IntegerType::get(getVMContext(), + MinABIStackAlignInBytes * 8); + + // Add (TySize / MinABIStackAlignInBytes) args of IntTy. + for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N) + ArgList.push_back(IntTy); + + // If necessary, add one more integer type to ArgList. + unsigned R = TySize % (MinABIStackAlignInBytes * 8); + + if (R) + ArgList.push_back(llvm::IntegerType::get(getVMContext(), R)); + + return llvm::StructType::get(getVMContext(), ArgList); +} + // In N32/64, an aligned double precision floating point field is passed in // a register. -llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty) const { +llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const { if (IsO32) - return 0; + return CoerceToIntArgs(TySize); if (Ty->isComplexType()) return CGT.ConvertType(Ty); @@ -3203,12 +3222,11 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty) const { // Unions are passed in integer registers. if (!RT || !RT->isStructureOrClassType()) - return 0; + return CoerceToIntArgs(TySize); const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); - uint64_t StructSize = getContext().getTypeSize(Ty); - assert(!(StructSize % 8) && "Size of structure must be multiple of 8."); + assert(!(TySize % 8) && "Size of structure must be multiple of 8."); uint64_t LastOffset = 0; unsigned idx = 0; @@ -3238,17 +3256,13 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty) const { LastOffset = Offset + 64; } - // This struct/class doesn't have an aligned double field. - if (!LastOffset) - return 0; - - // Add ((StructSize - LastOffset) / 64) args of type i64. - for (unsigned N = (StructSize - LastOffset) / 64; N; --N) + // Add ((TySize - LastOffset) / 64) args of type i64. + for (unsigned N = (TySize - LastOffset) / 64; N; --N) ArgList.push_back(I64); // If the size of the remainder is not zero, add one more integer type to // ArgList. - unsigned R = (StructSize - LastOffset) % 64; + unsigned R = (TySize - LastOffset) % 64; if (R) ArgList.push_back(llvm::IntegerType::get(getVMContext(), R)); @@ -3256,23 +3270,23 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty) const { } llvm::Type *MipsABIInfo::getPaddingType(uint64_t Align, uint64_t Offset) const { - // Padding is inserted only for N32/64. - if (IsO32) - return 0; + assert((Offset % MinABIStackAlignInBytes) == 0); + + if ((Align - 1) & Offset) + return llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8); - assert(Align <= 16 && "Alignment larger than 16 not handled."); - return (Align == 16 && Offset & 0xf) ? - llvm::IntegerType::get(getVMContext(), 64) : 0; + return 0; } ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { uint64_t OrigOffset = Offset; - uint64_t TySize = - llvm::RoundUpToAlignment(getContext().getTypeSize(Ty), 64) / 8; + uint64_t TySize = getContext().getTypeSize(Ty); uint64_t Align = getContext().getTypeAlign(Ty) / 8; - Offset = llvm::RoundUpToAlignment(Offset, std::max(Align, (uint64_t)8)); - Offset += TySize; + + Align = std::max(Align, (uint64_t)MinABIStackAlignInBytes); + Offset = llvm::RoundUpToAlignment(Offset, Align); + Offset += llvm::RoundUpToAlignment(TySize, Align * 8) / 8; if (isAggregateTypeForABI(Ty)) { // Ignore empty aggregates. @@ -3282,20 +3296,15 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { // Records with non trivial destructors/constructors should not be passed // by value. if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) { - Offset = OrigOffset + 8; + Offset = OrigOffset + MinABIStackAlignInBytes; return ABIArgInfo::getIndirect(0, /*ByVal=*/false); } - // If we have reached here, aggregates are passed either indirectly via a - // byval pointer or directly by coercing to another structure type. In the - // latter case, padding is inserted if the offset of the aggregate is - // unaligned. - llvm::Type *ResType = HandleAggregates(Ty); - - if (!ResType) - return ABIArgInfo::getIndirect(0); - - return ABIArgInfo::getDirect(ResType, 0, getPaddingType(Align, OrigOffset)); + // If we have reached here, aggregates are passed directly by coercing to + // another structure type. Padding is inserted if the offset of the + // aggregate is unaligned. + return ABIArgInfo::getDirect(HandleAggregates(Ty, TySize), 0, + getPaddingType(Align, OrigOffset)); } // Treat an enum type as its underlying type. @@ -3385,7 +3394,7 @@ void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const { RetInfo = classifyReturnType(FI.getReturnType()); // Check if a pointer to an aggregate is passed as a hidden argument. - uint64_t Offset = RetInfo.isIndirect() ? 8 : 0; + uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0; for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) diff --git a/test/CodeGen/mips-byval-arg.c b/test/CodeGen/mips-byval-arg.c new file mode 100644 index 0000000000..4e5f41a149 --- /dev/null +++ b/test/CodeGen/mips-byval-arg.c @@ -0,0 +1,15 @@ +// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -O3 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=O32 +// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s -check-prefix=N64 + +typedef struct { + float f[3]; +} S0; + +extern void foo2(S0); + +// O32: define void @foo1(i32 %a0.coerce0, i32 %a0.coerce1, i32 %a0.coerce2) +// N64: define void @foo1(i64 %a0.coerce0, i32 %a0.coerce1) + +void foo1(S0 a0) { + foo2(a0); +} diff --git a/test/CodeGen/mips64-class-return.cpp b/test/CodeGen/mips64-class-return.cpp index dc9ec0f5be..8e32d5cbd6 100644 --- a/test/CodeGen/mips64-class-return.cpp +++ b/test/CodeGen/mips64-class-return.cpp @@ -39,7 +39,7 @@ void foo3(D2 a0) { gd2 = a0; } -// CHECK: define void @_Z4foo42D0(%class.D0* nocapture byval %a0) +// CHECK: define void @_Z4foo42D0(i64 %a0.coerce0, i64 %a0.coerce1) void foo4(D0 a0) { gd0 = a0; } -- 2.40.0