diff options
Diffstat (limited to 'llvm/lib/Target/ARC/ARCISelLowering.cpp')
-rw-r--r-- | llvm/lib/Target/ARC/ARCISelLowering.cpp | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/llvm/lib/Target/ARC/ARCISelLowering.cpp b/llvm/lib/Target/ARC/ARCISelLowering.cpp new file mode 100644 index 00000000000..6b921cab950 --- /dev/null +++ b/llvm/lib/Target/ARC/ARCISelLowering.cpp @@ -0,0 +1,767 @@ +//===- ARCISelLowering.cpp - ARC DAG Lowering Impl --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ARCTargetLowering class. +// +//===----------------------------------------------------------------------===// + +#include "ARCISelLowering.h" +#include "ARC.h" +#include "ARCMachineFunctionInfo.h" +#include "ARCSubtarget.h" +#include "ARCTargetMachine.h" +#include "MCTargetDesc/ARCInfo.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/Debug.h" +#include <algorithm> + +#define DEBUG_TYPE "arc-lower" + +using namespace llvm; + +static SDValue lowerCallResult(SDValue Chain, SDValue InFlag, + const SmallVectorImpl<CCValAssign> &RVLocs, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals); + +static ARCCC::CondCode ISDCCtoARCCC(ISD::CondCode isdCC) { + switch (isdCC) { + case ISD::SETUEQ: + return ARCCC::EQ; + case ISD::SETUGT: + return ARCCC::HI; + case ISD::SETUGE: + return ARCCC::HS; + case ISD::SETULT: + return ARCCC::LO; + case ISD::SETULE: + return ARCCC::LS; + case ISD::SETUNE: + return ARCCC::NE; + case ISD::SETEQ: + return ARCCC::EQ; + case ISD::SETGT: + return ARCCC::GT; + case ISD::SETGE: + return ARCCC::GE; + case ISD::SETLT: + return ARCCC::LT; + case ISD::SETLE: + return ARCCC::LE; + case ISD::SETNE: + return ARCCC::NE; + default: + llvm_unreachable("Unhandled ISDCC code."); + } +} + +ARCTargetLowering::ARCTargetLowering(const TargetMachine &TM, + const ARCSubtarget &Subtarget) + : TargetLowering(TM), TM(TM), Subtarget(Subtarget) { + // Set up the register classes. + addRegisterClass(MVT::i32, &ARC::GPR32RegClass); + + // Compute derived properties from the register classes + computeRegisterProperties(Subtarget.getRegisterInfo()); + + setStackPointerRegisterToSaveRestore(ARC::SP); + + setSchedulingPreference(Sched::Source); + + // Use i32 for setcc operations results (slt, sgt, ...). + setBooleanContents(ZeroOrOneBooleanContent); + setBooleanVectorContents(ZeroOrOneBooleanContent); + + for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) + setOperationAction(Opc, MVT::i32, Expand); + + // Operations to get us off of the ground. + // Basic. + setOperationAction(ISD::ADD, MVT::i32, Legal); + setOperationAction(ISD::SUB, MVT::i32, Legal); + setOperationAction(ISD::AND, MVT::i32, Legal); + setOperationAction(ISD::SMAX, MVT::i32, Legal); + setOperationAction(ISD::SMIN, MVT::i32, Legal); + + // Need barrel shifter. + setOperationAction(ISD::SHL, MVT::i32, Legal); + setOperationAction(ISD::SRA, MVT::i32, Legal); + setOperationAction(ISD::SRL, MVT::i32, Legal); + setOperationAction(ISD::ROTR, MVT::i32, Legal); + + setOperationAction(ISD::Constant, MVT::i32, Legal); + setOperationAction(ISD::UNDEF, MVT::i32, Legal); + + // Need multiplier + setOperationAction(ISD::MUL, MVT::i32, Legal); + setOperationAction(ISD::MULHS, MVT::i32, Legal); + setOperationAction(ISD::MULHU, MVT::i32, Legal); + setOperationAction(ISD::LOAD, MVT::i32, Legal); + setOperationAction(ISD::STORE, MVT::i32, Legal); + + setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); + setOperationAction(ISD::BR_CC, MVT::i32, Custom); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + + // Have psuedo instruction for frame addresses. + setOperationAction(ISD::FRAMEADDR, MVT::i32, Legal); + // Custom lower global addresses. + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + + // Expand var-args ops. + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + setOperationAction(ISD::VAARG, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Expand); + + // Other expansions + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + // Sign extend inreg + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Custom); +} + +const char *ARCTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + case ARCISD::BL: + return "ARCISD::BL"; + case ARCISD::CMOV: + return "ARCISD::CMOV"; + case ARCISD::CMP: + return "ARCISD::CMP"; + case ARCISD::BRcc: + return "ARCISD::BRcc"; + case ARCISD::RET: + return "ARCISD::RET"; + case ARCISD::GAWRAPPER: + return "ARCISD::GAWRAPPER"; + } + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Misc Lower Operation implementation +//===----------------------------------------------------------------------===// + +SDValue ARCTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); + SDValue TVal = Op.getOperand(2); + SDValue FVal = Op.getOperand(3); + SDLoc dl(Op); + ARCCC::CondCode ArcCC = ISDCCtoARCCC(CC); + assert(LHS.getValueType() == MVT::i32 && "Only know how to SELECT_CC i32"); + SDValue Cmp = DAG.getNode(ARCISD::CMP, dl, MVT::Glue, LHS, RHS); + return DAG.getNode(ARCISD::CMOV, dl, TVal.getValueType(), TVal, FVal, + DAG.getConstant(ArcCC, dl, MVT::i32), Cmp); +} + +SDValue ARCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op, + SelectionDAG &DAG) const { + SDValue Op0 = Op.getOperand(0); + SDLoc dl(Op); + assert(Op.getValueType() == MVT::i32 && + "Unhandled target sign_extend_inreg."); + // These are legal + unsigned Width = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits(); + if (Width == 16 || Width == 8) + return Op; + if (Width >= 32) { + return {}; + } + SDValue LS = DAG.getNode(ISD::SHL, dl, MVT::i32, Op0, + DAG.getConstant(32 - Width, dl, MVT::i32)); + SDValue SR = DAG.getNode(ISD::SRA, dl, MVT::i32, LS, + DAG.getConstant(32 - Width, dl, MVT::i32)); + return SR; +} + +SDValue ARCTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + SDLoc dl(Op); + ARCCC::CondCode arcCC = ISDCCtoARCCC(CC); + assert(LHS.getValueType() == MVT::i32 && "Only know how to BR_CC i32"); + return DAG.getNode(ARCISD::BRcc, dl, MVT::Other, Chain, Dest, LHS, RHS, + DAG.getConstant(arcCC, dl, MVT::i32)); +} + +SDValue ARCTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { + auto *N = cast<JumpTableSDNode>(Op); + SDValue GA = DAG.getTargetJumpTable(N->getIndex(), MVT::i32); + return DAG.getNode(ARCISD::GAWRAPPER, SDLoc(N), MVT::i32, GA); +} + +#include "ARCGenCallingConv.inc" + +//===----------------------------------------------------------------------===// +// Call Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// ARC call implementation +SDValue ARCTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc &dl = CLI.DL; + SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; + SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; + SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + bool &IsTailCall = CLI.IsTailCall; + + IsTailCall = false; // Do not support tail calls yet. + + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + + CCInfo.AnalyzeCallOperands(Outs, CC_ARC); + + SmallVector<CCValAssign, 16> RVLocs; + // Analyze return values to determine the number of bytes of stack required. + CCState RetCCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + RetCCInfo.AllocateStack(CCInfo.getNextStackOffset(), 4); + RetCCInfo.AnalyzeCallResult(Ins, RetCC_ARC); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = RetCCInfo.getNextStackOffset(); + auto PtrVT = getPointerTy(DAG.getDataLayout()); + + Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl); + + SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; + SmallVector<SDValue, 12> MemOpChains; + + SDValue StackPtr; + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + SDValue Arg = OutVals[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: + break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); + break; + } + + // Arguments that can be passed on register must be kept at + // RegsToPass vector + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + } else { + assert(VA.isMemLoc() && "Must be register or memory argument."); + if (!StackPtr.getNode()) + StackPtr = DAG.getCopyFromReg(Chain, dl, ARC::SP, + getPointerTy(DAG.getDataLayout())); + // Calculate the stack position. + SDValue SOffset = DAG.getIntPtrConstant(VA.getLocMemOffset(), dl); + SDValue PtrOff = DAG.getNode( + ISD::ADD, dl, getPointerTy(DAG.getDataLayout()), StackPtr, SOffset); + + SDValue Store = + DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo()); + MemOpChains.push_back(Store); + IsTailCall = false; + } + } + + // Transform all store nodes into one single node because + // all store nodes are independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains); + + // Build a sequence of copy-to-reg nodes chained together with token + // chain and flag operands which copy the outgoing args into registers. + // The InFlag in necessary since all emitted instructions must be + // stuck together. + SDValue Glue; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, + RegsToPass[i].second, Glue); + Glue = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + bool IsDirect = true; + if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32); + else if (auto *E = dyn_cast<ExternalSymbolSDNode>(Callee)) + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); + else + IsDirect = false; + // Branch + Link = #chain, #target_address, #opt_in_flags... + // = Chain, Callee, Reg#1, Reg#2, ... + // + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector<SDValue, 8> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + // Add a register mask operand representing the call-preserved registers. + const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); + const uint32_t *Mask = + TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + if (Glue.getNode()) + Ops.push_back(Glue); + + Chain = DAG.getNode(IsDirect ? ARCISD::BL : ARCISD::JL, dl, NodeTys, Ops); + Glue = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, dl, PtrVT, true), + DAG.getConstant(0, dl, PtrVT, true), Glue, dl); + Glue = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + if (IsTailCall) + return Chain; + return lowerCallResult(Chain, Glue, RVLocs, dl, DAG, InVals); +} + +/// Lower the result values of a call into the appropriate copies out of +/// physical registers / memory locations. +static SDValue lowerCallResult(SDValue Chain, SDValue Glue, + const SmallVectorImpl<CCValAssign> &RVLocs, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) { + SmallVector<std::pair<int, unsigned>, 4> ResultMemLocs; + // Copy results out of physical registers. + for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) { + const CCValAssign &VA = RVLocs[i]; + if (VA.isRegLoc()) { + SDValue RetValue; + RetValue = + DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getValVT(), Glue); + Chain = RetValue.getValue(1); + Glue = RetValue.getValue(2); + InVals.push_back(RetValue); + } else { + assert(VA.isMemLoc() && "Must be memory location."); + ResultMemLocs.push_back( + std::make_pair(VA.getLocMemOffset(), InVals.size())); + + // Reserve space for this result. + InVals.push_back(SDValue()); + } + } + + // Copy results out of memory. + SmallVector<SDValue, 4> MemOpChains; + for (unsigned i = 0, e = ResultMemLocs.size(); i != e; ++i) { + int Offset = ResultMemLocs[i].first; + unsigned Index = ResultMemLocs[i].second; + SDValue StackPtr = DAG.getRegister(ARC::SP, MVT::i32); + SDValue SpLoc = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, + DAG.getConstant(Offset, dl, MVT::i32)); + SDValue Load = + DAG.getLoad(MVT::i32, dl, Chain, SpLoc, MachinePointerInfo()); + InVals[Index] = Load; + MemOpChains.push_back(Load.getValue(1)); + } + + // Transform all loads nodes into one single node because + // all load nodes are independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains); + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Formal Arguments Calling Convention Implementation +//===----------------------------------------------------------------------===// + +namespace { + +struct ArgDataPair { + SDValue SDV; + ISD::ArgFlagsTy Flags; +}; + +} // end anonymous namespace + +/// ARC formal arguments implementation +SDValue ARCTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, + SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { + switch (CallConv) { + default: + llvm_unreachable("Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + return LowerCallArguments(Chain, CallConv, IsVarArg, Ins, dl, DAG, InVals); + } +} + +/// Transform physical registers into virtual registers, and generate load +/// operations for argument places on the stack. +SDValue ARCTargetLowering::LowerCallArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + auto *AFI = MF.getInfo<ARCFunctionInfo>(); + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + + CCInfo.AnalyzeFormalArguments(Ins, CC_ARC); + + unsigned StackSlotSize = 4; + + if (!IsVarArg) + AFI->setReturnStackOffset(CCInfo.getNextStackOffset()); + + // All getCopyFromReg ops must precede any getMemcpys to prevent the + // scheduler clobbering a register before it has been copied. + // The stages are: + // 1. CopyFromReg (and load) arg & vararg registers. + // 2. Chain CopyFromReg nodes into a TokenFactor. + // 3. Memcpy 'byVal' args & push final InVals. + // 4. Chain mem ops nodes into a TokenFactor. + SmallVector<SDValue, 4> CFRegNode; + SmallVector<ArgDataPair, 4> ArgData; + SmallVector<SDValue, 4> MemOps; + + // 1a. CopyFromReg (and load) arg registers. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + SDValue ArgIn; + + if (VA.isRegLoc()) { + // Arguments passed in registers + EVT RegVT = VA.getLocVT(); + switch (RegVT.getSimpleVT().SimpleTy) { + default: { + DEBUG(errs() << "LowerFormalArguments Unhandled argument type: " + << RegVT.getSimpleVT().SimpleTy << "\n"); + llvm_unreachable("Unhandled LowerFormalArguments type."); + } + case MVT::i32: + unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + ArgIn = DAG.getCopyFromReg(Chain, dl, VReg, RegVT); + CFRegNode.push_back(ArgIn.getValue(ArgIn->getNumValues() - 1)); + } + } else { + // sanity check + assert(VA.isMemLoc()); + // Load the argument to a virtual register + unsigned ObjSize = VA.getLocVT().getStoreSize(); + assert((ObjSize <= StackSlotSize) && "Unhandled argument"); + + // Create the frame index object for this incoming parameter... + int FI = MFI.CreateFixedObject(ObjSize, VA.getLocMemOffset(), true); + + // Create the SelectionDAG nodes corresponding to a load + // from this parameter + SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); + ArgIn = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN, + MachinePointerInfo::getFixedStack(MF, FI)); + } + const ArgDataPair ADP = {ArgIn, Ins[i].Flags}; + ArgData.push_back(ADP); + } + + // 1b. CopyFromReg vararg registers. + if (IsVarArg) { + // Argument registers + static const MCPhysReg ArgRegs[] = {ARC::R0, ARC::R1, ARC::R2, ARC::R3, + ARC::R4, ARC::R5, ARC::R6, ARC::R7}; + auto *AFI = MF.getInfo<ARCFunctionInfo>(); + unsigned FirstVAReg = CCInfo.getFirstUnallocated(ArgRegs); + if (FirstVAReg < array_lengthof(ArgRegs)) { + int Offset = 0; + // Save remaining registers, storing higher register numbers at a higher + // address + // There are (array_lengthof(ArgRegs) - FirstVAReg) registers which + // need to be saved. + int VarFI = + MFI.CreateFixedObject((array_lengthof(ArgRegs) - FirstVAReg) * 4, + CCInfo.getNextStackOffset(), true); + AFI->setVarArgsFrameIndex(VarFI); + SDValue FIN = DAG.getFrameIndex(VarFI, MVT::i32); + for (unsigned i = FirstVAReg; i < array_lengthof(ArgRegs); i++) { + // Move argument from phys reg -> virt reg + unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass); + RegInfo.addLiveIn(ArgRegs[i], VReg); + SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32); + CFRegNode.push_back(Val.getValue(Val->getNumValues() - 1)); + SDValue VAObj = DAG.getNode(ISD::ADD, dl, MVT::i32, FIN, + DAG.getConstant(Offset, dl, MVT::i32)); + // Move argument from virt reg -> stack + SDValue Store = + DAG.getStore(Val.getValue(1), dl, Val, VAObj, MachinePointerInfo()); + MemOps.push_back(Store); + Offset += 4; + } + } else { + llvm_unreachable("Too many var args parameters."); + } + } + + // 2. Chain CopyFromReg nodes into a TokenFactor. + if (!CFRegNode.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, CFRegNode); + + // 3. Memcpy 'byVal' args & push final InVals. + // Aggregates passed "byVal" need to be copied by the callee. + // The callee will use a pointer to this copy, rather than the original + // pointer. + for (const auto &ArgDI : ArgData) { + if (ArgDI.Flags.isByVal() && ArgDI.Flags.getByValSize()) { + unsigned Size = ArgDI.Flags.getByValSize(); + unsigned Align = std::max(StackSlotSize, ArgDI.Flags.getByValAlign()); + // Create a new object on the stack and copy the pointee into it. + int FI = MFI.CreateStackObject(Size, Align, false); + SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); + InVals.push_back(FIN); + MemOps.push_back(DAG.getMemcpy( + Chain, dl, FIN, ArgDI.SDV, DAG.getConstant(Size, dl, MVT::i32), Align, + false, false, false, MachinePointerInfo(), MachinePointerInfo())); + } else { + InVals.push_back(ArgDI.SDV); + } + } + + // 4. Chain mem ops nodes into a TokenFactor. + if (!MemOps.empty()) { + MemOps.push_back(Chain); + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Return Value Calling Convention Implementation +//===----------------------------------------------------------------------===// + +bool ARCTargetLowering::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); + if (!CCInfo.CheckReturn(Outs, RetCC_ARC)) + return false; + if (CCInfo.getNextStackOffset() != 0 && IsVarArg) + return false; + return true; +} + +SDValue +ARCTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SDLoc &dl, SelectionDAG &DAG) const { + auto *AFI = DAG.getMachineFunction().getInfo<ARCFunctionInfo>(); + MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); + + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + + // Analyze return values. + if (!IsVarArg) + CCInfo.AllocateStack(AFI->getReturnStackOffset(), 4); + + CCInfo.AnalyzeReturn(Outs, RetCC_ARC); + + SDValue Flag; + SmallVector<SDValue, 4> RetOps(1, Chain); + SmallVector<SDValue, 4> MemOpChains; + // Handle return values that must be copied to memory. + for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) { + CCValAssign &VA = RVLocs[i]; + if (VA.isRegLoc()) + continue; + assert(VA.isMemLoc()); + if (IsVarArg) { + report_fatal_error("Can't return value from vararg function in memory"); + } + + int Offset = VA.getLocMemOffset(); + unsigned ObjSize = VA.getLocVT().getStoreSize(); + // Create the frame index object for the memory location. + int FI = MFI.CreateFixedObject(ObjSize, Offset, false); + + // Create a SelectionDAG node corresponding to a store + // to this memory location. + SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); + MemOpChains.push_back(DAG.getStore( + Chain, dl, OutVals[i], FIN, + MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI))); + } + + // Transform all store nodes into one single node because + // all stores are independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains); + + // Now handle return values copied to registers. + for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) { + CCValAssign &VA = RVLocs[i]; + if (!VA.isRegLoc()) + continue; + // Copy the result values into the output registers. + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag); + + // guarantee that all emitted copies are + // stuck together, avoiding something bad + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + RetOps[0] = Chain; // Update chain. + + // Add the flag if we have it. + if (Flag.getNode()) + RetOps.push_back(Flag); + + // What to do with the RetOps? + return DAG.getNode(ARCISD::RET, dl, MVT::Other, RetOps); +} + +//===----------------------------------------------------------------------===// +// Target Optimization Hooks +//===----------------------------------------------------------------------===// + +SDValue ARCTargetLowering::PerformDAGCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + return {}; +} + +//===----------------------------------------------------------------------===// +// Addressing mode description hooks +//===----------------------------------------------------------------------===// + +/// Return true if the addressing mode represented by AM is legal for this +/// target, for a load/store of the specified type. +bool ARCTargetLowering::isLegalAddressingMode(const DataLayout &DL, + const AddrMode &AM, Type *Ty, + unsigned AS, + Instruction *I) const { + return AM.Scale == 0; +} + +// Don't emit tail calls for the time being. +bool ARCTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const { + return false; +} + +SDValue ARCTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { + const ARCRegisterInfo &ARI = *Subtarget.getRegisterInfo(); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + MFI.setFrameAddressIsTaken(true); + + EVT VT = Op.getValueType(); + SDLoc dl(Op); + assert(cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() == 0 && + "Only support lowering frame addr of current frame."); + unsigned FrameReg = ARI.getFrameRegister(MF); + return DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT); +} + +SDValue ARCTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op); + const GlobalValue *GV = GN->getGlobal(); + SDLoc dl(GN); + int64_t Offset = GN->getOffset(); + SDValue GA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, Offset); + return DAG.getNode(ARCISD::GAWRAPPER, dl, MVT::i32, GA); +} + +static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) { + MachineFunction &MF = DAG.getMachineFunction(); + auto *FuncInfo = MF.getInfo<ARCFunctionInfo>(); + + // vastart just stores the address of the VarArgsFrameIndex slot into the + // memory location argument. + SDLoc dl(Op); + EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); + SDValue FR = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT); + const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); + return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1), + MachinePointerInfo(SV)); +} + +SDValue ARCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + case ISD::GlobalAddress: + return LowerGlobalAddress(Op, DAG); + case ISD::FRAMEADDR: + return LowerFRAMEADDR(Op, DAG); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG); + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); + case ISD::SIGN_EXTEND_INREG: + return LowerSIGN_EXTEND_INREG(Op, DAG); + case ISD::JumpTable: + return LowerJumpTable(Op, DAG); + case ISD::VASTART: + return LowerVASTART(Op, DAG); + default: + llvm_unreachable("unimplemented operand"); + } +} |