From fad28de40c545b053364528f1aa5864ab289e897 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 24 Oct 2012 01:59:00 +0000 Subject: [PATCH] Add padding inreg registers to cause llvm to skip ecx when needed with the x86_fastcallcc calling convention. llvm-svn: 166538 --- clang/lib/CodeGen/ABIInfo.h | 32 +++++++++++++------- clang/lib/CodeGen/CGCall.cpp | 42 +++++++++++++++++---------- clang/lib/CodeGen/TargetInfo.cpp | 21 +++++++++----- clang/test/CodeGen/stdcall-fastcall.c | 4 +-- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/clang/lib/CodeGen/ABIInfo.h b/clang/lib/CodeGen/ABIInfo.h index 1dd1d195c21e..da6d035dfaf0 100644 --- a/clang/lib/CodeGen/ABIInfo.h +++ b/clang/lib/CodeGen/ABIInfo.h @@ -70,46 +70,52 @@ namespace clang { private: Kind TheKind; llvm::Type *TypeData; - llvm::Type *PaddingType; // Currently allowed only for Direct. + llvm::Type *PaddingType; unsigned UIntData; bool BoolData0; bool BoolData1; bool InReg; + bool PaddingInReg; ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR, - llvm::Type* P) + bool PIR, llvm::Type* P) : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0), - BoolData1(B1), InReg(IR) {} + BoolData1(B1), InReg(IR), PaddingInReg(PIR) {} public: ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {} static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0, llvm::Type *Padding = 0) { - return ABIArgInfo(Direct, T, Offset, false, false, false, Padding); + return ABIArgInfo(Direct, T, Offset, false, false, false, false, Padding); } static ABIArgInfo getDirectInReg(llvm::Type *T = 0) { - return ABIArgInfo(Direct, T, 0, false, false, true, 0); + return ABIArgInfo(Direct, T, 0, false, false, true, false, 0); } static ABIArgInfo getExtend(llvm::Type *T = 0) { - return ABIArgInfo(Extend, T, 0, false, false, false, 0); + return ABIArgInfo(Extend, T, 0, false, false, false, false, 0); } static ABIArgInfo getExtendInReg(llvm::Type *T = 0) { - return ABIArgInfo(Extend, T, 0, false, false, true, 0); + return ABIArgInfo(Extend, T, 0, false, false, true, false, 0); } static ABIArgInfo getIgnore() { - return ABIArgInfo(Ignore, 0, 0, false, false, false, 0); + return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0); } static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true , bool Realign = false) { - return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, 0); + return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false, 0); } static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true , bool Realign = false) { - return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, 0); + return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0); } static ABIArgInfo getExpand() { - return ABIArgInfo(Expand, 0, 0, false, false, false, 0); + return ABIArgInfo(Expand, 0, 0, false, false, false, false, 0); + } + static ABIArgInfo getExpandWithPadding(bool PaddingInReg, + llvm::Type *Padding) { + return ABIArgInfo(Expand, 0, 0, false, false, false, PaddingInReg, + Padding); } Kind getKind() const { return TheKind; } @@ -133,6 +139,10 @@ namespace clang { return PaddingType; } + bool getPaddingInReg() const { + return PaddingInReg; + } + llvm::Type *getCoerceToType() const { assert(canHaveCoerceToType() && "Invalid kind!"); return TypeData; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index afcf541a3d39..b356e640a1c4 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -867,6 +867,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) { ie = FI.arg_end(); it != ie; ++it) { const ABIArgInfo &argAI = it->info; + // Insert a padding type to ensure proper alignment. + if (llvm::Type *PaddingType = argAI.getPaddingType()) + argTypes.push_back(PaddingType); + switch (argAI.getKind()) { case ABIArgInfo::Ignore: break; @@ -880,9 +884,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) { 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. @@ -1019,6 +1020,18 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const ABIArgInfo &AI = it->info; llvm::AttrBuilder Attrs; + if (AI.getPaddingType()) { + if (AI.getPaddingInReg()) { + llvm::AttrBuilder PadAttrs; + PadAttrs.addAttribute(llvm::Attributes::InReg); + + llvm::Attributes A =llvm::Attributes::get(getLLVMContext(), PadAttrs); + PAL.push_back(llvm::AttributeWithIndex::get(Index, A)); + } + // Increment Index if there is padding. + ++Index; + } + // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we // have the corresponding parameter variable. It doesn't make // sense to do it here because parameters are so messed up. @@ -1035,9 +1048,6 @@ 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())) { unsigned Extra = STy->getNumElements()-1; // 1 will be added below. @@ -1155,6 +1165,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, bool isPromoted = isa(Arg) && cast(Arg)->isKNRPromoted(); + // Skip the dummy padding argument. + if (ArgI.getPaddingType()) + ++AI; + switch (ArgI.getKind()) { case ABIArgInfo::Indirect: { llvm::Value *V = AI; @@ -1196,9 +1210,6 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, case ABIArgInfo::Extend: case ABIArgInfo::Direct: { - // Skip the dummy padding argument. - if (ArgI.getPaddingType()) - ++AI; // If we have the trivial case, handle it with no muss and fuss. if (!isa(ArgI.getCoerceToType()) && @@ -1976,6 +1987,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, unsigned TypeAlign = getContext().getTypeAlignInChars(I->Ty).getQuantity(); + + // Insert a padding argument to ensure proper alignment. + if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) { + Args.push_back(llvm::UndefValue::get(PaddingType)); + ++IRArgNo; + } + switch (ArgInfo.getKind()) { case ABIArgInfo::Indirect: { if (RV.isScalar() || RV.isComplex()) { @@ -2031,12 +2049,6 @@ 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/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 534c8f685d5a..2c2d17df77b4 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -531,7 +531,7 @@ class X86_32ABIInfo : public ABIInfo { ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs, bool IsFastCall) const; bool shouldUseInReg(QualType Ty, unsigned &FreeRegs, - bool IsFastCall) const; + bool IsFastCall, bool &NeedsPadding) const; public: @@ -807,7 +807,8 @@ X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const { } bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs, - bool IsFastCall) const { + bool IsFastCall, bool &NeedsPadding) const { + NeedsPadding = false; Class C = classify(Ty); if (C == Float) return false; @@ -838,6 +839,9 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs, if (Ty->isReferenceType()) return true; + if (FreeRegs) + NeedsPadding = true; + return false; } @@ -864,16 +868,18 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - if (shouldUseInReg(Ty, FreeRegs, IsFastCall)) { + llvm::LLVMContext &LLVMContext = getVMContext(); + llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); + bool NeedsPadding; + if (shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding)) { unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; - llvm::LLVMContext &LLVMContext = getVMContext(); - llvm::Type *Int32 = llvm::Type::getInt32Ty(LLVMContext); SmallVector Elements; for (unsigned I = 0; I < SizeInRegs; ++I) Elements.push_back(Int32); llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); return ABIArgInfo::getDirectInReg(Result); } + llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : 0; // Expand small (<= 128-bit) record types when we know that the stack layout // of those arguments will match the struct. This is important because the @@ -881,7 +887,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, // optimizations. if (getContext().getTypeSize(Ty) <= 4*32 && canExpandIndirectArgument(Ty, getContext())) - return ABIArgInfo::getExpand(); + return ABIArgInfo::getExpandWithPadding(IsFastCall, PaddingType); return getIndirectResult(Ty, true, FreeRegs); } @@ -914,7 +920,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); - bool InReg = shouldUseInReg(Ty, FreeRegs, IsFastCall); + bool NeedsPadding; + bool InReg = shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding); if (Ty->isPromotableIntegerType()) { if (InReg) diff --git a/clang/test/CodeGen/stdcall-fastcall.c b/clang/test/CodeGen/stdcall-fastcall.c index dac2a3a14286..d51817882283 100644 --- a/clang/test/CodeGen/stdcall-fastcall.c +++ b/clang/test/CodeGen/stdcall-fastcall.c @@ -62,7 +62,7 @@ struct S1 { void __attribute__((fastcall)) foo2(struct S1 y); void bar2(struct S1 y) { // CHECK: define void @bar2 - // CHECK: call x86_fastcallcc void @foo2(i32 % + // CHECK: call x86_fastcallcc void @foo2(i32 inreg undef, i32 % foo2(y); } @@ -110,7 +110,7 @@ void bar7(int a, struct S1 b, int c) { void __attribute__((fastcall)) foo8(struct S1 a, int b); void bar8(struct S1 a, int b) { // CHECK: define void @bar8 - // CHECK: call x86_fastcallcc void @foo8(i32 %{{.*}}, i32 inreg % + // CHECK: call x86_fastcallcc void @foo8(i32 inreg undef, i32 %{{.*}}, i32 inreg % foo8(a, b); }