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+
220231static 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+
8621062SDValue 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:
0 commit comments