summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/ARC/ARCISelLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARC/ARCISelLowering.cpp')
-rw-r--r--llvm/lib/Target/ARC/ARCISelLowering.cpp767
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");
+ }
+}
OpenPOWER on IntegriCloud