diff options
Diffstat (limited to 'lib/CodeGen/TargetInfo.cpp')
-rw-r--r-- | lib/CodeGen/TargetInfo.cpp | 79 |
1 files changed, 44 insertions, 35 deletions
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<llvm::Type*, 8> 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) |