422 lines
13 KiB
C++
422 lines
13 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::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);
|
|
|
|
computeRegisterProperties(Subtarget.getRegisterInfo());
|
|
}
|
|
|
|
const char *FootTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|
switch (Opcode) {
|
|
case FootISD::FIRST_NUMBER:
|
|
break;
|
|
case FootISD::CALL:
|
|
return "FootISD::CALL";
|
|
case FootISD::CMP:
|
|
return "FootISD::CMP";
|
|
}
|
|
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(1).getReg())
|
|
.addReg(MI.getOperand(2).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;
|
|
}
|