|
@@ -3156,7 +3156,8 @@ namespace {
|
|
class MipsABIInfo : public ABIInfo {
|
|
class MipsABIInfo : public ABIInfo {
|
|
bool IsO32;
|
|
bool IsO32;
|
|
unsigned MinABIStackAlignInBytes;
|
|
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* returnAggregateInRegs(QualType RetTy, uint64_t Size) const;
|
|
llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const;
|
|
llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const;
|
|
public:
|
|
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
|
|
// In N32/64, an aligned double precision floating point field is passed in
|
|
// a register.
|
|
// a register.
|
|
-llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty) const {
|
|
|
|
|
|
+llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const {
|
|
if (IsO32)
|
|
if (IsO32)
|
|
- return 0;
|
|
|
|
|
|
+ return CoerceToIntArgs(TySize);
|
|
|
|
|
|
if (Ty->isComplexType())
|
|
if (Ty->isComplexType())
|
|
return CGT.ConvertType(Ty);
|
|
return CGT.ConvertType(Ty);
|
|
@@ -3203,12 +3222,11 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty) const {
|
|
|
|
|
|
// Unions are passed in integer registers.
|
|
// Unions are passed in integer registers.
|
|
if (!RT || !RT->isStructureOrClassType())
|
|
if (!RT || !RT->isStructureOrClassType())
|
|
- return 0;
|
|
|
|
|
|
+ return CoerceToIntArgs(TySize);
|
|
|
|
|
|
const RecordDecl *RD = RT->getDecl();
|
|
const RecordDecl *RD = RT->getDecl();
|
|
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
|
|
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;
|
|
uint64_t LastOffset = 0;
|
|
unsigned idx = 0;
|
|
unsigned idx = 0;
|
|
@@ -3238,17 +3256,13 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty) const {
|
|
LastOffset = Offset + 64;
|
|
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);
|
|
ArgList.push_back(I64);
|
|
|
|
|
|
// If the size of the remainder is not zero, add one more integer type to
|
|
// If the size of the remainder is not zero, add one more integer type to
|
|
// ArgList.
|
|
// ArgList.
|
|
- unsigned R = (StructSize - LastOffset) % 64;
|
|
|
|
|
|
+ unsigned R = (TySize - LastOffset) % 64;
|
|
if (R)
|
|
if (R)
|
|
ArgList.push_back(llvm::IntegerType::get(getVMContext(), 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 {
|
|
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
|
|
ABIArgInfo
|
|
MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
|
|
MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
|
|
uint64_t OrigOffset = Offset;
|
|
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;
|
|
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)) {
|
|
if (isAggregateTypeForABI(Ty)) {
|
|
// Ignore empty aggregates.
|
|
// 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
|
|
// Records with non trivial destructors/constructors should not be passed
|
|
// by value.
|
|
// by value.
|
|
if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) {
|
|
if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) {
|
|
- Offset = OrigOffset + 8;
|
|
|
|
|
|
+ Offset = OrigOffset + MinABIStackAlignInBytes;
|
|
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
|
|
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.
|
|
// Treat an enum type as its underlying type.
|
|
@@ -3385,7 +3394,7 @@ void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
|
RetInfo = classifyReturnType(FI.getReturnType());
|
|
RetInfo = classifyReturnType(FI.getReturnType());
|
|
|
|
|
|
// Check if a pointer to an aggregate is passed as a hidden argument.
|
|
// 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();
|
|
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
|
|
it != ie; ++it)
|
|
it != ie; ++it)
|