Refactor ABI argument lowering a little

Currently it tracks the number of free registers, but soon it will track
stack offsets for inalloca lowering.

No functional change.

llvm-svn: 199532
This commit is contained in:
Reid Kleckner 2014-01-18 01:12:41 +00:00
parent 0abb057715
commit 661f35b0c5
1 changed files with 60 additions and 57 deletions

View File

@ -526,6 +526,14 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
// X86-32 ABI Implementation
//===----------------------------------------------------------------------===//
/// \brief Similar to llvm::CCState, but for Clang.
struct CCState {
CCState(unsigned CC) : CC(CC), FreeRegs(0) {}
unsigned CC;
unsigned FreeRegs;
};
/// X86_32ABIInfo - The X86-32 ABI information.
class X86_32ABIInfo : public ABIInfo {
enum Class {
@ -549,19 +557,17 @@ class X86_32ABIInfo : public ABIInfo {
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
ABIArgInfo getIndirectResult(QualType Ty, bool ByVal,
unsigned &FreeRegs) const;
ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const;
ABIArgInfo getIndirectReturnResult(CCState &State) const;
/// \brief Return the alignment to use for the given type on the stack.
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
Class classify(QualType Ty) const;
ABIArgInfo classifyReturnType(QualType RetTy,
unsigned callingConvention) const;
ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs,
bool IsFastCall) const;
bool shouldUseInReg(QualType Ty, unsigned &FreeRegs,
bool IsFastCall, bool &NeedsPadding) const;
ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const;
public:
@ -677,8 +683,18 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
return true;
}
ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
unsigned callingConvention) const {
ABIArgInfo X86_32ABIInfo::getIndirectReturnResult(CCState &State) const {
// If the return value is indirect, then the hidden argument is consuming one
// integer register.
if (State.FreeRegs) {
--State.FreeRegs;
return ABIArgInfo::getIndirectInReg(/*Align=*/0, /*ByVal=*/false);
}
return ABIArgInfo::getIndirect(/*Align=*/0, /*ByVal=*/false);
}
ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
CCState &State) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@ -701,7 +717,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
return ABIArgInfo::getIndirect(0);
return getIndirectReturnResult(State);
}
return ABIArgInfo::getDirect();
@ -710,21 +726,21 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
if (isAggregateTypeForABI(RetTy)) {
if (const RecordType *RT = RetTy->getAs<RecordType>()) {
if (isRecordReturnIndirect(RT, getCXXABI()))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
return getIndirectReturnResult(State);
// Structures with flexible arrays are always indirect.
if (RT->getDecl()->hasFlexibleArrayMember())
return ABIArgInfo::getIndirect(0);
return getIndirectReturnResult(State);
}
// If specified, structs and unions are always indirect.
if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType())
return ABIArgInfo::getIndirect(0);
return getIndirectReturnResult(State);
// Small structures which are register sized are generally returned
// in a register.
if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext(),
callingConvention)) {
if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext(),
State.CC)) {
uint64_t Size = getContext().getTypeSize(RetTy);
// As a special-case, if the struct is a "single-element" struct, and
@ -742,7 +758,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size));
}
return ABIArgInfo::getIndirect(0);
return getIndirectReturnResult(State);
}
// Treat an enum type as its underlying type.
@ -806,10 +822,10 @@ unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty,
}
ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal,
unsigned &FreeRegs) const {
CCState &State) const {
if (!ByVal) {
if (FreeRegs) {
--FreeRegs; // Non-byval indirects just use one pointer.
if (State.FreeRegs) {
--State.FreeRegs; // Non-byval indirects just use one pointer.
return ABIArgInfo::getIndirectInReg(0, false);
}
return ABIArgInfo::getIndirect(0, false);
@ -843,8 +859,8 @@ X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
return Integer;
}
bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
bool IsFastCall, bool &NeedsPadding) const {
bool X86_32ABIInfo::shouldUseInReg(QualType Ty, CCState &State,
bool &NeedsPadding) const {
NeedsPadding = false;
Class C = classify(Ty);
if (C == Float)
@ -856,14 +872,14 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
if (SizeInRegs == 0)
return false;
if (SizeInRegs > FreeRegs) {
FreeRegs = 0;
if (SizeInRegs > State.FreeRegs) {
State.FreeRegs = 0;
return false;
}
FreeRegs -= SizeInRegs;
State.FreeRegs -= SizeInRegs;
if (IsFastCall) {
if (State.CC == llvm::CallingConv::X86_FastCall) {
if (Size > 32)
return false;
@ -876,7 +892,7 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
if (Ty->isReferenceType())
return true;
if (FreeRegs)
if (State.FreeRegs)
NeedsPadding = true;
return false;
@ -885,21 +901,20 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
return true;
}
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
unsigned &FreeRegs,
bool IsFastCall) const {
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State) const {
// FIXME: Set alignment on indirect arguments.
if (isAggregateTypeForABI(Ty)) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
if (IsWin32StructABI)
return getIndirectResult(Ty, true, FreeRegs);
return getIndirectResult(Ty, true, State);
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
return getIndirectResult(Ty, RAA == CGCXXABI::RAA_DirectInMemory, FreeRegs);
return getIndirectResult(Ty, RAA == CGCXXABI::RAA_DirectInMemory,
State);
// Structures with flexible arrays are always indirect.
if (RT->getDecl()->hasFlexibleArrayMember())
return getIndirectResult(Ty, true, FreeRegs);
return getIndirectResult(Ty, true, State);
}
// Ignore empty structs/unions.
@ -909,7 +924,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
llvm::LLVMContext &LLVMContext = getVMContext();
llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
bool NeedsPadding;
if (shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding)) {
if (shouldUseInReg(Ty, State, NeedsPadding)) {
unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
SmallVector<llvm::Type*, 3> Elements(SizeInRegs, Int32);
llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
@ -923,9 +938,10 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
// optimizations.
if (getContext().getTypeSize(Ty) <= 4*32 &&
canExpandIndirectArgument(Ty, getContext()))
return ABIArgInfo::getExpandWithPadding(IsFastCall, PaddingType);
return ABIArgInfo::getExpandWithPadding(
State.CC == llvm::CallingConv::X86_FastCall, PaddingType);
return getIndirectResult(Ty, true, FreeRegs);
return getIndirectResult(Ty, true, State);
}
if (const VectorType *VT = Ty->getAs<VectorType>()) {
@ -950,7 +966,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
Ty = EnumTy->getDecl()->getIntegerType();
bool NeedsPadding;
bool InReg = shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding);
bool InReg = shouldUseInReg(Ty, State, NeedsPadding);
if (Ty->isPromotableIntegerType()) {
if (InReg)
@ -963,32 +979,19 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
}
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
FI.getCallingConvention());
unsigned CC = FI.getCallingConvention();
bool IsFastCall = CC == llvm::CallingConv::X86_FastCall;
unsigned FreeRegs;
if (IsFastCall)
FreeRegs = 2;
CCState State(FI.getCallingConvention());
if (State.CC == llvm::CallingConv::X86_FastCall)
State.FreeRegs = 2;
else if (FI.getHasRegParm())
FreeRegs = FI.getRegParm();
State.FreeRegs = FI.getRegParm();
else
FreeRegs = DefaultNumRegisterParameters;
State.FreeRegs = DefaultNumRegisterParameters;
// If the return value is indirect, then the hidden argument is consuming one
// integer register.
if (FI.getReturnInfo().isIndirect() && FreeRegs) {
--FreeRegs;
ABIArgInfo &Old = FI.getReturnInfo();
Old = ABIArgInfo::getIndirectInReg(Old.getIndirectAlign(),
Old.getIndirectByVal(),
Old.getIndirectRealign());
}
FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State);
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
it->info = classifyArgumentType(it->type, FreeRegs, IsFastCall);
it->info = classifyArgumentType(it->type, State);
}
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,