llvm-project/llvm/lib/Target/Foot/FootISelLowering.cpp
2025-10-21 18:25:06 -04:00

319 lines
11 KiB
C++

#include "FootCallingConvention.h"
#include "FootISelLowering.h"
#include "FootSubtarget.h"
#include "MCTargetDesc/FootMCTargetDesc.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
using namespace llvm;
FootTargetLowering::FootTargetLowering(const TargetMachine &TM,
const FootSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
addRegisterClass(MVT::i32, &Foot::GP32RegClass);
//addRegisterClass(MVT::v2i16, &Foot::GP32RegClass);
//addRegisterClass(MVT::v4i8, &Foot::GP32RegClass);
setOperationAction(ISD::ADD, MVT::i32, Legal);
setOperationAction(ISD::SUB, MVT::i32, Legal);
setOperationAction(ISD::MUL, MVT::i32, Legal);
setOperationAction(ISD::UDIV, MVT::i32, Legal);
setOperationAction(ISD::UREM, MVT::i32, Legal);
setOperationAction(ISD::SHL, MVT::i32, Legal);
setOperationAction(ISD::ROTL, MVT::i32, Legal);
setOperationAction(ISD::SRA, MVT::i32, Legal);
setOperationAction(ISD::OR, MVT::i32, Legal);
setOperationAction(ISD::AND, MVT::i32, Legal);
setOperationAction(ISD::XOR, MVT::i32, Legal);
setOperationAction(ISD::STORE, MVT::i32, Legal);
setOperationAction(ISD::LOAD, MVT::i32, Legal);
/*
setOperationAction(ISD::ADD, MVT::v2i16, Legal);
setOperationAction(ISD::SUB, MVT::v2i16, Legal);
setOperationAction(ISD::MUL, MVT::v2i16, Legal);
setOperationAction(ISD::UDIV, MVT::v2i16, Legal);
setOperationAction(ISD::OR, MVT::v2i16, Legal);
setOperationAction(ISD::AND, MVT::v2i16, Legal);
setOperationAction(ISD::XOR, MVT::v2i16, Legal);
setOperationAction(ISD::ADD, MVT::v4i8, Legal);
setOperationAction(ISD::SUB, MVT::v4i8, Legal);
setOperationAction(ISD::MUL, MVT::v4i8, Legal);
setOperationAction(ISD::UDIV, MVT::v4i8, Legal);
setOperationAction(ISD::UREM, MVT::v4i8, Legal);
setOperationAction(ISD::OR, MVT::v4i8, Legal);
setOperationAction(ISD::AND, MVT::v4i8, Legal);
setOperationAction(ISD::XOR, MVT::v4i8, Legal);
setOperationAction(ISD::FADD, MVT::f32, LibCall);
setOperationAction(ISD::FSUB, MVT::f32, LibCall);
setOperationAction(ISD::FMUL, MVT::f32, LibCall);
setOperationAction(ISD::FDIV, MVT::f32, LibCall);
setOperationAction(ISD::FREM, MVT::f32, LibCall);
*/
computeRegisterProperties(Subtarget.getRegisterInfo());
}
const char *FootTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch (Opcode) {
case FootISD::FIRST_NUMBER:
break;
case FootISD::CALL:
return "FootISD::CALL";
}
return nullptr;
}
SDValue FootTargetLowering::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();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
MachineFrameInfo &MFI = MF.getFrameInfo();
MFI.CreateFixedObject(4, 0, true);
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
CCInfo.AnalyzeFormalArguments(Ins, CC_Foot_Common);
for (size_t I = 0; I < ArgLocs.size(); ++I) {
auto &VA = ArgLocs[I];
SDValue ArgValue;
if (VA.isRegLoc()) {
if (VA.getLocInfo() != CCValAssign::Full) {
report_fatal_error("non-full passing, not yet implemented");
}
EVT RegVT = VA.getLocVT();
// no special logic for selecting register class
// just don't use one of the hardware-reserved registers
// (which aren't part of GP32RegClass anyway)
const TargetRegisterClass *DstRC = &Foot::GP32RegClass;
Register VReg = RegInfo.createVirtualRegister(DstRC);
RegInfo.addLiveIn(VA.getLocReg(), VReg);
ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, RegVT);
}
else {
assert(VA.isMemLoc() && "CCValAssign is neither reg nor mem");
unsigned ArgOffset = VA.getLocMemOffset();
if (VA.getLocInfo() != CCValAssign::Full) {
report_fatal_error("only values are supported directly in the stack");
}
unsigned ArgSize = VA.getValVT().getSizeInBits() / 8;
int FrameIndex = MFI.CreateFixedObject(ArgSize, ArgOffset, true);
SDValue FrameIdxNode = DAG.getFrameIndex(FrameIndex, getPointerTy(DAG.getDataLayout()));
MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex);
ISD::LoadExtType ExtType = ISD::NON_EXTLOAD;
MVT MemVT = VA.getValVT();
ArgValue = DAG.getExtLoad(ExtType, DL, VA.getLocVT(), Chain, FrameIdxNode, PtrInfo, MemVT);
}
InVals.push_back(ArgValue);
}
return Chain;
}
SDValue FootTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
SelectionDAG &DAG) const {
SmallVector<CCValAssign> RetValLocs;
MachineFunction &MF = DAG.getMachineFunction();
CCState CCInfo(CallConv, IsVarArg, MF, RetValLocs, *DAG.getContext());
CCInfo.AnalyzeReturn(Outs, RetCC_Foot_Common);
SDValue Glue;
SmallVector<SDValue> RetOps(1, Chain);
for (size_t I = 0, E = RetValLocs.size(); I != E; ++I) {
CCValAssign &VA = RetValLocs[I];
assert(VA.isRegLoc() && "stack return not yet implemented");
assert(VA.getLocInfo() == CCValAssign::Full &&
"extension/truncation of any sort is not yet implemented");
Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[I], Glue);
// guarantee that all emitted copies are 'stuck together'
Glue = Chain.getValue(1);
if (Glue) {
RetOps.push_back(Glue);
}
}
SDNode *NewNode = DAG.getMachineNode(Foot::PSEUDO_RET, DL, MVT::Other, RetOps);
return SDValue(NewNode, 0);
}
SDValue FootTargetLowering::LowerCall(CallLoweringInfo &CLI, SmallVectorImpl<SDValue> &InVals) const {
SelectionDAG &DAG = CLI.DAG;
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;
CallingConv::ID CallConv = CLI.CallConv;
MachineFunction &MF = DAG.getMachineFunction();
SDLoc &DL = CLI.DL;
// Tail-call optimization is not supported yet
CLI.IsTailCall = false;
if (CLI.IsVarArg) {
report_fatal_error("Var args not yet implemented");
}
bool IsVarArg = false;
switch (CallConv) {
default:
report_fatal_error("unsupported callling convention: " + Twine(CallConv));
case CallingConv::Fast:
case CallingConv::C:
break;
}
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
CCInfo.AnalyzeCallOperands(Outs, CC_Foot_Common);
unsigned NumBytes = CCInfo.getStackSize();
for (const ISD::OutputArg &Out : Outs) {
ISD::ArgFlagsTy OutFlags = Out.Flags;
if (OutFlags.isByVal()) {
report_fatal_error("Unsupported attribute");
}
}
SDValue InGlue;
auto PtrVT = getPointerTy(MF.getDataLayout());
Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, DL);
SDValue StackPtr = DAG.getCopyFromReg(Chain, DL, Foot::RSP, getPointerTy(DAG.getDataLayout()));
SmallVector<std::pair<Register, SDValue>> RegsToPass;
SmallVector<SDValue, 8> MemOpChains;
for (size_t I = 0, E = ArgLocs.size(); I != E; ++I) {
CCValAssign &VA = ArgLocs[I];
SDValue &Arg = OutVals[I];
if (VA.getLocInfo() != CCValAssign::Full) {
report_fatal_error("extensions not yet implemented: " + Twine(VA.getLocInfo()));
}
if (VA.isRegLoc()) {
RegsToPass.emplace_back(VA.getLocReg(), Arg);
continue;
}
assert(VA.isMemLoc() && "Expected stack argument");
SDValue DstAddr;
MachinePointerInfo DstInfo;
unsigned OpSize = VA.getValVT().getSizeInBits();
// round up to nearest byte count
OpSize = (OpSize + 7) / 8;
unsigned LocMemOffset = VA.getLocMemOffset();
SDValue PtrOff = DAG.getIntPtrConstant(LocMemOffset, DL);
// pointer arithmetic
DstAddr = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, PtrOff);
DstInfo = MachinePointerInfo::getStack(MF, LocMemOffset);
SDValue Store = DAG.getStore(Chain, DL, Arg, DstAddr, DstInfo);
MemOpChains.push_back(Store);
}
if (!MemOpChains.empty()) {
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
}
for (auto& RegToPass : RegsToPass) {
Chain = DAG.getCopyToReg(Chain, DL, RegToPass.first, RegToPass.second, InGlue);
InGlue = Chain.getValue(1);
}
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVT, G->getOffset(), 0);
}
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, 0);
}
else {
report_fatal_error("Other calls not supported");
}
SmallVector<SDValue, 8> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
for (auto &Reg : RegsToPass) {
Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
}
const TargetRegisterInfo &TRI = *Subtarget.getRegisterInfo();
const uint32_t *Mask = TRI.getCallPreservedMask(MF, CallConv);
assert(Mask && "Missing call preserved mask for calling convention");
Ops.push_back(DAG.getRegisterMask(Mask));
if (InGlue.getNode()) {
Ops.push_back(InGlue);
}
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
Chain = DAG.getNode(FootISD::CALL, DL, NodeTys, Ops);
InGlue = Chain.getValue(1);
DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, InGlue, DL);
InGlue = Chain.getValue(1);
SmallVector<CCValAssign, 16> RetValLocs;
CCState CCRetInfo(CallConv, IsVarArg, MF, RetValLocs, *DAG.getContext());
CCRetInfo.AnalyzeCallResult(Ins, RetCC_Foot_Common);
for (size_t I = 0, E = RetValLocs.size(); I != E; ++I) {
CCValAssign &VA = RetValLocs[I];
assert(VA.isRegLoc() && "stack return not yet implemented");
assert(VA.getLocInfo() == CCValAssign::Full && "extension/truncation not yet implemented");
Chain = DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getValVT(), InGlue)
.getValue(1);
InGlue = Chain.getValue(2);
InVals.push_back(Chain.getValue(0));
}
return Chain;
}
bool FootTargetLowering::CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
const Type *RetTy) const {
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs,
MF.getFunction().getContext());
return !IsVarArg && CCInfo.CheckReturn(Outs, RetCC_Foot_Common);
}