llvm-project/llvm/lib/Target/Foot/FootISelLowering.cpp

438 lines
13 KiB
C++

#include "FootISelLowering.h"
#include "FootCallingConvention.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::SDIV, MVT::i32, Legal);
setOperationAction(ISD::SREM, 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::BR, MVT::i32, Legal);
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
setOperationAction(ISD::SETCC, MVT::i32, Expand);
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);
}
SDValue FootTargetLowering::LowerOperation(SDValue Op,
SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
case ISD::BR_CC:
return LowerBrCC(Op, DAG);
default:
llvm_unreachable("unexpected custom operation");
return SDValue();
}
}
MachineBasicBlock *
FootTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *MBB) const {
switch (MI.getOpcode()) {
case Foot::PSEUDO_SELECT:
return EmitSelect(MI);
default:
llvm_unreachable("custom inserter not yet implemented");
}
}
SDValue FootTargetLowering::LowerBrCC(SDValue Op, SelectionDAG &DAG) const {
assert(Op.getOpcode() == ISD::BR_CC);
SDValue Cmp =
DAG.getNode(FootISD::CMP_CHAIN, SDLoc(Op), MVT::Other, Op.getOperand(0),
Op.getOperand(2), Op.getOperand(3));
assert(isa<CondCodeSDNode>(Op.getOperand(1).getNode()) &&
"CC Must be CondCodeSDNode");
unsigned Opc;
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1).getNode())->get();
switch (CC) {
case ISD::SETLT:
case ISD::SETULT:
Opc = FootISD::BR_L;
break;
case ISD::SETLE:
case ISD::SETULE:
Opc = FootISD::BR_LE;
break;
case ISD::SETEQ:
case ISD::SETUEQ:
Opc = FootISD::BR_E;
break;
case ISD::SETGE:
case ISD::SETUGE:
Opc = FootISD::BR_GE;
break;
case ISD::SETGT:
case ISD::SETUGT:
Opc = FootISD::BR_G;
break;
case ISD::SETNE:
case ISD::SETUNE:
Opc = FootISD::BR_NE;
break;
default:
dbgs() << CC << "\n";
llvm_unreachable("Unexpected condition code");
}
return DAG.getNode(Opc, SDLoc(Op), MVT::Other, {Op.getOperand(4), Cmp});
}
MachineBasicBlock *FootTargetLowering::EmitSelect(MachineInstr &MI) const {
MachineBasicBlock &MBB = *MI.getParent();
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(Foot::CMPR_D_D_A))
.addReg(MI.getOperand(2).getReg())
.addReg(MI.getOperand(1).getReg());
unsigned OpcTrue;
unsigned OpcFalse;
// this should probably use enums instead
// refer to DOCS.txt in the other repo
switch (MI.getOperand(5).getImm()) {
case 1:
OpcTrue = Foot::COPY_D_D_L;
OpcFalse = Foot::COPY_D_D_GE;
break;
case 2:
OpcTrue = Foot::COPY_D_D_LE;
OpcFalse = Foot::COPY_D_D_G;
break;
case 3:
OpcTrue = Foot::COPY_D_D_E;
OpcFalse = Foot::COPY_D_D_NE;
break;
case 4:
OpcTrue = Foot::COPY_D_D_GE;
OpcFalse = Foot::COPY_D_D_L;
break;
case 5:
OpcTrue = Foot::COPY_D_D_G;
OpcFalse = Foot::COPY_D_D_LE;
break;
case 6:
OpcTrue = Foot::COPY_D_D_NE;
OpcFalse = Foot::COPY_D_D_E;
break;
}
Register Out = MI.getOperand(0).getReg();
BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(OpcTrue), Out)
.addReg(MI.getOperand(3).getReg());
BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(OpcFalse))
.addReg(Out)
.addReg(MI.getOperand(4).getReg());
MI.eraseFromParent();
return &MBB;
}