From f0cc2087b18c48b17c2f647c88a3e7eef19285fd Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Sat, 7 Jan 2012 00:25:33 +0000 Subject: [PATCH] Add field PaddingType to ABIArgInfo which specifies the type of padding that is inserted before the real argument. Padding is needed to ensure the backend reads from or writes to the correct argument slots when the original alignment of a byval structure is unavailable due to flattening. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147699 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/ABIInfo.h | 21 +++++++++++++------ lib/CodeGen/CGCall.cpp | 16 +++++++++++++++ lib/CodeGen/TargetInfo.cpp | 34 ++++++++++++++++++++++--------- test/CodeGen/mips64-padding-arg.c | 19 +++++++++++++++++ 4 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 test/CodeGen/mips64-padding-arg.c 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(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(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()) 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); +} +