|
14 | 14 | #include "XtensaISelLowering.h"
|
15 | 15 | #include "XtensaConstantPoolValue.h"
|
16 | 16 | #include "XtensaInstrInfo.h"
|
| 17 | +#include "XtensaMachineFunctionInfo.h" |
17 | 18 | #include "XtensaSubtarget.h"
|
18 | 19 | #include "XtensaTargetMachine.h"
|
19 | 20 | #include "llvm/CodeGen/CallingConvLower.h"
|
@@ -133,6 +134,14 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
|
133 | 134 | setOperationAction(ISD::STACKSAVE, MVT::Other, Custom);
|
134 | 135 | setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom);
|
135 | 136 |
|
| 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 | + |
136 | 145 | // Compute derived properties from the register classes
|
137 | 146 | computeRegisterProperties(STI.getRegisterInfo());
|
138 | 147 | }
|
@@ -211,6 +220,11 @@ void XtensaTargetLowering::LowerAsmOperandForConstraint(
|
211 | 220 | TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
|
212 | 221 | }
|
213 | 222 |
|
| 223 | +unsigned XtensaTargetLowering::getVaListSizeInBits(const DataLayout &DL) const { |
| 224 | + // 2 * sizeof(int*) + sizeof(int) |
| 225 | + return 3 * 4; |
| 226 | +} |
| 227 | + |
214 | 228 | //===----------------------------------------------------------------------===//
|
215 | 229 | // Calling conventions
|
216 | 230 | //===----------------------------------------------------------------------===//
|
@@ -304,13 +318,14 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
|
304 | 318 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
|
305 | 319 | MachineFunction &MF = DAG.getMachineFunction();
|
306 | 320 | MachineFrameInfo &MFI = MF.getFrameInfo();
|
| 321 | + XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>(); |
| 322 | + EVT PtrVT = getPointerTy(MF.getDataLayout()); |
| 323 | + |
| 324 | + XtensaFI->setVarArgsFrameIndex(0); |
307 | 325 |
|
308 | 326 | // Used with vargs to acumulate store chains.
|
309 | 327 | std::vector<SDValue> OutChains;
|
310 | 328 |
|
311 |
| - if (IsVarArg) |
312 |
| - report_fatal_error("Var arg not supported by FormalArguments Lowering"); |
313 |
| - |
314 | 329 | // Assign locations to all of the incoming arguments.
|
315 | 330 | SmallVector<CCValAssign, 16> ArgLocs;
|
316 | 331 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
|
@@ -378,6 +393,68 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
|
378 | 393 | }
|
379 | 394 | }
|
380 | 395 |
|
| 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 | + |
381 | 458 | // All stores are grouped in one node to allow the matching between
|
382 | 459 | // the size of Ins and InVals. This only happens when on varg functions
|
383 | 460 | if (!OutChains.empty()) {
|
@@ -579,9 +656,6 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
|
579 | 656 | const SmallVectorImpl<ISD::OutputArg> &Outs,
|
580 | 657 | const SmallVectorImpl<SDValue> &OutVals,
|
581 | 658 | const SDLoc &DL, SelectionDAG &DAG) const {
|
582 |
| - if (IsVarArg) |
583 |
| - report_fatal_error("VarArg not supported"); |
584 |
| - |
585 | 659 | MachineFunction &MF = DAG.getMachineFunction();
|
586 | 660 |
|
587 | 661 | // Assign locations to each returned value.
|
@@ -859,6 +933,147 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
|
859 | 933 | return DAG.getMergeValues(Ops, DL);
|
860 | 934 | }
|
861 | 935 |
|
| 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 | + |
862 | 1077 | SDValue XtensaTargetLowering::LowerShiftLeftParts(SDValue Op,
|
863 | 1078 | SelectionDAG &DAG) const {
|
864 | 1079 | SDLoc DL(Op);
|
@@ -1001,6 +1216,12 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
|
1001 | 1216 | return LowerFRAMEADDR(Op, DAG);
|
1002 | 1217 | case ISD::DYNAMIC_STACKALLOC:
|
1003 | 1218 | 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); |
1004 | 1225 | case ISD::SHL_PARTS:
|
1005 | 1226 | return LowerShiftLeftParts(Op, DAG);
|
1006 | 1227 | case ISD::SRA_PARTS:
|
|
0 commit comments