Skip to content

Commit ae26b7e

Browse files
committed
[Xtensa] Refactoring call abi code generation.
Now large structures are passed by value, as it is implemented in gcc call abi generation for Xtensa. Closes #14
1 parent a5a002f commit ae26b7e

File tree

4 files changed

+151
-196
lines changed

4 files changed

+151
-196
lines changed

clang/lib/Basic/Targets/Xtensa.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo {
3636
: TargetInfo(Triple) {
3737
BigEndian = false;
3838
NoAsmVariants = true;
39-
LongLongAlign = 32;
39+
LongLongAlign = 64;
4040
SuitableAlign = 32;
41-
DoubleAlign = LongDoubleAlign = 32;
41+
DoubleAlign = LongDoubleAlign = 64;
4242
SizeType = UnsignedInt;
4343
PtrDiffType = SignedInt;
4444
IntPtrType = SignedInt;

clang/lib/CodeGen/TargetInfo.cpp

Lines changed: 113 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -9642,10 +9642,8 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
96429642
namespace {
96439643
class XtensaABIInfo : public DefaultABIInfo {
96449644
private:
9645-
static const int NumArgGPRs = 6;
9646-
static const int MAX_ARG_IN_REGS_SIZE = 4 * 32;
9647-
static const int MAX_ARG_DIRECT_SIZE = MAX_ARG_IN_REGS_SIZE;
9648-
static const int MAX_RET_IN_REGS_SIZE = 2 * 32;
9645+
static const int MaxNumArgGPRs = 6;
9646+
static const int MaxNumRetGPRs = 4;
96499647

96509648
public:
96519649
XtensaABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
@@ -9654,8 +9652,8 @@ class XtensaABIInfo : public DefaultABIInfo {
96549652
// non-virtual, but computeInfo is virtual, so we overload it.
96559653
void computeInfo(CGFunctionInfo &FI) const override;
96569654

9657-
ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed,
9658-
int &ArgGPRsLeft) const;
9655+
ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft) const;
9656+
96599657
ABIArgInfo classifyReturnType(QualType RetTy) const;
96609658

96619659
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
@@ -9669,31 +9667,16 @@ void XtensaABIInfo::computeInfo(CGFunctionInfo &FI) const {
96699667
QualType RetTy = FI.getReturnType();
96709668
if (!getCXXABI().classifyReturnType(FI))
96719669
FI.getReturnInfo() = classifyReturnType(RetTy);
9672-
// IsRetIndirect is true if classifyArgumentType indicated the value should
9673-
// be passed indirect or if the type size is greater than 2*32.
9674-
// is passed direct in LLVM IR, relying on the backend lowering code to
9675-
// rewrite the argument list and pass indirectly on RV32.
9676-
bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect ||
9677-
getContext().getTypeSize(RetTy) > MAX_RET_IN_REGS_SIZE;
9678-
// We must track the number of GPRs used in order to conform to the Xtensa
9679-
// ABI, as integer scalars passed in registers should have signext/zeroext
9680-
// when promoted, but are anyext if passed on the stack. As GPR usage is
9681-
// different for variadic arguments, we must also track whether we are
9682-
// examining a vararg or not.
9683-
int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
9684-
int NumFixedArgs = FI.getNumRequiredArgs();
9685-
int ArgNum = 0;
9670+
9671+
int ArgGPRsLeft = MaxNumArgGPRs;
96869672
for (auto &ArgInfo : FI.arguments()) {
9687-
bool IsFixed = ArgNum < NumFixedArgs;
9688-
ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft);
9689-
ArgNum++;
9673+
ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft);
96909674
}
96919675
}
96929676

9693-
ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
9677+
ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty,
96949678
int &ArgGPRsLeft) const {
9695-
assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
9696-
9679+
assert(ArgGPRsLeft <= MaxNumArgGPRs && "Arg GPR tracking underflow");
96979680
Ty = useFirstFieldIfTransparentUnion(Ty);
96989681
// Structures with either a non-trivial destructor or a non-trivial
96999682
// copy constructor are always passed indirectly.
@@ -9703,26 +9686,26 @@ ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
97039686
return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
97049687
CGCXXABI::RAA_DirectInMemory);
97059688
}
9689+
97069690
// Ignore empty structs/unions.
97079691
if (isEmptyRecord(getContext(), Ty, true))
97089692
return ABIArgInfo::getIgnore();
9693+
97099694
uint64_t Size = getContext().getTypeSize(Ty);
97109695
uint64_t NeededAlign = getContext().getTypeAlign(Ty);
97119696
bool MustUseStack = false;
9712-
// Determine the number of GPRs needed to pass the current argument
9713-
// according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
9714-
// register pairs, so may consume 3 registers.
9715-
int NeededArgGPRs = 1;
9716-
if (!IsFixed && NeededAlign == 2 * 32)
9717-
NeededArgGPRs = 2 + (ArgGPRsLeft % 2);
9718-
else if (Size > 32 && Size <= MAX_ARG_IN_REGS_SIZE)
9719-
NeededArgGPRs = (Size + 31) / 32;
9720-
if (NeededArgGPRs > ArgGPRsLeft) {
9697+
int NeededArgGPRs = (Size + 31) / 32;
9698+
9699+
if (NeededAlign == 2 * 32)
9700+
NeededArgGPRs += (ArgGPRsLeft % 2);
9701+
9702+
if ((NeededArgGPRs > ArgGPRsLeft) || (NeededAlign > 2 * 32)) {
97219703
MustUseStack = true;
97229704
NeededArgGPRs = ArgGPRsLeft;
97239705
}
97249706
ArgGPRsLeft -= NeededArgGPRs;
9725-
if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) {
9707+
9708+
if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType() && !MustUseStack) {
97269709
// Treat an enum type as its underlying type.
97279710
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
97289711
Ty = EnumTy->getDecl()->getIntegerType();
@@ -9731,76 +9714,127 @@ ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
97319714
if (Size < 32 && Ty->isIntegralOrEnumerationType() && !MustUseStack) {
97329715
return extendType(Ty);
97339716
}
9734-
return ABIArgInfo::getDirect();
9717+
if (Size == 64)
9718+
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64));
9719+
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 32));
97359720
}
97369721

9737-
// Aggregates which are <= 4*32 will be passed in registers if possible,
9722+
// Aggregates which are <= 6*32 will be passed in registers if possible,
97389723
// so coerce to integers.
9739-
if (Size <= MAX_ARG_IN_REGS_SIZE) {
9740-
unsigned Alignment = getContext().getTypeAlign(Ty);
9741-
// Use a single XLen int if possible, 2*XLen if 2*XLen alignment is
9742-
// required, and a 2-element XLen array if only XLen alignment is
9743-
// required.
9724+
if ((Size <= (MaxNumArgGPRs * 32)) && (!MustUseStack)) {
97449725
if (Size <= 32) {
97459726
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 32));
9746-
}
9747-
9748-
else if (Alignment == 2 * 32) {
9749-
return ABIArgInfo::getDirect(
9750-
llvm::IntegerType::get(getVMContext(), 2 * 32));
97519727
} else {
97529728
return ABIArgInfo::getDirect(llvm::ArrayType::get(
9753-
llvm::IntegerType::get(getVMContext(), 32), (Size + 31) / 32));
9729+
llvm::IntegerType::get(getVMContext(), 32), NeededArgGPRs));
97549730
}
97559731
}
97569732
#undef MAX_STRUCT_IN_REGS_SIZE
9757-
return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
9733+
return getNaturalAlignIndirect(Ty, /*ByVal=*/true);
97589734
}
97599735

97609736
ABIArgInfo XtensaABIInfo::classifyReturnType(QualType RetTy) const {
97619737
if (RetTy->isVoidType())
97629738
return ABIArgInfo::getIgnore();
9763-
int ArgGPRsLeft = 2;
9739+
int ArgGPRsLeft = MaxNumRetGPRs;
97649740
// The rules for return and argument types are the same, so defer to
97659741
// classifyArgumentType.
9766-
return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft);
9742+
return classifyArgumentType(RetTy, ArgGPRsLeft);
97679743
}
97689744

97699745
Address XtensaABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
97709746
QualType Ty) const {
9771-
CharUnits SlotSize = CharUnits::fromQuantity(32 / 8);
9772-
// Empty records are ignored for parameter passing purposes.
9773-
if (isEmptyRecord(getContext(), Ty, true)) {
9774-
// We try to return some dummy value which will be
9775-
// removed by backend
9747+
// The va_list structure memory layout:
9748+
// struct __va_list_tag {
9749+
// int32_t *va_stk;
9750+
// int32_t *va_reg;
9751+
// int32_t va_ndx;
9752+
// };
9753+
CGBuilderTy &Builder = CGF.Builder;
9754+
9755+
Address OverflowAreaPtr = Builder.CreateStructGEP(VAListAddr, 0, "__va_stk");
9756+
Address OverflowArea = Address(Builder.CreateLoad(OverflowAreaPtr, ""),
9757+
CharUnits::fromQuantity(4));
9758+
Address RegSaveAreaPtr = Builder.CreateStructGEP(VAListAddr, 1, "__va_reg");
9759+
Address RegSaveArea = Address(Builder.CreateLoad(RegSaveAreaPtr, ""),
9760+
CharUnits::fromQuantity(4));
9761+
Address ARAreaPtr = Builder.CreateStructGEP(VAListAddr, 2, "__va_ndx");
9762+
llvm::Value *ARIndex = Builder.CreateLoad(ARAreaPtr, "");
9763+
9764+
ARIndex = Builder.CreateLShr(ARIndex, Builder.getInt32(2));
97769765

9777-
auto TypeInfo = getContext().getTypeInfoInChars(Ty);
9778-
return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TypeInfo, SlotSize,
9779-
/*AllowHigherAlign=*/false);
9766+
unsigned Align = getContext().getTypeAlign(Ty) / 32;
9767+
unsigned Size = (getContext().getTypeSize(Ty) + 31) / 32;
9768+
9769+
if (Align > 1) {
9770+
ARIndex = Builder.CreateAdd(ARIndex, Builder.getInt32(Align - 1));
9771+
ARIndex =
9772+
Builder.CreateAnd(ARIndex, Builder.getInt32((uint32_t) ~(Align - 1)));
97809773
}
97819774

9782-
std::pair<CharUnits, CharUnits> SizeAndAlign =
9783-
getContext().getTypeInfoInChars(Ty);
9784-
// Arguments bigger than MAX_STRUCT_DIRECT_SIZE indirectly.
9785-
CharUnits DirectSize = CharUnits::fromQuantity(MAX_ARG_DIRECT_SIZE / 8);
9786-
bool IsIndirect = SizeAndAlign.first > DirectSize;
9775+
llvm::Value *ARIndexNext = Builder.CreateAdd(ARIndex, Builder.getInt32(Size));
9776+
Builder.CreateStore(Builder.CreateShl(ARIndexNext, Builder.getInt32(2)),
9777+
ARAreaPtr);
97879778

9788-
if (IsIndirect) {
9789-
auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty);
9790-
CharUnits TyAlignForABI = TyInfo.second;
9779+
const unsigned OverflowLimit = 6;
9780+
llvm::Value *CC = Builder.CreateICmpULE(
9781+
ARIndexNext, Builder.getInt32(OverflowLimit), "cond");
97919782

9792-
llvm::Type *BaseTy =
9793-
llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty));
9794-
llvm::Value *Addr =
9795-
CGF.Builder.CreateVAArg(VAListAddr.getPointer(), BaseTy);
9796-
return Address(Addr, TyAlignForABI);
9797-
} else {
9798-
Address Temp = CGF.CreateMemTemp(Ty, "varet");
9799-
llvm::Value *Val =
9800-
CGF.Builder.CreateVAArg(VAListAddr.getPointer(), CGF.ConvertType(Ty));
9801-
CGF.Builder.CreateStore(Val, Temp);
9802-
return Temp;
9783+
llvm::BasicBlock *UsingRegSaveArea =
9784+
CGF.createBasicBlock("using_regsavearea");
9785+
llvm::BasicBlock *UsingOverflow = CGF.createBasicBlock("using_overflow");
9786+
llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
9787+
9788+
Builder.CreateCondBr(CC, UsingRegSaveArea, UsingOverflow);
9789+
9790+
llvm::Type *DirectTy = CGF.ConvertType(Ty);
9791+
9792+
// Case 1: consume registers.
9793+
Address RegAddr = Address::invalid();
9794+
{
9795+
CGF.EmitBlock(UsingRegSaveArea);
9796+
9797+
CharUnits RegSize = CharUnits::fromQuantity(4);
9798+
RegSaveArea =
9799+
Address(Builder.CreateInBoundsGEP(CGF.Int32Ty, RegSaveArea.getPointer(),
9800+
ARIndex),
9801+
RegSaveArea.getAlignment().alignmentOfArrayElement(RegSize));
9802+
RegAddr = Builder.CreateElementBitCast(RegSaveArea, DirectTy);
9803+
CGF.EmitBranch(Cont);
98039804
}
9805+
9806+
// Case 2: consume space in the overflow area.
9807+
Address MemAddr = Address::invalid();
9808+
{
9809+
CGF.EmitBlock(UsingOverflow);
9810+
llvm::Value *CC1 = Builder.CreateICmpULE(
9811+
ARIndex, Builder.getInt32(OverflowLimit), "cond_overflow");
9812+
9813+
llvm::Value *ARIndexOff = Builder.CreateSelect(
9814+
CC1, Builder.CreateSub(Builder.getInt32(8), ARIndex),
9815+
Builder.getInt32(0));
9816+
9817+
llvm::Value *ARIndexCorr = Builder.CreateAdd(ARIndex, ARIndexOff);
9818+
llvm::Value *ARIndexNextCorr = Builder.CreateAdd(ARIndexNext, ARIndexOff);
9819+
Builder.CreateStore(Builder.CreateShl(ARIndexNextCorr, Builder.getInt32(2)),
9820+
ARAreaPtr);
9821+
9822+
CharUnits RegSize = CharUnits::fromQuantity(4);
9823+
OverflowArea =
9824+
Address(Builder.CreateInBoundsGEP(
9825+
CGF.Int32Ty, OverflowArea.getPointer(), ARIndexCorr),
9826+
OverflowArea.getAlignment().alignmentOfArrayElement(RegSize));
9827+
MemAddr = Builder.CreateElementBitCast(OverflowArea, DirectTy);
9828+
CGF.EmitBranch(Cont);
9829+
}
9830+
9831+
CGF.EmitBlock(Cont);
9832+
9833+
// Merge the cases with a phi.
9834+
Address Result =
9835+
emitMergePHI(CGF, RegAddr, UsingRegSaveArea, MemAddr, UsingOverflow, "");
9836+
9837+
return Result;
98049838
}
98059839

98069840
ABIArgInfo XtensaABIInfo::extendType(QualType Ty) const {

0 commit comments

Comments
 (0)