Skip to content

Commit be4a183

Browse files
authored
[Xtensa] Implement vararg support. (#117126)
1 parent ea632e1 commit be4a183

File tree

4 files changed

+775
-16
lines changed

4 files changed

+775
-16
lines changed

llvm/lib/Target/Xtensa/XtensaISelLowering.cpp

Lines changed: 221 additions & 15 deletions
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,13 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
133134
setOperationAction(ISD::STACKSAVE, MVT::Other, Custom);
134135
setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom);
135136

137+
// VASTART, VAARG 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+
setOperationAction(ISD::VAARG, MVT::Other, Custom);
141+
setOperationAction(ISD::VACOPY, MVT::Other, Custom);
142+
setOperationAction(ISD::VAEND, MVT::Other, Expand);
143+
136144
// Compute derived properties from the register classes
137145
computeRegisterProperties(STI.getRegisterInfo());
138146
}
@@ -217,12 +225,12 @@ void XtensaTargetLowering::LowerAsmOperandForConstraint(
217225

218226
#include "XtensaGenCallingConv.inc"
219227

228+
static const MCPhysReg IntRegs[] = {Xtensa::A2, Xtensa::A3, Xtensa::A4,
229+
Xtensa::A5, Xtensa::A6, Xtensa::A7};
230+
220231
static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT,
221232
CCValAssign::LocInfo LocInfo,
222233
ISD::ArgFlagsTy ArgFlags, CCState &State) {
223-
static const MCPhysReg IntRegs[] = {Xtensa::A2, Xtensa::A3, Xtensa::A4,
224-
Xtensa::A5, Xtensa::A6, Xtensa::A7};
225-
226234
if (ArgFlags.isByVal()) {
227235
Align ByValAlign = ArgFlags.getNonZeroByValAlign();
228236
unsigned ByValSize = ArgFlags.getByValSize();
@@ -304,13 +312,11 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
304312
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
305313
MachineFunction &MF = DAG.getMachineFunction();
306314
MachineFrameInfo &MFI = MF.getFrameInfo();
315+
XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
307316

308317
// Used with vargs to acumulate store chains.
309318
std::vector<SDValue> OutChains;
310319

311-
if (IsVarArg)
312-
report_fatal_error("Var arg not supported by FormalArguments Lowering");
313-
314320
// Assign locations to all of the incoming arguments.
315321
SmallVector<CCValAssign, 16> ArgLocs;
316322
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
@@ -323,17 +329,14 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
323329
// Arguments stored on registers
324330
if (VA.isRegLoc()) {
325331
EVT RegVT = VA.getLocVT();
326-
const TargetRegisterClass *RC;
327332

328-
if (RegVT == MVT::i32)
329-
RC = &Xtensa::ARRegClass;
330-
else
333+
if (RegVT != MVT::i32)
331334
report_fatal_error("RegVT not supported by FormalArguments Lowering");
332335

333336
// Transform the arguments stored on
334337
// physical registers into virtual ones
335-
unsigned Register = MF.addLiveIn(VA.getLocReg(), RC);
336-
SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Register, RegVT);
338+
Register Reg = MF.addLiveIn(VA.getLocReg(), &Xtensa::ARRegClass);
339+
SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegVT);
337340

338341
// If this is an 8 or 16-bit value, it has been passed promoted
339342
// to 32 bits. Insert an assert[sz]ext to capture this, then
@@ -378,6 +381,56 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
378381
}
379382
}
380383

384+
if (IsVarArg) {
385+
unsigned Idx = CCInfo.getFirstUnallocated(IntRegs);
386+
unsigned ArgRegsNum = std::size(IntRegs);
387+
const TargetRegisterClass *RC = &Xtensa::ARRegClass;
388+
MachineFrameInfo &MFI = MF.getFrameInfo();
389+
MachineRegisterInfo &RegInfo = MF.getRegInfo();
390+
unsigned RegSize = 4;
391+
MVT RegTy = MVT::i32;
392+
MVT FITy = getFrameIndexTy(DAG.getDataLayout());
393+
394+
XtensaFI->setVarArgsFirstGPR(Idx + 2); // 2 - number of a2 register
395+
396+
XtensaFI->setVarArgsOnStackFrameIndex(
397+
MFI.CreateFixedObject(4, CCInfo.getStackSize(), true));
398+
399+
// Offset of the first variable argument from stack pointer, and size of
400+
// the vararg save area. For now, the varargs save area is either zero or
401+
// large enough to hold a0-a7.
402+
int VaArgOffset, VarArgsSaveSize;
403+
404+
// If all registers are allocated, then all varargs must be passed on the
405+
// stack and we don't need to save any argregs.
406+
if (ArgRegsNum == Idx) {
407+
VaArgOffset = CCInfo.getStackSize();
408+
VarArgsSaveSize = 0;
409+
} else {
410+
VarArgsSaveSize = RegSize * (ArgRegsNum - Idx);
411+
VaArgOffset = -VarArgsSaveSize;
412+
413+
// Record the frame index of the first variable argument
414+
// which is a value necessary to VASTART.
415+
int FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);
416+
XtensaFI->setVarArgsInRegsFrameIndex(FI);
417+
418+
// Copy the integer registers that may have been used for passing varargs
419+
// to the vararg save area.
420+
for (unsigned I = Idx; I < ArgRegsNum; ++I, VaArgOffset += RegSize) {
421+
const Register Reg = RegInfo.createVirtualRegister(RC);
422+
RegInfo.addLiveIn(IntRegs[I], Reg);
423+
424+
SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegTy);
425+
FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);
426+
SDValue PtrOff = DAG.getFrameIndex(FI, FITy);
427+
SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
428+
MachinePointerInfo::getFixedStack(MF, FI));
429+
OutChains.push_back(Store);
430+
}
431+
}
432+
}
433+
381434
// All stores are grouped in one node to allow the matching between
382435
// the size of Ins and InVals. This only happens when on varg functions
383436
if (!OutChains.empty()) {
@@ -579,9 +632,6 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
579632
const SmallVectorImpl<ISD::OutputArg> &Outs,
580633
const SmallVectorImpl<SDValue> &OutVals,
581634
const SDLoc &DL, SelectionDAG &DAG) const {
582-
if (IsVarArg)
583-
report_fatal_error("VarArg not supported");
584-
585635
MachineFunction &MF = DAG.getMachineFunction();
586636

587637
// Assign locations to each returned value.
@@ -859,6 +909,156 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
859909
return DAG.getMergeValues(Ops, DL);
860910
}
861911

912+
SDValue XtensaTargetLowering::LowerVASTART(SDValue Op,
913+
SelectionDAG &DAG) const {
914+
MachineFunction &MF = DAG.getMachineFunction();
915+
XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
916+
SDValue Chain = Op.getOperand(0);
917+
SDValue Addr = Op.getOperand(1);
918+
EVT PtrVT = Addr.getValueType();
919+
SDLoc DL(Op);
920+
921+
// Struct va_list_tag
922+
// int32 *va_stk - points to the arguments passed in memory
923+
// int32 *va_reg - points to the registers with arguments saved in memory
924+
// int32 va_ndx - offset from va_stk or va_reg pointers which points to the
925+
// next variable argument
926+
927+
SDValue VAIndex;
928+
SDValue StackOffsetFI =
929+
DAG.getFrameIndex(XtensaFI->getVarArgsOnStackFrameIndex(), PtrVT);
930+
unsigned ArgWords = XtensaFI->getVarArgsFirstGPR() - 2;
931+
932+
// If first variable argument passed in registers (maximum words in registers
933+
// is 6) then set va_ndx to the position of this argument in registers area
934+
// stored in memory (va_reg pointer). Otherwise va_ndx should point to the
935+
// position of the first variable argument on stack (va_stk pointer).
936+
if (ArgWords < 6) {
937+
VAIndex = DAG.getConstant(ArgWords * 4, DL, MVT::i32);
938+
} else {
939+
VAIndex = DAG.getConstant(32, DL, MVT::i32);
940+
}
941+
942+
SDValue FrameIndex =
943+
DAG.getFrameIndex(XtensaFI->getVarArgsInRegsFrameIndex(), PtrVT);
944+
uint64_t FrameOffset = PtrVT.getStoreSize();
945+
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
946+
947+
// Store pointer to arguments given on stack (va_stk)
948+
SDValue StackPtr = DAG.getNode(ISD::SUB, DL, PtrVT, StackOffsetFI,
949+
DAG.getConstant(32, DL, PtrVT));
950+
951+
SDValue StoreStackPtr =
952+
DAG.getStore(Chain, DL, StackPtr, Addr, MachinePointerInfo(SV));
953+
954+
uint64_t NextOffset = FrameOffset;
955+
SDValue NextPtr =
956+
DAG.getObjectPtrOffset(DL, Addr, TypeSize::getFixed(NextOffset));
957+
958+
// Store pointer to arguments given on registers (va_reg)
959+
SDValue StoreRegPtr = DAG.getStore(StoreStackPtr, DL, FrameIndex, NextPtr,
960+
MachinePointerInfo(SV, NextOffset));
961+
NextOffset += FrameOffset;
962+
NextPtr = DAG.getObjectPtrOffset(DL, Addr, TypeSize::getFixed(NextOffset));
963+
964+
// Store third word : position in bytes of the first VA argument (va_ndx)
965+
return DAG.getStore(StoreRegPtr, DL, VAIndex, NextPtr,
966+
MachinePointerInfo(SV, NextOffset));
967+
}
968+
969+
SDValue XtensaTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG) const {
970+
// Size of the va_list_tag structure
971+
constexpr unsigned VAListSize = 3 * 4;
972+
SDValue Chain = Op.getOperand(0);
973+
SDValue DstPtr = Op.getOperand(1);
974+
SDValue SrcPtr = Op.getOperand(2);
975+
const Value *DstSV = cast<SrcValueSDNode>(Op.getOperand(3))->getValue();
976+
const Value *SrcSV = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
977+
SDLoc DL(Op);
978+
979+
return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr,
980+
DAG.getConstant(VAListSize, SDLoc(Op), MVT::i32),
981+
Align(4), /*isVolatile*/ false, /*AlwaysInline*/ true,
982+
/*CI=*/nullptr, std::nullopt, MachinePointerInfo(DstSV),
983+
MachinePointerInfo(SrcSV));
984+
}
985+
986+
SDValue XtensaTargetLowering::LowerVAARG(SDValue Op, SelectionDAG &DAG) const {
987+
SDNode *Node = Op.getNode();
988+
EVT VT = Node->getValueType(0);
989+
Type *Ty = VT.getTypeForEVT(*DAG.getContext());
990+
EVT PtrVT = Op.getValueType();
991+
SDValue InChain = Node->getOperand(0);
992+
SDValue VAListPtr = Node->getOperand(1);
993+
const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
994+
SDLoc DL(Node);
995+
auto &TD = DAG.getDataLayout();
996+
Align ArgAlignment = TD.getABITypeAlign(Ty);
997+
unsigned ArgAlignInBytes = ArgAlignment.value();
998+
unsigned ArgSizeInBytes = TD.getTypeAllocSize(Ty);
999+
unsigned VASizeInBytes = llvm::alignTo(ArgSizeInBytes, 4);
1000+
1001+
// va_stk
1002+
SDValue VAStack =
1003+
DAG.getLoad(MVT::i32, DL, InChain, VAListPtr, MachinePointerInfo());
1004+
InChain = VAStack.getValue(1);
1005+
1006+
// va_reg
1007+
SDValue VARegPtr =
1008+
DAG.getObjectPtrOffset(DL, VAListPtr, TypeSize::getFixed(4));
1009+
SDValue VAReg =
1010+
DAG.getLoad(MVT::i32, DL, InChain, VARegPtr, MachinePointerInfo());
1011+
InChain = VAReg.getValue(1);
1012+
1013+
// va_ndx
1014+
SDValue VarArgIndexPtr =
1015+
DAG.getObjectPtrOffset(DL, VARegPtr, TypeSize::getFixed(4));
1016+
SDValue VAIndex =
1017+
DAG.getLoad(MVT::i32, DL, InChain, VarArgIndexPtr, MachinePointerInfo());
1018+
InChain = VAIndex.getValue(1);
1019+
1020+
SDValue OrigIndex = VAIndex;
1021+
1022+
if (ArgAlignInBytes > 4) {
1023+
OrigIndex = DAG.getNode(ISD::ADD, DL, PtrVT, OrigIndex,
1024+
DAG.getConstant(ArgAlignInBytes - 1, DL, MVT::i32));
1025+
OrigIndex =
1026+
DAG.getNode(ISD::AND, DL, PtrVT, OrigIndex,
1027+
DAG.getSignedConstant(-ArgAlignInBytes, DL, MVT::i32));
1028+
}
1029+
1030+
VAIndex = DAG.getNode(ISD::ADD, DL, PtrVT, OrigIndex,
1031+
DAG.getConstant(VASizeInBytes, DL, MVT::i32));
1032+
1033+
SDValue CC = DAG.getSetCC(DL, MVT::i32, OrigIndex,
1034+
DAG.getConstant(6 * 4, DL, MVT::i32), ISD::SETLE);
1035+
1036+
SDValue StkIndex =
1037+
DAG.getNode(ISD::ADD, DL, PtrVT, VAIndex,
1038+
DAG.getConstant(32 + VASizeInBytes, DL, MVT::i32));
1039+
1040+
CC = DAG.getSetCC(DL, MVT::i32, VAIndex, DAG.getConstant(6 * 4, DL, MVT::i32),
1041+
ISD::SETLE);
1042+
1043+
SDValue Array = DAG.getNode(ISD::SELECT, DL, MVT::i32, CC, VAReg, VAStack);
1044+
1045+
VAIndex = DAG.getNode(ISD::SELECT, DL, MVT::i32, CC, VAIndex, StkIndex);
1046+
1047+
CC = DAG.getSetCC(DL, MVT::i32, VAIndex, DAG.getConstant(6 * 4, DL, MVT::i32),
1048+
ISD::SETLE);
1049+
1050+
SDValue VAIndexStore = DAG.getStore(InChain, DL, VAIndex, VarArgIndexPtr,
1051+
MachinePointerInfo(SV));
1052+
InChain = VAIndexStore;
1053+
1054+
SDValue Addr = DAG.getNode(ISD::SUB, DL, PtrVT, VAIndex,
1055+
DAG.getConstant(VASizeInBytes, DL, MVT::i32));
1056+
1057+
Addr = DAG.getNode(ISD::ADD, DL, PtrVT, Array, Addr);
1058+
1059+
return DAG.getLoad(VT, DL, InChain, Addr, MachinePointerInfo());
1060+
}
1061+
8621062
SDValue XtensaTargetLowering::LowerShiftLeftParts(SDValue Op,
8631063
SelectionDAG &DAG) const {
8641064
SDLoc DL(Op);
@@ -1001,6 +1201,12 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
10011201
return LowerFRAMEADDR(Op, DAG);
10021202
case ISD::DYNAMIC_STACKALLOC:
10031203
return LowerDYNAMIC_STACKALLOC(Op, DAG);
1204+
case ISD::VASTART:
1205+
return LowerVASTART(Op, DAG);
1206+
case ISD::VAARG:
1207+
return LowerVAARG(Op, DAG);
1208+
case ISD::VACOPY:
1209+
return LowerVACOPY(Op, DAG);
10041210
case ISD::SHL_PARTS:
10051211
return LowerShiftLeftParts(Op, DAG);
10061212
case ISD::SRA_PARTS:

llvm/lib/Target/Xtensa/XtensaISelLowering.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ class XtensaTargetLowering : public TargetLowering {
148148

149149
SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const;
150150

151+
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
152+
153+
SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const;
154+
155+
SDValue LowerVACOPY(SDValue Op, SelectionDAG &DAG) const;
156+
151157
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
152158

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

llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,32 @@ 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 VarArgsOnStackFrameIndex;
29+
int VarArgsInRegsFrameIndex;
2730

2831
public:
2932
explicit XtensaMachineFunctionInfo(const Function &F,
30-
const TargetSubtargetInfo *STI) {}
33+
const TargetSubtargetInfo *STI)
34+
: VarArgsFirstGPR(0), VarArgsOnStackFrameIndex(0),
35+
VarArgsInRegsFrameIndex(0) {}
3136

3237
int getBranchRelaxationScratchFrameIndex() const {
3338
return BranchRelaxationScratchFrameIndex;
3439
}
3540
void setBranchRelaxationScratchFrameIndex(int Index) {
3641
BranchRelaxationScratchFrameIndex = Index;
3742
}
43+
44+
unsigned getVarArgsFirstGPR() const { return VarArgsFirstGPR; }
45+
void setVarArgsFirstGPR(unsigned GPR) { VarArgsFirstGPR = GPR; }
46+
47+
int getVarArgsOnStackFrameIndex() const { return VarArgsOnStackFrameIndex; }
48+
void setVarArgsOnStackFrameIndex(int FI) { VarArgsOnStackFrameIndex = FI; }
49+
50+
// Get and set the frame index of the first stack vararg.
51+
int getVarArgsInRegsFrameIndex() const { return VarArgsInRegsFrameIndex; }
52+
void setVarArgsInRegsFrameIndex(int FI) { VarArgsInRegsFrameIndex = FI; }
3853
};
3954

4055
} // namespace llvm

0 commit comments

Comments
 (0)