[llvm] [Xtensa] Implement base CallConvention. (PR #83280)
Sergei Barannikov via llvm-commits
llvm-commits at lists.llvm.org
Sat Mar 23 17:07:29 PDT 2024
================
@@ -41,18 +52,507 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setMinFunctionAlignment(Align(4));
+ setOperationAction(ISD::Constant, MVT::i32, Custom);
+ setOperationAction(ISD::Constant, MVT::i64, Expand);
+
+ setBooleanContents(ZeroOrOneBooleanContent);
+
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
+
+ setOperationAction(ISD::BITCAST, MVT::i32, Expand);
+ setOperationAction(ISD::BITCAST, MVT::f32, Expand);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand);
+
+ // No sign extend instructions for i1
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
+ setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote);
+ setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote);
+ }
+
+ setOperationAction(ISD::ConstantPool, PtrVT, Custom);
+
// Compute derived properties from the register classes
computeRegisterProperties(STI.getRegisterInfo());
}
+//===----------------------------------------------------------------------===//
+// Calling conventions
+//===----------------------------------------------------------------------===//
+
+#include "XtensaGenCallingConv.inc"
+
+static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT,
+ CCValAssign::LocInfo LocInfo,
+ ISD::ArgFlagsTy ArgFlags, CCState &State) {
+ static const MCPhysReg IntRegs[] = {Xtensa::A2, Xtensa::A3, Xtensa::A4,
+ Xtensa::A5, Xtensa::A6, Xtensa::A7};
+
+ if (ArgFlags.isByVal()) {
+ Align ByValAlign = ArgFlags.getNonZeroByValAlign();
+ unsigned ByValSize = ArgFlags.getByValSize();
+ if (ByValSize < 4) {
+ ByValSize = 4;
+ }
+ if (ByValAlign < Align(4)) {
+ ByValAlign = Align(4);
+ }
+ unsigned Offset = State.AllocateStack(ByValSize, ByValAlign);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ // Mark all unused registers as allocated to avoid misuse
+ // of such registers.
+ while (State.AllocateReg(IntRegs))
+ ;
+ return false;
+ }
+
+ // Promote i8 and i16
+ if (LocVT == MVT::i8 || LocVT == MVT::i16) {
+ LocVT = MVT::i32;
+ if (ArgFlags.isSExt())
+ LocInfo = CCValAssign::SExt;
+ else if (ArgFlags.isZExt())
+ LocInfo = CCValAssign::ZExt;
+ else
+ LocInfo = CCValAssign::AExt;
+ }
+
+ unsigned Register;
+
+ Align OrigAlign = ArgFlags.getNonZeroOrigAlign();
+ bool needs64BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(8));
+ bool needs128BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(16));
+
+ if (ValVT == MVT::i32 || ValVT == MVT::f32) {
+ Register = State.AllocateReg(IntRegs);
+ // If this is the first part of an i64 arg,
+ // the allocated register must be either A2, A4 or A6.
+ if (needs64BitAlign && (Register == Xtensa::A3 || Register == Xtensa::A5 ||
+ Register == Xtensa::A7))
+ Register = State.AllocateReg(IntRegs);
+ // arguments with 16byte alignment must be passed in the first register or
+ // passed via stack
+ if (needs128BitAlign && (Register != Xtensa::A2))
+ while ((Register = State.AllocateReg(IntRegs)))
+ ;
+ LocVT = MVT::i32;
+ } else if (ValVT == MVT::f64) {
+ // Allocate int register and shadow next int register.
+ Register = State.AllocateReg(IntRegs);
+ if (Register == Xtensa::A3 || Register == Xtensa::A5 ||
+ Register == Xtensa::A7)
+ Register = State.AllocateReg(IntRegs);
+ State.AllocateReg(IntRegs);
+ LocVT = MVT::i32;
+ } else {
+ report_fatal_error("Cannot handle this ValVT.");
+ }
+
+ if (!Register) {
+ unsigned Offset = State.AllocateStack(ValVT.getStoreSize(), OrigAlign);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ } else {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Register, LocVT, LocInfo));
+ }
+
+ return false;
+}
+
+CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC,
+ bool IsVarArg) const {
+ return CC_Xtensa_Custom;
+}
+
+SDValue XtensaTargetLowering::LowerFormalArguments(
+ SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
+ SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+
+ // Used with vargs to acumulate store chains.
+ std::vector<SDValue> OutChains;
+
+ if (IsVarArg)
+ report_fatal_error("Var arg not supported by FormalArguments Lowering");
+
+ // Assign locations to all of the incoming arguments.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+
+ CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg));
+
+ for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ CCValAssign &VA = ArgLocs[i];
+ // Arguments stored on registers
+ if (VA.isRegLoc()) {
+ EVT RegVT = VA.getLocVT();
+ const TargetRegisterClass *RC;
+
+ if (RegVT == MVT::i32)
+ RC = &Xtensa::ARRegClass;
+ else
+ report_fatal_error("RegVT not supported by FormalArguments Lowering");
+
+ // Transform the arguments stored on
+ // physical registers into virtual ones
+ unsigned Register = MF.addLiveIn(VA.getLocReg(), RC);
+ SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Register, RegVT);
+
+ // If this is an 8 or 16-bit value, it has been passed promoted
+ // to 32 bits. Insert an assert[sz]ext to capture this, then
+ // truncate to the right size.
+ if (VA.getLocInfo() != CCValAssign::Full) {
+ unsigned Opcode = 0;
+ if (VA.getLocInfo() == CCValAssign::SExt)
+ Opcode = ISD::AssertSext;
+ else if (VA.getLocInfo() == CCValAssign::ZExt)
+ Opcode = ISD::AssertZext;
+ if (Opcode)
+ ArgValue = DAG.getNode(Opcode, DL, RegVT, ArgValue,
+ DAG.getValueType(VA.getValVT()));
+ ArgValue = DAG.getNode((VA.getValVT() == MVT::f32) ? ISD::BITCAST
+ : ISD::TRUNCATE,
+ DL, VA.getValVT(), ArgValue);
+ }
+
+ InVals.push_back(ArgValue);
+
+ } else {
+ assert(VA.isMemLoc());
+
+ EVT ValVT = VA.getValVT();
+
+ // The stack pointer offset is relative to the caller stack frame.
+ int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
+ true);
+
+ if (Ins[VA.getValNo()].Flags.isByVal()) {
+ // Assume that in this case load operation is created
+ SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
+ InVals.push_back(FIN);
+ } else {
+ // Create load nodes to retrieve arguments from the stack
+ SDValue FIN =
+ DAG.getFrameIndex(FI, getFrameIndexTy(DAG.getDataLayout()));
+ InVals.push_back(DAG.getLoad(
+ ValVT, DL, Chain, FIN,
+ MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)));
+ }
+ }
+ }
+
+ // All stores are grouped in one node to allow the matching between
+ // the size of Ins and InVals. This only happens when on varg functions
+ if (!OutChains.empty()) {
+ OutChains.push_back(Chain);
+ Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
+ }
+
+ return Chain;
+}
+
+SDValue
+XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const {
+ SelectionDAG &DAG = CLI.DAG;
+ SDLoc &DL = CLI.DL;
+ SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs;
+ SmallVector<SDValue, 32> &OutVals = CLI.OutVals;
+ SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins;
+ SDValue Chain = CLI.Chain;
+ SDValue Callee = CLI.Callee;
+ bool &IsTailCall = CLI.IsTailCall;
+ CallingConv::ID CallConv = CLI.CallConv;
+ bool IsVarArg = CLI.IsVarArg;
+
+ MachineFunction &MF = DAG.getMachineFunction();
+ EVT PtrVT = getPointerTy(DAG.getDataLayout());
+ const TargetFrameLowering *TFL = Subtarget.getFrameLowering();
+
+ // TODO: Support tail call optimization.
+ IsTailCall = false;
+
+ // Analyze the operands of the call, assigning locations to each operand.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
+
+ CCAssignFn *CC = CCAssignFnForCall(CallConv, IsVarArg);
+
+ CCInfo.AnalyzeCallOperands(Outs, CC);
+
+ // Get a count of how many bytes are to be pushed on the stack.
+ unsigned NumBytes = CCInfo.getStackSize();
+
+ unsigned StackAlignment = TFL->getStackAlignment();
----------------
s-barannikov wrote:
The method is deprecated, consider using `getStackAlign`.
https://github.com/llvm/llvm-project/pull/83280
More information about the llvm-commits
mailing list