Skip to content

Commit d3db27e

Browse files
committed
[Xtensa] Implement variable arguments support.
1 parent 7c07863 commit d3db27e

File tree

4 files changed

+338
-7
lines changed

4 files changed

+338
-7
lines changed

llvm/lib/Target/Xtensa/XtensaISelLowering.cpp

+227-6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "XtensaISelLowering.h"
1515
#include "XtensaConstantPoolValue.h"
1616
#include "XtensaInstrInfo.h"
17+
#include "XtensaMachineFunctionInfo.h"
1718
#include "XtensaSubtarget.h"
1819
#include "XtensaTargetMachine.h"
1920
#include "llvm/CodeGen/CallingConvLower.h"
@@ -133,6 +134,14 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
133134
setOperationAction(ISD::STACKSAVE, MVT::Other, Custom);
134135
setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom);
135136

137+
// VASTART and VACOPY need to deal with the Xtensa-specific varargs
138+
// structure, but VAEND is a no-op.
139+
setOperationAction(ISD::VASTART, MVT::Other, Custom);
140+
// we use special va_list structure so we have to customize this
141+
setOperationAction(ISD::VAARG, MVT::Other, Custom);
142+
setOperationAction(ISD::VACOPY, MVT::Other, Custom);
143+
setOperationAction(ISD::VAEND, MVT::Other, Expand);
144+
136145
// Compute derived properties from the register classes
137146
computeRegisterProperties(STI.getRegisterInfo());
138147
}
@@ -211,6 +220,11 @@ void XtensaTargetLowering::LowerAsmOperandForConstraint(
211220
TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
212221
}
213222

223+
unsigned XtensaTargetLowering::getVaListSizeInBits(const DataLayout &DL) const {
224+
// 2 * sizeof(int*) + sizeof(int)
225+
return 3 * 4;
226+
}
227+
214228
//===----------------------------------------------------------------------===//
215229
// Calling conventions
216230
//===----------------------------------------------------------------------===//
@@ -304,13 +318,14 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
304318
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
305319
MachineFunction &MF = DAG.getMachineFunction();
306320
MachineFrameInfo &MFI = MF.getFrameInfo();
321+
XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
322+
EVT PtrVT = getPointerTy(MF.getDataLayout());
323+
324+
XtensaFI->setVarArgsFrameIndex(0);
307325

308326
// Used with vargs to acumulate store chains.
309327
std::vector<SDValue> OutChains;
310328

311-
if (IsVarArg)
312-
report_fatal_error("Var arg not supported by FormalArguments Lowering");
313-
314329
// Assign locations to all of the incoming arguments.
315330
SmallVector<CCValAssign, 16> ArgLocs;
316331
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
@@ -378,6 +393,68 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
378393
}
379394
}
380395

396+
if (IsVarArg) {
397+
static const MCPhysReg XtensaArgRegs[6] = {
398+
Xtensa::A2, Xtensa::A3, Xtensa::A4, Xtensa::A5, Xtensa::A6, Xtensa::A7};
399+
ArrayRef<MCPhysReg> ArgRegs = ArrayRef(XtensaArgRegs);
400+
unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
401+
const TargetRegisterClass *RC = &Xtensa::ARRegClass;
402+
MachineFrameInfo &MFI = MF.getFrameInfo();
403+
MachineRegisterInfo &RegInfo = MF.getRegInfo();
404+
unsigned RegSize = 4;
405+
MVT RegTy = MVT::getIntegerVT(RegSize * 8);
406+
407+
XtensaFI->setVarArgsFirstGPR(Idx + 2); // 2 - number of a2 register
408+
409+
XtensaFI->setVarArgsStackOffset(MFI.CreateFixedObject(
410+
PtrVT.getSizeInBits() / 8, CCInfo.getStackSize(), true));
411+
412+
// Offset of the first variable argument from stack pointer, and size of
413+
// the vararg save area. For now, the varargs save area is either zero or
414+
// large enough to hold a0-a7.
415+
int VaArgOffset, VarArgsSaveSize;
416+
417+
// If all registers are allocated, then all varargs must be passed on the
418+
// stack and we don't need to save any argregs.
419+
if (ArgRegs.size() == Idx) {
420+
VaArgOffset = CCInfo.getStackSize();
421+
VarArgsSaveSize = 0;
422+
} else {
423+
VarArgsSaveSize = RegSize * (ArgRegs.size() - Idx);
424+
VaArgOffset = -VarArgsSaveSize;
425+
}
426+
427+
// Record the frame index of the first variable argument
428+
// which is a value necessary to VASTART.
429+
int FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);
430+
XtensaFI->setVarArgsFrameIndex(FI);
431+
432+
// Copy the integer registers that may have been used for passing varargs
433+
// to the vararg save area.
434+
for (unsigned I = Idx; I < ArgRegs.size(); ++I, VaArgOffset += RegSize) {
435+
const unsigned Reg = RegInfo.createVirtualRegister(RC);
436+
unsigned FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
437+
438+
// Argument passed in FrameReg we save in A8 (in emitPrologue),
439+
// so load argument from A8
440+
if (ArgRegs[I] == FrameReg) {
441+
RegInfo.addLiveIn(Xtensa::A8, Reg);
442+
} else {
443+
RegInfo.addLiveIn(ArgRegs[I], Reg);
444+
}
445+
446+
SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegTy);
447+
FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);
448+
SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
449+
SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
450+
MachinePointerInfo::getFixedStack(MF, FI));
451+
cast<StoreSDNode>(Store.getNode())
452+
->getMemOperand()
453+
->setValue((Value *)nullptr);
454+
OutChains.push_back(Store);
455+
}
456+
}
457+
381458
// All stores are grouped in one node to allow the matching between
382459
// the size of Ins and InVals. This only happens when on varg functions
383460
if (!OutChains.empty()) {
@@ -579,9 +656,6 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
579656
const SmallVectorImpl<ISD::OutputArg> &Outs,
580657
const SmallVectorImpl<SDValue> &OutVals,
581658
const SDLoc &DL, SelectionDAG &DAG) const {
582-
if (IsVarArg)
583-
report_fatal_error("VarArg not supported");
584-
585659
MachineFunction &MF = DAG.getMachineFunction();
586660

587661
// Assign locations to each returned value.
@@ -859,6 +933,147 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
859933
return DAG.getMergeValues(Ops, DL);
860934
}
861935

936+
SDValue XtensaTargetLowering::LowerVASTART(SDValue Op,
937+
SelectionDAG &DAG) const {
938+
MachineFunction &MF = DAG.getMachineFunction();
939+
XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
940+
SDValue Chain = Op.getOperand(0);
941+
SDValue Addr = Op.getOperand(1);
942+
EVT PtrVT = Addr.getValueType();
943+
SDLoc DL(Op);
944+
945+
// Struct va_list_tag
946+
// int32 *va_stk - points to the arguments passed in memory
947+
// int32 *va_reg - points to the registers with arguments saved in memory
948+
// int32 va_ndx - offset from va_stk or va_reg pointers which points to the
949+
// next variable argument
950+
951+
SDValue VAIndex;
952+
SDValue StackOffsetFI =
953+
DAG.getFrameIndex(XtensaFI->getVarArgsStackOffset(), PtrVT);
954+
unsigned ArgWords = XtensaFI->getVarArgsFirstGPR() - 2;
955+
956+
// If first variable argument passed in registers (maximum words in registers
957+
// is 6) then set va_ndx to the position of this argument in registers area
958+
// stored in memory (va_reg pointer). Otherwise va_ndx should point to the
959+
// position of the first variable argument on stack (va_stk pointer).
960+
if (ArgWords < 6) {
961+
VAIndex = DAG.getConstant(ArgWords * 4, DL, MVT::i32);
962+
} else {
963+
VAIndex = DAG.getConstant(32, DL, MVT::i32);
964+
}
965+
966+
SDValue FrameIndex =
967+
DAG.getFrameIndex(XtensaFI->getVarArgsFrameIndex(), PtrVT);
968+
uint64_t FrameOffset = PtrVT.getStoreSize();
969+
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
970+
971+
// Store pointer to arguments given on stack (va_stk)
972+
SDValue StackPtr = DAG.getNode(ISD::SUB, DL, PtrVT, StackOffsetFI,
973+
DAG.getConstant(32, DL, PtrVT));
974+
SDValue StoreStackPtr =
975+
DAG.getStore(Chain, DL, StackPtr, Addr, MachinePointerInfo(SV));
976+
977+
uint64_t NextOffset = FrameOffset;
978+
SDValue NextPtr = DAG.getNode(ISD::ADD, DL, PtrVT, Addr,
979+
DAG.getConstant(NextOffset, DL, PtrVT));
980+
981+
// Store pointer to arguments given on registers (va_reg)
982+
SDValue StoreRegPtr = DAG.getStore(StoreStackPtr, DL, FrameIndex, NextPtr,
983+
MachinePointerInfo(SV, NextOffset));
984+
NextOffset += FrameOffset;
985+
NextPtr = DAG.getNode(ISD::ADD, DL, PtrVT, Addr,
986+
DAG.getConstant(NextOffset, DL, PtrVT));
987+
988+
// Store third word : position in bytes of the first VA argument (va_ndx)
989+
return DAG.getStore(StoreRegPtr, DL, VAIndex, NextPtr,
990+
MachinePointerInfo(SV, NextOffset));
991+
}
992+
993+
SDValue XtensaTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG) const {
994+
unsigned VAListSize = getVaListSizeInBits(DAG.getDataLayout()) / 8;
995+
return DAG.getMemcpy(
996+
Op.getOperand(0), Op, Op.getOperand(1), Op.getOperand(2),
997+
DAG.getConstant(VAListSize, SDLoc(Op), MVT::i32), Align(4),
998+
/*isVolatile=*/false, /*AlwaysInline=*/false,
999+
/*CI=*/nullptr, std::nullopt, MachinePointerInfo(), MachinePointerInfo());
1000+
}
1001+
1002+
SDValue XtensaTargetLowering::LowerVAARG(SDValue Op, SelectionDAG &DAG) const {
1003+
SDNode *Node = Op.getNode();
1004+
EVT VT = Node->getValueType(0);
1005+
EVT PtrVT = Op.getValueType();
1006+
SDValue InChain = Node->getOperand(0);
1007+
SDValue VAListPtr = Node->getOperand(1);
1008+
const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
1009+
SDLoc DL(Node);
1010+
auto &TD = DAG.getDataLayout();
1011+
Align ArgAlignment = TD.getPrefTypeAlign(VT.getTypeForEVT(*DAG.getContext()));
1012+
unsigned ArgAlignInBytes = ArgAlignment.value();
1013+
unsigned ArgSizeInBytes =
1014+
TD.getTypeAllocSize(VT.getTypeForEVT(*DAG.getContext()));
1015+
unsigned VASizeInBytes = (ArgSizeInBytes + 3) & 0x3;
1016+
1017+
// va_stk
1018+
SDValue VAStack =
1019+
DAG.getLoad(MVT::i32, DL, InChain, VAListPtr, MachinePointerInfo());
1020+
InChain = VAStack.getValue(1);
1021+
1022+
// va_reg
1023+
SDValue VARegPtr = DAG.getNode(ISD::ADD, DL, PtrVT, VAListPtr,
1024+
DAG.getConstant(4, DL, MVT::i32));
1025+
SDValue VAReg =
1026+
DAG.getLoad(MVT::i32, DL, InChain, VARegPtr, MachinePointerInfo());
1027+
InChain = VAReg.getValue(1);
1028+
1029+
// va_ndx
1030+
SDValue VarArgIndexPtr = DAG.getNode(ISD::ADD, DL, PtrVT, VARegPtr,
1031+
DAG.getConstant(4, DL, MVT::i32));
1032+
SDValue VAIndex =
1033+
DAG.getLoad(MVT::i32, DL, InChain, VarArgIndexPtr, MachinePointerInfo());
1034+
InChain = VAIndex.getValue(1);
1035+
1036+
SDValue OrigIndex = VAIndex;
1037+
1038+
if (ArgAlignInBytes > 4) {
1039+
OrigIndex = DAG.getNode(ISD::ADD, DL, PtrVT, OrigIndex,
1040+
DAG.getConstant(ArgAlignInBytes - 1, DL, MVT::i32));
1041+
OrigIndex = DAG.getNode(ISD::AND, DL, PtrVT, OrigIndex,
1042+
DAG.getConstant(-ArgAlignInBytes, DL, MVT::i32));
1043+
}
1044+
1045+
VAIndex = DAG.getNode(ISD::ADD, DL, PtrVT, OrigIndex,
1046+
DAG.getConstant(VASizeInBytes, DL, MVT::i32));
1047+
1048+
SDValue CC = DAG.getSetCC(DL, MVT::i32, OrigIndex,
1049+
DAG.getConstant(6 * 4, DL, MVT::i32), ISD::SETLE);
1050+
1051+
SDValue StkIndex =
1052+
DAG.getNode(ISD::ADD, DL, PtrVT, VAIndex,
1053+
DAG.getConstant(32 + VASizeInBytes, DL, MVT::i32));
1054+
1055+
CC = DAG.getSetCC(DL, MVT::i32, VAIndex, DAG.getConstant(6 * 4, DL, MVT::i32),
1056+
ISD::SETLE);
1057+
1058+
SDValue Array = DAG.getNode(ISD::SELECT, DL, MVT::i32, CC, VAReg, VAStack);
1059+
1060+
VAIndex = DAG.getNode(ISD::SELECT, DL, MVT::i32, CC, VAIndex, StkIndex);
1061+
1062+
CC = DAG.getSetCC(DL, MVT::i32, VAIndex, DAG.getConstant(6 * 4, DL, MVT::i32),
1063+
ISD::SETLE);
1064+
1065+
SDValue VAIndexStore = DAG.getStore(InChain, DL, VAIndex, VarArgIndexPtr,
1066+
MachinePointerInfo(SV));
1067+
InChain = VAIndexStore;
1068+
1069+
SDValue Addr = DAG.getNode(ISD::SUB, DL, PtrVT, VAIndex,
1070+
DAG.getConstant(VASizeInBytes, DL, MVT::i32));
1071+
1072+
Addr = DAG.getNode(ISD::ADD, DL, PtrVT, Array, Addr);
1073+
1074+
return DAG.getLoad(VT, DL, InChain, Addr, MachinePointerInfo());
1075+
}
1076+
8621077
SDValue XtensaTargetLowering::LowerShiftLeftParts(SDValue Op,
8631078
SelectionDAG &DAG) const {
8641079
SDLoc DL(Op);
@@ -1001,6 +1216,12 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
10011216
return LowerFRAMEADDR(Op, DAG);
10021217
case ISD::DYNAMIC_STACKALLOC:
10031218
return LowerDYNAMIC_STACKALLOC(Op, DAG);
1219+
case ISD::VASTART:
1220+
return LowerVASTART(Op, DAG);
1221+
case ISD::VAARG:
1222+
return LowerVAARG(Op, DAG);
1223+
case ISD::VACOPY:
1224+
return LowerVACOPY(Op, DAG);
10041225
case ISD::SHL_PARTS:
10051226
return LowerShiftLeftParts(Op, DAG);
10061227
case ISD::SRA_PARTS:

llvm/lib/Target/Xtensa/XtensaISelLowering.h

+9
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ class XtensaTargetLowering : public TargetLowering {
7474

7575
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
7676

77+
/// Returns the size of the platform's va_list object.
78+
unsigned getVaListSizeInBits(const DataLayout &DL) const override;
79+
7780
const char *getTargetNodeName(unsigned Opcode) const override;
7881

7982
std::pair<unsigned, const TargetRegisterClass *>
@@ -148,6 +151,12 @@ class XtensaTargetLowering : public TargetLowering {
148151

149152
SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const;
150153

154+
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
155+
156+
SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const;
157+
158+
SDValue LowerVACOPY(SDValue Op, SelectionDAG &DAG) const;
159+
151160
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
152161

153162
SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const;

llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,31 @@ namespace llvm {
2424
class XtensaMachineFunctionInfo : public MachineFunctionInfo {
2525
/// FrameIndex of the spill slot for the scratch register in BranchRelaxation.
2626
int BranchRelaxationScratchFrameIndex = -1;
27+
unsigned VarArgsFirstGPR;
28+
int VarArgsStackOffset;
29+
unsigned VarArgsFrameIndex;
2730

2831
public:
2932
explicit XtensaMachineFunctionInfo(const Function &F,
30-
const TargetSubtargetInfo *STI) {}
33+
const TargetSubtargetInfo *STI)
34+
: VarArgsFirstGPR(0), VarArgsStackOffset(0), VarArgsFrameIndex(0) {}
3135

3236
int getBranchRelaxationScratchFrameIndex() const {
3337
return BranchRelaxationScratchFrameIndex;
3438
}
3539
void setBranchRelaxationScratchFrameIndex(int Index) {
3640
BranchRelaxationScratchFrameIndex = Index;
3741
}
42+
43+
unsigned getVarArgsFirstGPR() const { return VarArgsFirstGPR; }
44+
void setVarArgsFirstGPR(unsigned GPR) { VarArgsFirstGPR = GPR; }
45+
46+
int getVarArgsStackOffset() const { return VarArgsStackOffset; }
47+
void setVarArgsStackOffset(int Offset) { VarArgsStackOffset = Offset; }
48+
49+
// Get and set the frame index of the first stack vararg.
50+
unsigned getVarArgsFrameIndex() const { return VarArgsFrameIndex; }
51+
void setVarArgsFrameIndex(unsigned FI) { VarArgsFrameIndex = FI; }
3852
};
3953

4054
} // namespace llvm

0 commit comments

Comments
 (0)