[llvm] [Xtensa] Implement base CallConvention. (PR #83280)
Andrei Safronov via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 7 16:56:26 PST 2024
================
@@ -41,10 +41,273 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setMinFunctionAlignment(Align(4));
+ setBooleanContents(ZeroOrOneBooleanContent);
+
+ // 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);
+ }
+
// 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 Reg;
+
+ 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) {
+ Reg = 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 &&
+ (Reg == Xtensa::A3 || Reg == Xtensa::A5 || Reg == Xtensa::A7))
+ Reg = State.AllocateReg(IntRegs);
+ // arguments with 16byte alignment must be passed in the first register or
+ // passed via stack
+ if (needs128BitAlign && Reg != Xtensa::A2)
+ while ((Reg = State.AllocateReg(IntRegs)))
+ ;
+ LocVT = MVT::i32;
+ } else if (ValVT == MVT::f64) {
+ // Allocate int register and shadow next int register.
+ Reg = State.AllocateReg(IntRegs);
+ if (Reg == Xtensa::A3 || Reg == Xtensa::A5 || Reg == Xtensa::A7)
+ Reg = State.AllocateReg(IntRegs);
+ State.AllocateReg(IntRegs);
+ LocVT = MVT::i32;
+ } else {
+ report_fatal_error("Cannot handle this ValVT.");
+ }
+
+ if (!Reg) {
+ unsigned Offset = State.AllocateStack(ValVT.getStoreSize(), OrigAlign);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ } else {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ }
+
+ return false;
+}
+
+CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC,
+ bool IsVarArg) const {
+ return CC_Xtensa_Custom;
+}
+
+// Value is a value of type VA.getValVT() that we need to copy into
+// the location described by VA. Return a copy of Value converted to
+// VA.getValVT(). The caller is responsible for handling indirect values.
+static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDLoc DL, CCValAssign &VA,
+ SDValue Value) {
+ switch (VA.getLocInfo()) {
+ case CCValAssign::SExt:
+ return DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Value);
+ case CCValAssign::ZExt:
+ return DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Value);
+ case CCValAssign::AExt:
+ return DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Value);
+ case CCValAssign::BCvt:
+ return DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Value);
+ case CCValAssign::Full:
+ return Value;
+ default:
+ report_fatal_error("Unhandled getLocInfo()");
+ }
+}
+
+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;
+}
+
+bool XtensaTargetLowering::CanLowerReturn(
+ CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
+ return CCInfo.CheckReturn(Outs, RetCC_Xtensa);
+}
+
+SDValue
+XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
+ bool IsVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ const SDLoc &DL, SelectionDAG &DAG) const {
+ if (IsVarArg)
+ report_fatal_error("VarArg not supported");
+
+ MachineFunction &MF = DAG.getMachineFunction();
+
+ // Assign locations to each returned value.
+ SmallVector<CCValAssign, 16> RetLocs;
+ CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());
+ RetCCInfo.AnalyzeReturn(Outs, RetCC_Xtensa);
+
+ SDValue Glue;
+ // Quick exit for void returns
+ if (RetLocs.empty())
+ return DAG.getNode(XtensaISD::RET, DL, MVT::Other, Chain);
+
+ // Copy the result values into the output registers.
+ SmallVector<SDValue, 4> RetOps;
+ RetOps.push_back(Chain);
+ for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) {
+ CCValAssign &VA = RetLocs[I];
+ SDValue RetValue = OutVals[I];
+
+ // Make the return register live on exit.
+ assert(VA.isRegLoc() && "Can only return in registers!");
+
+ // Promote the value as required.
+ RetValue = convertValVTToLocVT(DAG, DL, VA, RetValue);
+
+ // Chain and glue the copies together.
+ unsigned Reg = VA.getLocReg();
----------------
andreisfr wrote:
@arsenm , thank you very much for comments. Corrected
https://github.com/llvm/llvm-project/pull/83280
More information about the llvm-commits
mailing list