diff options
-rw-r--r-- | lib/CodeGen/ABIInfo.h | 21 | ||||
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 16 | ||||
-rw-r--r-- | lib/CodeGen/TargetInfo.cpp | 34 | ||||
-rw-r--r-- | test/CodeGen/mips64-padding-arg.c | 19 |
4 files changed, 74 insertions, 16 deletions
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index 138123816c..2853bc80a5 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -42,7 +42,8 @@ namespace clang { /// type, or by coercing to another specified type stored in /// 'CoerceToType'). If an offset is specified (in UIntData), then the /// argument passed is offset by some number of bytes in the memory - /// representation. + /// representation. A dummy argument is emitted before the real argument + /// if the specified type stored in "PaddingType" is not zero. Direct, /// Extend - Valid only for integer argument types. Same as 'direct' @@ -69,19 +70,22 @@ namespace clang { private: Kind TheKind; llvm::Type *TypeData; + llvm::Type *PaddingType; // Currently allowed only for Direct. unsigned UIntData; bool BoolData0; bool BoolData1; - ABIArgInfo(Kind K, llvm::Type *TD=0, - unsigned UI=0, bool B0 = false, bool B1 = false) - : TheKind(K), TypeData(TD), UIntData(UI), BoolData0(B0), BoolData1(B1) {} + ABIArgInfo(Kind K, llvm::Type *TD=0, unsigned UI=0, + bool B0 = false, bool B1 = false, llvm::Type* P = 0) + : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0), + BoolData1(B1) {} public: ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {} - static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0) { - return ABIArgInfo(Direct, T, Offset); + static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0, + llvm::Type *Padding = 0) { + return ABIArgInfo(Direct, T, Offset, false, false, Padding); } static ABIArgInfo getExtend(llvm::Type *T = 0) { return ABIArgInfo(Extend, T, 0); @@ -113,6 +117,11 @@ namespace clang { assert((isDirect() || isExtend()) && "Not a direct or extend kind"); return UIntData; } + + llvm::Type *getPaddingType() const { + return PaddingType; + } + llvm::Type *getCoerceToType() const { assert(canHaveCoerceToType() && "Invalid kind!"); return TypeData; diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 3457b5bc14..962339ab77 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -686,6 +686,9 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) { case ABIArgInfo::Extend: case ABIArgInfo::Direct: { + // Insert a padding type to ensure proper alignment. + if (llvm::Type *PaddingType = argAI.getPaddingType()) + argTypes.push_back(PaddingType); // If the coerce-to type is a first class aggregate, flatten it. Either // way is semantically identical, but fast-isel and the optimizer // generally likes scalar values better than FCAs. @@ -840,6 +843,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, } // FIXME: handle sseregparm someday... + // Increment Index if there is padding. + Index += (AI.getPaddingType() != 0); + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(AI.getCoerceToType())) Index += STy->getNumElements()-1; // 1 will be added below. @@ -1024,6 +1030,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::PointerType::getUnqual(ArgI.getCoerceToType())); } + // Skip the dummy padding argument. + if (ArgI.getPaddingType()) + ++AI; + // If the coerce-to type is a first class aggregate, we flatten it and // pass the elements. Either way is semantically identical, but fast-isel // and the optimizer generally likes scalar values better than FCAs. @@ -1658,6 +1668,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::Extend: case ABIArgInfo::Direct: { + // Insert a padding argument to ensure proper alignment. + if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) { + Args.push_back(llvm::UndefValue::get(PaddingType)); + ++IRArgNo; + } + if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) && ArgInfo.getCoerceToType() == ConvertType(info_it->type) && ArgInfo.getDirectOffset() == 0) { diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 0ce5957246..d1bebc1863 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -3047,7 +3047,7 @@ public: ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8) {} ABIArgInfo classifyReturnType(QualType RetTy) const; - ABIArgInfo classifyArgumentType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const; virtual void computeInfo(CGFunctionInfo &FI) const; virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const; @@ -3132,28 +3132,41 @@ llvm::Type* MipsABIInfo::HandleStructTy(QualType Ty) const { return llvm::StructType::get(getVMContext(), ArgList); } -ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const { +ABIArgInfo +MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { if (isAggregateTypeForABI(Ty)) { // Ignore empty aggregates. - if (getContext().getTypeSize(Ty) == 0) + uint64_t TySize = getContext().getTypeSize(Ty); + if (TySize == 0) return ABIArgInfo::getIgnore(); // Records with non trivial destructors/constructors should not be passed // by value. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) { + Offset += 8; return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + } - llvm::Type *ResType; - if ((ResType = HandleStructTy(Ty))) - return ABIArgInfo::getDirect(ResType); - - return ABIArgInfo::getIndirect(0); + // 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 = HandleStructTy(Ty); + uint64_t Align = getContext().getTypeAlign(Ty) / 8; + assert(Align <= 16 && "Alignment larger than 16 not handled."); + llvm::Type *PaddingTy = (ResType && Align == 16 && Offset & 0xf) ? + llvm::IntegerType::get(getVMContext(), 64) : 0; + Offset = llvm::RoundUpToAlignment(Offset, std::max(Align, (uint64_t)8)); + Offset += llvm::RoundUpToAlignment(TySize, 8); + return ResType ? ABIArgInfo::getDirect(ResType, 0, PaddingTy) : + ABIArgInfo::getIndirect(0); } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs<EnumType>()) Ty = EnumTy->getDecl()->getIntegerType(); + Offset += 8; return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } @@ -3230,9 +3243,10 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + uint64_t Offset = 0; for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentType(it->type); + it->info = classifyArgumentType(it->type, Offset); } llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, diff --git a/test/CodeGen/mips64-padding-arg.c b/test/CodeGen/mips64-padding-arg.c new file mode 100644 index 0000000000..658e6ebea0 --- /dev/null +++ b/test/CodeGen/mips64-padding-arg.c @@ -0,0 +1,19 @@ +// RUN: %clang -ccc-host-triple mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s + +typedef struct { + double d; + long double ld; +} S0; + +// Insert padding to ensure arugments of type S0 are aligned to 16-byte boundaries. + +// CHECK: define void @foo1(i32 %a0, i64, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 %b, i64, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3) +// CHECK: tail call void @foo2(i32 1, i32 2, i32 %a0, i64 undef, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 3, i64 undef, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3) +// CHECK: declare void @foo2(i32, i32, i32, i64, double, i64, i64, i64, double, i64, i64, i64, i32, i64, double, i64, i64, i64) + +extern void foo2(int, int, int, S0, S0, int, S0); + +void foo1(int a0, S0 a1, S0 a2, int b, S0 a3) { + foo2(1, 2, a0, a1, a2, 3, a3); +} + |