[llvm] [Xtensa] Implement vararg support. (PR #117126)
Andrei Safronov via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 11 11:08:24 PST 2024
================
@@ -859,6 +909,155 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
return DAG.getMergeValues(Ops, DL);
}
+SDValue XtensaTargetLowering::LowerVASTART(SDValue Op,
+ SelectionDAG &DAG) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
+ SDValue Chain = Op.getOperand(0);
+ SDValue Addr = Op.getOperand(1);
+ EVT PtrVT = Addr.getValueType();
+ SDLoc DL(Op);
+
+ // Struct va_list_tag
+ // int32 *va_stk - points to the arguments passed in memory
+ // int32 *va_reg - points to the registers with arguments saved in memory
+ // int32 va_ndx - offset from va_stk or va_reg pointers which points to the
+ // next variable argument
+
+ SDValue VAIndex;
+ SDValue StackOffsetFI =
+ DAG.getFrameIndex(XtensaFI->getVarArgsOnStackFrameIndex(), PtrVT);
+ unsigned ArgWords = XtensaFI->getVarArgsFirstGPR() - 2;
+
+ // If first variable argument passed in registers (maximum words in registers
+ // is 6) then set va_ndx to the position of this argument in registers area
+ // stored in memory (va_reg pointer). Otherwise va_ndx should point to the
+ // position of the first variable argument on stack (va_stk pointer).
+ if (ArgWords < 6) {
+ VAIndex = DAG.getConstant(ArgWords * 4, DL, MVT::i32);
+ } else {
+ VAIndex = DAG.getConstant(32, DL, MVT::i32);
+ }
+
+ SDValue FrameIndex =
+ DAG.getFrameIndex(XtensaFI->getVarArgsInRegsFrameIndex(), PtrVT);
+ uint64_t FrameOffset = PtrVT.getStoreSize();
+ const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
+
+ // Store pointer to arguments given on stack (va_stk)
+ SDValue StackPtr = DAG.getNode(ISD::SUB, DL, PtrVT, StackOffsetFI,
+ DAG.getConstant(32, DL, PtrVT));
+
+ SDValue StoreStackPtr =
+ DAG.getStore(Chain, DL, StackPtr, Addr, MachinePointerInfo(SV));
+
+ uint64_t NextOffset = FrameOffset;
+ SDValue NextPtr =
+ DAG.getObjectPtrOffset(DL, Addr, TypeSize::getFixed(NextOffset));
+
+ // Store pointer to arguments given on registers (va_reg)
+ SDValue StoreRegPtr = DAG.getStore(StoreStackPtr, DL, FrameIndex, NextPtr,
+ MachinePointerInfo(SV, NextOffset));
+ NextOffset += FrameOffset;
+ NextPtr = DAG.getObjectPtrOffset(DL, Addr, TypeSize::getFixed(NextOffset));
+
+ // Store third word : position in bytes of the first VA argument (va_ndx)
+ return DAG.getStore(StoreRegPtr, DL, VAIndex, NextPtr,
+ MachinePointerInfo(SV, NextOffset));
+}
+
+SDValue XtensaTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG) const {
+ // Size of the va_list_tag structure
+ constexpr unsigned VAListSize = 3 * 4;
+ SDValue Chain = Op.getOperand(0);
+ SDValue DstPtr = Op.getOperand(1);
+ SDValue SrcPtr = Op.getOperand(2);
+ const Value *DstSV = cast<SrcValueSDNode>(Op.getOperand(3))->getValue();
+ const Value *SrcSV = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
+ SDLoc DL(Op);
+
+ return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr,
+ DAG.getConstant(VAListSize, SDLoc(Op), MVT::i32),
+ Align(4), /*isVolatile*/ false, /*AlwaysInline*/ true,
+ /*CI=*/nullptr, std::nullopt, MachinePointerInfo(DstSV),
+ MachinePointerInfo(SrcSV));
+}
+
+SDValue XtensaTargetLowering::LowerVAARG(SDValue Op, SelectionDAG &DAG) const {
+ SDNode *Node = Op.getNode();
+ EVT VT = Node->getValueType(0);
+ Type *Ty = VT.getTypeForEVT(*DAG.getContext());
+ EVT PtrVT = Op.getValueType();
+ SDValue InChain = Node->getOperand(0);
+ SDValue VAListPtr = Node->getOperand(1);
+ const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
+ SDLoc DL(Node);
+ auto &TD = DAG.getDataLayout();
+ Align ArgAlignment = TD.getABITypeAlign(Ty);
+ unsigned ArgAlignInBytes = ArgAlignment.value();
+ unsigned ArgSizeInBytes = TD.getTypeAllocSize(Ty);
+ unsigned VASizeInBytes = llvm::alignTo(ArgSizeInBytes, 4);
+
+ // va_stk
+ SDValue VAStack =
+ DAG.getLoad(MVT::i32, DL, InChain, VAListPtr, MachinePointerInfo());
+ InChain = VAStack.getValue(1);
+
+ // va_reg
+ SDValue VARegPtr =
+ DAG.getObjectPtrOffset(DL, VAListPtr, TypeSize::getFixed(4));
+ SDValue VAReg =
+ DAG.getLoad(MVT::i32, DL, InChain, VARegPtr, MachinePointerInfo());
+ InChain = VAReg.getValue(1);
+
+ // va_ndx
+ SDValue VarArgIndexPtr =
+ DAG.getObjectPtrOffset(DL, VARegPtr, TypeSize::getFixed(4));
+ SDValue VAIndex =
+ DAG.getLoad(MVT::i32, DL, InChain, VarArgIndexPtr, MachinePointerInfo());
+ InChain = VAIndex.getValue(1);
+
+ SDValue OrigIndex = VAIndex;
+
+ if (ArgAlignInBytes > 4) {
+ OrigIndex = DAG.getNode(ISD::ADD, DL, PtrVT, OrigIndex,
+ DAG.getConstant(ArgAlignInBytes - 1, DL, MVT::i32));
+ OrigIndex = DAG.getNode(ISD::AND, DL, PtrVT, OrigIndex,
+ DAG.getConstant(-ArgAlignInBytes, DL, MVT::i32));
----------------
andreisfr wrote:
Thank you for comment. Fixed.
https://github.com/llvm/llvm-project/pull/117126
More information about the llvm-commits
mailing list