10b57cec5SDimitry Andric //===- ARCISelLowering.cpp - ARC DAG Lowering Impl --------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the ARCTargetLowering class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "ARCISelLowering.h"
140b57cec5SDimitry Andric #include "ARC.h"
150b57cec5SDimitry Andric #include "ARCMachineFunctionInfo.h"
160b57cec5SDimitry Andric #include "ARCSubtarget.h"
170b57cec5SDimitry Andric #include "ARCTargetMachine.h"
180b57cec5SDimitry Andric #include "MCTargetDesc/ARCInfo.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/CallingConvLower.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/ValueTypes.h"
260b57cec5SDimitry Andric #include "llvm/IR/CallingConv.h"
270b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
280b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
290b57cec5SDimitry Andric #include <algorithm>
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric #define DEBUG_TYPE "arc-lower"
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric using namespace llvm;
340b57cec5SDimitry Andric 
3506c3fb27SDimitry Andric static SDValue lowerCallResult(SDValue Chain, SDValue InGlue,
360b57cec5SDimitry Andric                                const SmallVectorImpl<CCValAssign> &RVLocs,
370b57cec5SDimitry Andric                                SDLoc dl, SelectionDAG &DAG,
380b57cec5SDimitry Andric                                SmallVectorImpl<SDValue> &InVals);
390b57cec5SDimitry Andric 
ISDCCtoARCCC(ISD::CondCode isdCC)400b57cec5SDimitry Andric static ARCCC::CondCode ISDCCtoARCCC(ISD::CondCode isdCC) {
410b57cec5SDimitry Andric   switch (isdCC) {
420b57cec5SDimitry Andric   case ISD::SETUEQ:
430b57cec5SDimitry Andric     return ARCCC::EQ;
440b57cec5SDimitry Andric   case ISD::SETUGT:
450b57cec5SDimitry Andric     return ARCCC::HI;
460b57cec5SDimitry Andric   case ISD::SETUGE:
470b57cec5SDimitry Andric     return ARCCC::HS;
480b57cec5SDimitry Andric   case ISD::SETULT:
490b57cec5SDimitry Andric     return ARCCC::LO;
500b57cec5SDimitry Andric   case ISD::SETULE:
510b57cec5SDimitry Andric     return ARCCC::LS;
520b57cec5SDimitry Andric   case ISD::SETUNE:
530b57cec5SDimitry Andric     return ARCCC::NE;
540b57cec5SDimitry Andric   case ISD::SETEQ:
550b57cec5SDimitry Andric     return ARCCC::EQ;
560b57cec5SDimitry Andric   case ISD::SETGT:
570b57cec5SDimitry Andric     return ARCCC::GT;
580b57cec5SDimitry Andric   case ISD::SETGE:
590b57cec5SDimitry Andric     return ARCCC::GE;
600b57cec5SDimitry Andric   case ISD::SETLT:
610b57cec5SDimitry Andric     return ARCCC::LT;
620b57cec5SDimitry Andric   case ISD::SETLE:
630b57cec5SDimitry Andric     return ARCCC::LE;
640b57cec5SDimitry Andric   case ISD::SETNE:
650b57cec5SDimitry Andric     return ARCCC::NE;
660b57cec5SDimitry Andric   default:
670b57cec5SDimitry Andric     llvm_unreachable("Unhandled ISDCC code.");
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
ReplaceNodeResults(SDNode * N,SmallVectorImpl<SDValue> & Results,SelectionDAG & DAG) const71349cc55cSDimitry Andric void ARCTargetLowering::ReplaceNodeResults(SDNode *N,
72349cc55cSDimitry Andric                                            SmallVectorImpl<SDValue> &Results,
73349cc55cSDimitry Andric                                            SelectionDAG &DAG) const {
74349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "[ARC-ISEL] ReplaceNodeResults ");
75349cc55cSDimitry Andric   LLVM_DEBUG(N->dump(&DAG));
76349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "; use_count=" << N->use_size() << "\n");
77349cc55cSDimitry Andric 
78349cc55cSDimitry Andric   switch (N->getOpcode()) {
79349cc55cSDimitry Andric   case ISD::READCYCLECOUNTER:
80349cc55cSDimitry Andric     if (N->getValueType(0) == MVT::i64) {
81349cc55cSDimitry Andric       // We read the TIMER0 and zero-extend it to 64-bits as the intrinsic
82349cc55cSDimitry Andric       // requires.
83349cc55cSDimitry Andric       SDValue V =
84349cc55cSDimitry Andric           DAG.getNode(ISD::READCYCLECOUNTER, SDLoc(N),
85349cc55cSDimitry Andric                       DAG.getVTList(MVT::i32, MVT::Other), N->getOperand(0));
86349cc55cSDimitry Andric       SDValue Op = DAG.getNode(ISD::ZERO_EXTEND, SDLoc(N), MVT::i64, V);
87349cc55cSDimitry Andric       Results.push_back(Op);
88349cc55cSDimitry Andric       Results.push_back(V.getValue(1));
89349cc55cSDimitry Andric     }
90349cc55cSDimitry Andric     break;
91349cc55cSDimitry Andric   default:
92349cc55cSDimitry Andric     break;
93349cc55cSDimitry Andric   }
94349cc55cSDimitry Andric }
95349cc55cSDimitry Andric 
ARCTargetLowering(const TargetMachine & TM,const ARCSubtarget & Subtarget)960b57cec5SDimitry Andric ARCTargetLowering::ARCTargetLowering(const TargetMachine &TM,
970b57cec5SDimitry Andric                                      const ARCSubtarget &Subtarget)
980b57cec5SDimitry Andric     : TargetLowering(TM), Subtarget(Subtarget) {
990b57cec5SDimitry Andric   // Set up the register classes.
1000b57cec5SDimitry Andric   addRegisterClass(MVT::i32, &ARC::GPR32RegClass);
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // Compute derived properties from the register classes
1030b57cec5SDimitry Andric   computeRegisterProperties(Subtarget.getRegisterInfo());
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   setStackPointerRegisterToSaveRestore(ARC::SP);
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   setSchedulingPreference(Sched::Source);
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   // Use i32 for setcc operations results (slt, sgt, ...).
1100b57cec5SDimitry Andric   setBooleanContents(ZeroOrOneBooleanContent);
1110b57cec5SDimitry Andric   setBooleanVectorContents(ZeroOrOneBooleanContent);
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc)
1140b57cec5SDimitry Andric     setOperationAction(Opc, MVT::i32, Expand);
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   // Operations to get us off of the ground.
1170b57cec5SDimitry Andric   // Basic.
1180b57cec5SDimitry Andric   setOperationAction(ISD::ADD, MVT::i32, Legal);
1190b57cec5SDimitry Andric   setOperationAction(ISD::SUB, MVT::i32, Legal);
1200b57cec5SDimitry Andric   setOperationAction(ISD::AND, MVT::i32, Legal);
1210b57cec5SDimitry Andric   setOperationAction(ISD::SMAX, MVT::i32, Legal);
1220b57cec5SDimitry Andric   setOperationAction(ISD::SMIN, MVT::i32, Legal);
1230b57cec5SDimitry Andric 
124349cc55cSDimitry Andric   setOperationAction(ISD::ADDC, MVT::i32, Legal);
125349cc55cSDimitry Andric   setOperationAction(ISD::ADDE, MVT::i32, Legal);
126349cc55cSDimitry Andric   setOperationAction(ISD::SUBC, MVT::i32, Legal);
127349cc55cSDimitry Andric   setOperationAction(ISD::SUBE, MVT::i32, Legal);
128349cc55cSDimitry Andric 
1290b57cec5SDimitry Andric   // Need barrel shifter.
1300b57cec5SDimitry Andric   setOperationAction(ISD::SHL, MVT::i32, Legal);
1310b57cec5SDimitry Andric   setOperationAction(ISD::SRA, MVT::i32, Legal);
1320b57cec5SDimitry Andric   setOperationAction(ISD::SRL, MVT::i32, Legal);
1330b57cec5SDimitry Andric   setOperationAction(ISD::ROTR, MVT::i32, Legal);
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   setOperationAction(ISD::Constant, MVT::i32, Legal);
1360b57cec5SDimitry Andric   setOperationAction(ISD::UNDEF, MVT::i32, Legal);
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   // Need multiplier
1390b57cec5SDimitry Andric   setOperationAction(ISD::MUL, MVT::i32, Legal);
1400b57cec5SDimitry Andric   setOperationAction(ISD::MULHS, MVT::i32, Legal);
1410b57cec5SDimitry Andric   setOperationAction(ISD::MULHU, MVT::i32, Legal);
1420b57cec5SDimitry Andric   setOperationAction(ISD::LOAD, MVT::i32, Legal);
1430b57cec5SDimitry Andric   setOperationAction(ISD::STORE, MVT::i32, Legal);
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
1460b57cec5SDimitry Andric   setOperationAction(ISD::BR_CC, MVT::i32, Custom);
1470b57cec5SDimitry Andric   setOperationAction(ISD::BRCOND, MVT::Other, Expand);
1480b57cec5SDimitry Andric   setOperationAction(ISD::BR_JT, MVT::Other, Expand);
1490b57cec5SDimitry Andric   setOperationAction(ISD::JumpTable, MVT::i32, Custom);
1500b57cec5SDimitry Andric 
151480093f4SDimitry Andric   // Have pseudo instruction for frame addresses.
1520b57cec5SDimitry Andric   setOperationAction(ISD::FRAMEADDR, MVT::i32, Legal);
1530b57cec5SDimitry Andric   // Custom lower global addresses.
1540b57cec5SDimitry Andric   setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   // Expand var-args ops.
1570b57cec5SDimitry Andric   setOperationAction(ISD::VASTART, MVT::Other, Custom);
1580b57cec5SDimitry Andric   setOperationAction(ISD::VAEND, MVT::Other, Expand);
1590b57cec5SDimitry Andric   setOperationAction(ISD::VAARG, MVT::Other, Expand);
1600b57cec5SDimitry Andric   setOperationAction(ISD::VACOPY, MVT::Other, Expand);
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   // Other expansions
1630b57cec5SDimitry Andric   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
1640b57cec5SDimitry Andric   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   // Sign extend inreg
1670b57cec5SDimitry Andric   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Custom);
168349cc55cSDimitry Andric 
169349cc55cSDimitry Andric   // TODO: Predicate these with `options.hasBitScan() ? Legal : Expand`
170349cc55cSDimitry Andric   //       when the HasBitScan predicate is available.
171349cc55cSDimitry Andric   setOperationAction(ISD::CTLZ, MVT::i32, Legal);
172349cc55cSDimitry Andric   setOperationAction(ISD::CTTZ, MVT::i32, Legal);
173349cc55cSDimitry Andric 
174349cc55cSDimitry Andric   setOperationAction(ISD::READCYCLECOUNTER, MVT::i32, Legal);
175349cc55cSDimitry Andric   setOperationAction(ISD::READCYCLECOUNTER, MVT::i64,
176349cc55cSDimitry Andric                      isTypeLegal(MVT::i64) ? Legal : Custom);
1771db9f3b2SDimitry Andric 
1781db9f3b2SDimitry Andric   setMaxAtomicSizeInBitsSupported(0);
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
getTargetNodeName(unsigned Opcode) const1810b57cec5SDimitry Andric const char *ARCTargetLowering::getTargetNodeName(unsigned Opcode) const {
1820b57cec5SDimitry Andric   switch (Opcode) {
1830b57cec5SDimitry Andric   case ARCISD::BL:
1840b57cec5SDimitry Andric     return "ARCISD::BL";
1850b57cec5SDimitry Andric   case ARCISD::CMOV:
1860b57cec5SDimitry Andric     return "ARCISD::CMOV";
1870b57cec5SDimitry Andric   case ARCISD::CMP:
1880b57cec5SDimitry Andric     return "ARCISD::CMP";
1890b57cec5SDimitry Andric   case ARCISD::BRcc:
1900b57cec5SDimitry Andric     return "ARCISD::BRcc";
1910b57cec5SDimitry Andric   case ARCISD::RET:
1920b57cec5SDimitry Andric     return "ARCISD::RET";
1930b57cec5SDimitry Andric   case ARCISD::GAWRAPPER:
1940b57cec5SDimitry Andric     return "ARCISD::GAWRAPPER";
1950b57cec5SDimitry Andric   }
1960b57cec5SDimitry Andric   return nullptr;
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2000b57cec5SDimitry Andric //  Misc Lower Operation implementation
2010b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2020b57cec5SDimitry Andric 
LowerSELECT_CC(SDValue Op,SelectionDAG & DAG) const2030b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
2040b57cec5SDimitry Andric   SDValue LHS = Op.getOperand(0);
2050b57cec5SDimitry Andric   SDValue RHS = Op.getOperand(1);
2060b57cec5SDimitry Andric   ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
2070b57cec5SDimitry Andric   SDValue TVal = Op.getOperand(2);
2080b57cec5SDimitry Andric   SDValue FVal = Op.getOperand(3);
2090b57cec5SDimitry Andric   SDLoc dl(Op);
2100b57cec5SDimitry Andric   ARCCC::CondCode ArcCC = ISDCCtoARCCC(CC);
2110b57cec5SDimitry Andric   assert(LHS.getValueType() == MVT::i32 && "Only know how to SELECT_CC i32");
2120b57cec5SDimitry Andric   SDValue Cmp = DAG.getNode(ARCISD::CMP, dl, MVT::Glue, LHS, RHS);
2130b57cec5SDimitry Andric   return DAG.getNode(ARCISD::CMOV, dl, TVal.getValueType(), TVal, FVal,
2140b57cec5SDimitry Andric                      DAG.getConstant(ArcCC, dl, MVT::i32), Cmp);
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric 
LowerSIGN_EXTEND_INREG(SDValue Op,SelectionDAG & DAG) const2170b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
2180b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
2190b57cec5SDimitry Andric   SDValue Op0 = Op.getOperand(0);
2200b57cec5SDimitry Andric   SDLoc dl(Op);
2210b57cec5SDimitry Andric   assert(Op.getValueType() == MVT::i32 &&
2220b57cec5SDimitry Andric          "Unhandled target sign_extend_inreg.");
2230b57cec5SDimitry Andric   // These are legal
2240b57cec5SDimitry Andric   unsigned Width = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits();
2250b57cec5SDimitry Andric   if (Width == 16 || Width == 8)
2260b57cec5SDimitry Andric     return Op;
2270b57cec5SDimitry Andric   if (Width >= 32) {
2280b57cec5SDimitry Andric     return {};
2290b57cec5SDimitry Andric   }
2300b57cec5SDimitry Andric   SDValue LS = DAG.getNode(ISD::SHL, dl, MVT::i32, Op0,
2310b57cec5SDimitry Andric                            DAG.getConstant(32 - Width, dl, MVT::i32));
2320b57cec5SDimitry Andric   SDValue SR = DAG.getNode(ISD::SRA, dl, MVT::i32, LS,
2330b57cec5SDimitry Andric                            DAG.getConstant(32 - Width, dl, MVT::i32));
2340b57cec5SDimitry Andric   return SR;
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
LowerBR_CC(SDValue Op,SelectionDAG & DAG) const2370b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
2380b57cec5SDimitry Andric   SDValue Chain = Op.getOperand(0);
2390b57cec5SDimitry Andric   ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
2400b57cec5SDimitry Andric   SDValue LHS = Op.getOperand(2);
2410b57cec5SDimitry Andric   SDValue RHS = Op.getOperand(3);
2420b57cec5SDimitry Andric   SDValue Dest = Op.getOperand(4);
2430b57cec5SDimitry Andric   SDLoc dl(Op);
2440b57cec5SDimitry Andric   ARCCC::CondCode arcCC = ISDCCtoARCCC(CC);
2450b57cec5SDimitry Andric   assert(LHS.getValueType() == MVT::i32 && "Only know how to BR_CC i32");
2460b57cec5SDimitry Andric   return DAG.getNode(ARCISD::BRcc, dl, MVT::Other, Chain, Dest, LHS, RHS,
2470b57cec5SDimitry Andric                      DAG.getConstant(arcCC, dl, MVT::i32));
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric 
LowerJumpTable(SDValue Op,SelectionDAG & DAG) const2500b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const {
2510b57cec5SDimitry Andric   auto *N = cast<JumpTableSDNode>(Op);
2520b57cec5SDimitry Andric   SDValue GA = DAG.getTargetJumpTable(N->getIndex(), MVT::i32);
2530b57cec5SDimitry Andric   return DAG.getNode(ARCISD::GAWRAPPER, SDLoc(N), MVT::i32, GA);
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric #include "ARCGenCallingConv.inc"
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2590b57cec5SDimitry Andric //                  Call Calling Convention Implementation
2600b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric /// ARC call implementation
LowerCall(TargetLowering::CallLoweringInfo & CLI,SmallVectorImpl<SDValue> & InVals) const2630b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
2640b57cec5SDimitry Andric                                      SmallVectorImpl<SDValue> &InVals) const {
2650b57cec5SDimitry Andric   SelectionDAG &DAG = CLI.DAG;
2660b57cec5SDimitry Andric   SDLoc &dl = CLI.DL;
2670b57cec5SDimitry Andric   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
2680b57cec5SDimitry Andric   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
2690b57cec5SDimitry Andric   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
2700b57cec5SDimitry Andric   SDValue Chain = CLI.Chain;
2710b57cec5SDimitry Andric   SDValue Callee = CLI.Callee;
2720b57cec5SDimitry Andric   CallingConv::ID CallConv = CLI.CallConv;
2730b57cec5SDimitry Andric   bool IsVarArg = CLI.IsVarArg;
2740b57cec5SDimitry Andric   bool &IsTailCall = CLI.IsTailCall;
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   IsTailCall = false; // Do not support tail calls yet.
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric   SmallVector<CCValAssign, 16> ArgLocs;
2790b57cec5SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
2800b57cec5SDimitry Andric                  *DAG.getContext());
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   CCInfo.AnalyzeCallOperands(Outs, CC_ARC);
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   SmallVector<CCValAssign, 16> RVLocs;
2850b57cec5SDimitry Andric   // Analyze return values to determine the number of bytes of stack required.
2860b57cec5SDimitry Andric   CCState RetCCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
2870b57cec5SDimitry Andric                     *DAG.getContext());
28806c3fb27SDimitry Andric   RetCCInfo.AllocateStack(CCInfo.getStackSize(), Align(4));
2890b57cec5SDimitry Andric   RetCCInfo.AnalyzeCallResult(Ins, RetCC_ARC);
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric   // Get a count of how many bytes are to be pushed on the stack.
29206c3fb27SDimitry Andric   unsigned NumBytes = RetCCInfo.getStackSize();
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric   Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl);
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric   SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass;
2970b57cec5SDimitry Andric   SmallVector<SDValue, 12> MemOpChains;
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   SDValue StackPtr;
3000b57cec5SDimitry Andric   // Walk the register/memloc assignments, inserting copies/loads.
3010b57cec5SDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
3020b57cec5SDimitry Andric     CCValAssign &VA = ArgLocs[i];
3030b57cec5SDimitry Andric     SDValue Arg = OutVals[i];
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric     // Promote the value if needed.
3060b57cec5SDimitry Andric     switch (VA.getLocInfo()) {
3070b57cec5SDimitry Andric     default:
3080b57cec5SDimitry Andric       llvm_unreachable("Unknown loc info!");
3090b57cec5SDimitry Andric     case CCValAssign::Full:
3100b57cec5SDimitry Andric       break;
3110b57cec5SDimitry Andric     case CCValAssign::SExt:
3120b57cec5SDimitry Andric       Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
3130b57cec5SDimitry Andric       break;
3140b57cec5SDimitry Andric     case CCValAssign::ZExt:
3150b57cec5SDimitry Andric       Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
3160b57cec5SDimitry Andric       break;
3170b57cec5SDimitry Andric     case CCValAssign::AExt:
3180b57cec5SDimitry Andric       Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
3190b57cec5SDimitry Andric       break;
3200b57cec5SDimitry Andric     }
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric     // Arguments that can be passed on register must be kept at
3230b57cec5SDimitry Andric     // RegsToPass vector
3240b57cec5SDimitry Andric     if (VA.isRegLoc()) {
3250b57cec5SDimitry Andric       RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
3260b57cec5SDimitry Andric     } else {
3270b57cec5SDimitry Andric       assert(VA.isMemLoc() && "Must be register or memory argument.");
3280b57cec5SDimitry Andric       if (!StackPtr.getNode())
3290b57cec5SDimitry Andric         StackPtr = DAG.getCopyFromReg(Chain, dl, ARC::SP,
3300b57cec5SDimitry Andric                                       getPointerTy(DAG.getDataLayout()));
3310b57cec5SDimitry Andric       // Calculate the stack position.
3320b57cec5SDimitry Andric       SDValue SOffset = DAG.getIntPtrConstant(VA.getLocMemOffset(), dl);
3330b57cec5SDimitry Andric       SDValue PtrOff = DAG.getNode(
3340b57cec5SDimitry Andric           ISD::ADD, dl, getPointerTy(DAG.getDataLayout()), StackPtr, SOffset);
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric       SDValue Store =
3370b57cec5SDimitry Andric           DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo());
3380b57cec5SDimitry Andric       MemOpChains.push_back(Store);
3390b57cec5SDimitry Andric       IsTailCall = false;
3400b57cec5SDimitry Andric     }
3410b57cec5SDimitry Andric   }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   // Transform all store nodes into one single node because
3440b57cec5SDimitry Andric   // all store nodes are independent of each other.
3450b57cec5SDimitry Andric   if (!MemOpChains.empty())
3460b57cec5SDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric   // Build a sequence of copy-to-reg nodes chained together with token
3490b57cec5SDimitry Andric   // chain and flag operands which copy the outgoing args into registers.
35006c3fb27SDimitry Andric   // The Glue in necessary since all emitted instructions must be
3510b57cec5SDimitry Andric   // stuck together.
3520b57cec5SDimitry Andric   SDValue Glue;
3530b57cec5SDimitry Andric   for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
3540b57cec5SDimitry Andric     Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
3550b57cec5SDimitry Andric                              RegsToPass[i].second, Glue);
3560b57cec5SDimitry Andric     Glue = Chain.getValue(1);
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   // If the callee is a GlobalAddress node (quite common, every direct call is)
3600b57cec5SDimitry Andric   // turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
3610b57cec5SDimitry Andric   // Likewise ExternalSymbol -> TargetExternalSymbol.
3620b57cec5SDimitry Andric   bool IsDirect = true;
3630b57cec5SDimitry Andric   if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee))
3640b57cec5SDimitry Andric     Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32);
3650b57cec5SDimitry Andric   else if (auto *E = dyn_cast<ExternalSymbolSDNode>(Callee))
3660b57cec5SDimitry Andric     Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
3670b57cec5SDimitry Andric   else
3680b57cec5SDimitry Andric     IsDirect = false;
3690b57cec5SDimitry Andric   // Branch + Link = #chain, #target_address, #opt_in_flags...
3700b57cec5SDimitry Andric   //             = Chain, Callee, Reg#1, Reg#2, ...
3710b57cec5SDimitry Andric   //
37206c3fb27SDimitry Andric   // Returns a chain & a glue for retval copy to use.
3730b57cec5SDimitry Andric   SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
3740b57cec5SDimitry Andric   SmallVector<SDValue, 8> Ops;
3750b57cec5SDimitry Andric   Ops.push_back(Chain);
3760b57cec5SDimitry Andric   Ops.push_back(Callee);
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric   for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
3790b57cec5SDimitry Andric     Ops.push_back(DAG.getRegister(RegsToPass[i].first,
3800b57cec5SDimitry Andric                                   RegsToPass[i].second.getValueType()));
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   // Add a register mask operand representing the call-preserved registers.
3830b57cec5SDimitry Andric   const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
3840b57cec5SDimitry Andric   const uint32_t *Mask =
3850b57cec5SDimitry Andric       TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv);
3860b57cec5SDimitry Andric   assert(Mask && "Missing call preserved mask for calling convention");
3870b57cec5SDimitry Andric   Ops.push_back(DAG.getRegisterMask(Mask));
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   if (Glue.getNode())
3900b57cec5SDimitry Andric     Ops.push_back(Glue);
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   Chain = DAG.getNode(IsDirect ? ARCISD::BL : ARCISD::JL, dl, NodeTys, Ops);
3930b57cec5SDimitry Andric   Glue = Chain.getValue(1);
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   // Create the CALLSEQ_END node.
396bdd1243dSDimitry Andric   Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, dl);
3970b57cec5SDimitry Andric   Glue = Chain.getValue(1);
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric   // Handle result values, copying them out of physregs into vregs that we
4000b57cec5SDimitry Andric   // return.
4010b57cec5SDimitry Andric   if (IsTailCall)
4020b57cec5SDimitry Andric     return Chain;
4030b57cec5SDimitry Andric   return lowerCallResult(Chain, Glue, RVLocs, dl, DAG, InVals);
4040b57cec5SDimitry Andric }
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric /// Lower the result values of a call into the appropriate copies out of
4070b57cec5SDimitry Andric /// physical registers / memory locations.
lowerCallResult(SDValue Chain,SDValue Glue,const SmallVectorImpl<CCValAssign> & RVLocs,SDLoc dl,SelectionDAG & DAG,SmallVectorImpl<SDValue> & InVals)4080b57cec5SDimitry Andric static SDValue lowerCallResult(SDValue Chain, SDValue Glue,
4090b57cec5SDimitry Andric                                const SmallVectorImpl<CCValAssign> &RVLocs,
4100b57cec5SDimitry Andric                                SDLoc dl, SelectionDAG &DAG,
4110b57cec5SDimitry Andric                                SmallVectorImpl<SDValue> &InVals) {
4120b57cec5SDimitry Andric   SmallVector<std::pair<int, unsigned>, 4> ResultMemLocs;
4130b57cec5SDimitry Andric   // Copy results out of physical registers.
4140b57cec5SDimitry Andric   for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
4150b57cec5SDimitry Andric     const CCValAssign &VA = RVLocs[i];
4160b57cec5SDimitry Andric     if (VA.isRegLoc()) {
4170b57cec5SDimitry Andric       SDValue RetValue;
4180b57cec5SDimitry Andric       RetValue =
4190b57cec5SDimitry Andric           DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getValVT(), Glue);
4200b57cec5SDimitry Andric       Chain = RetValue.getValue(1);
4210b57cec5SDimitry Andric       Glue = RetValue.getValue(2);
4220b57cec5SDimitry Andric       InVals.push_back(RetValue);
4230b57cec5SDimitry Andric     } else {
4240b57cec5SDimitry Andric       assert(VA.isMemLoc() && "Must be memory location.");
4250b57cec5SDimitry Andric       ResultMemLocs.push_back(
4260b57cec5SDimitry Andric           std::make_pair(VA.getLocMemOffset(), InVals.size()));
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric       // Reserve space for this result.
4290b57cec5SDimitry Andric       InVals.push_back(SDValue());
4300b57cec5SDimitry Andric     }
4310b57cec5SDimitry Andric   }
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric   // Copy results out of memory.
4340b57cec5SDimitry Andric   SmallVector<SDValue, 4> MemOpChains;
4350b57cec5SDimitry Andric   for (unsigned i = 0, e = ResultMemLocs.size(); i != e; ++i) {
4360b57cec5SDimitry Andric     int Offset = ResultMemLocs[i].first;
4370b57cec5SDimitry Andric     unsigned Index = ResultMemLocs[i].second;
4380b57cec5SDimitry Andric     SDValue StackPtr = DAG.getRegister(ARC::SP, MVT::i32);
4390b57cec5SDimitry Andric     SDValue SpLoc = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr,
4400b57cec5SDimitry Andric                                 DAG.getConstant(Offset, dl, MVT::i32));
4410b57cec5SDimitry Andric     SDValue Load =
4420b57cec5SDimitry Andric         DAG.getLoad(MVT::i32, dl, Chain, SpLoc, MachinePointerInfo());
4430b57cec5SDimitry Andric     InVals[Index] = Load;
4440b57cec5SDimitry Andric     MemOpChains.push_back(Load.getValue(1));
4450b57cec5SDimitry Andric   }
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric   // Transform all loads nodes into one single node because
4480b57cec5SDimitry Andric   // all load nodes are independent of each other.
4490b57cec5SDimitry Andric   if (!MemOpChains.empty())
4500b57cec5SDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric   return Chain;
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4560b57cec5SDimitry Andric //             Formal Arguments Calling Convention Implementation
4570b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4580b57cec5SDimitry Andric 
4590b57cec5SDimitry Andric namespace {
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric struct ArgDataPair {
4620b57cec5SDimitry Andric   SDValue SDV;
4630b57cec5SDimitry Andric   ISD::ArgFlagsTy Flags;
4640b57cec5SDimitry Andric };
4650b57cec5SDimitry Andric 
4660b57cec5SDimitry Andric } // end anonymous namespace
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric /// ARC formal arguments implementation
LowerFormalArguments(SDValue Chain,CallingConv::ID CallConv,bool IsVarArg,const SmallVectorImpl<ISD::InputArg> & Ins,const SDLoc & dl,SelectionDAG & DAG,SmallVectorImpl<SDValue> & InVals) const4690b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerFormalArguments(
4700b57cec5SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
4710b57cec5SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
4720b57cec5SDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
4730b57cec5SDimitry Andric   switch (CallConv) {
4740b57cec5SDimitry Andric   default:
4750b57cec5SDimitry Andric     llvm_unreachable("Unsupported calling convention");
4760b57cec5SDimitry Andric   case CallingConv::C:
4770b57cec5SDimitry Andric   case CallingConv::Fast:
4780b57cec5SDimitry Andric     return LowerCallArguments(Chain, CallConv, IsVarArg, Ins, dl, DAG, InVals);
4790b57cec5SDimitry Andric   }
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric /// Transform physical registers into virtual registers, and generate load
4830b57cec5SDimitry Andric /// operations for argument places on the stack.
LowerCallArguments(SDValue Chain,CallingConv::ID CallConv,bool IsVarArg,const SmallVectorImpl<ISD::InputArg> & Ins,SDLoc dl,SelectionDAG & DAG,SmallVectorImpl<SDValue> & InVals) const4840b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerCallArguments(
4850b57cec5SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
4860b57cec5SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, SelectionDAG &DAG,
4870b57cec5SDimitry Andric     SmallVectorImpl<SDValue> &InVals) const {
4880b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
4890b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
4900b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = MF.getRegInfo();
4910b57cec5SDimitry Andric   auto *AFI = MF.getInfo<ARCFunctionInfo>();
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   // Assign locations to all of the incoming arguments.
4940b57cec5SDimitry Andric   SmallVector<CCValAssign, 16> ArgLocs;
4950b57cec5SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
4960b57cec5SDimitry Andric                  *DAG.getContext());
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric   CCInfo.AnalyzeFormalArguments(Ins, CC_ARC);
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   unsigned StackSlotSize = 4;
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric   if (!IsVarArg)
50306c3fb27SDimitry Andric     AFI->setReturnStackOffset(CCInfo.getStackSize());
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric   // All getCopyFromReg ops must precede any getMemcpys to prevent the
5060b57cec5SDimitry Andric   // scheduler clobbering a register before it has been copied.
5070b57cec5SDimitry Andric   // The stages are:
5080b57cec5SDimitry Andric   // 1. CopyFromReg (and load) arg & vararg registers.
5090b57cec5SDimitry Andric   // 2. Chain CopyFromReg nodes into a TokenFactor.
5100b57cec5SDimitry Andric   // 3. Memcpy 'byVal' args & push final InVals.
5110b57cec5SDimitry Andric   // 4. Chain mem ops nodes into a TokenFactor.
5120b57cec5SDimitry Andric   SmallVector<SDValue, 4> CFRegNode;
5130b57cec5SDimitry Andric   SmallVector<ArgDataPair, 4> ArgData;
5140b57cec5SDimitry Andric   SmallVector<SDValue, 4> MemOps;
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric   // 1a. CopyFromReg (and load) arg registers.
5170b57cec5SDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
5180b57cec5SDimitry Andric     CCValAssign &VA = ArgLocs[i];
5190b57cec5SDimitry Andric     SDValue ArgIn;
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric     if (VA.isRegLoc()) {
5220b57cec5SDimitry Andric       // Arguments passed in registers
5230b57cec5SDimitry Andric       EVT RegVT = VA.getLocVT();
5240b57cec5SDimitry Andric       switch (RegVT.getSimpleVT().SimpleTy) {
5250b57cec5SDimitry Andric       default: {
5260b57cec5SDimitry Andric         LLVM_DEBUG(errs() << "LowerFormalArguments Unhandled argument type: "
5270b57cec5SDimitry Andric                           << (unsigned)RegVT.getSimpleVT().SimpleTy << "\n");
5280b57cec5SDimitry Andric         llvm_unreachable("Unhandled LowerFormalArguments type.");
5290b57cec5SDimitry Andric       }
5300b57cec5SDimitry Andric       case MVT::i32:
5310b57cec5SDimitry Andric         unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass);
5320b57cec5SDimitry Andric         RegInfo.addLiveIn(VA.getLocReg(), VReg);
5330b57cec5SDimitry Andric         ArgIn = DAG.getCopyFromReg(Chain, dl, VReg, RegVT);
5340b57cec5SDimitry Andric         CFRegNode.push_back(ArgIn.getValue(ArgIn->getNumValues() - 1));
5350b57cec5SDimitry Andric       }
5360b57cec5SDimitry Andric     } else {
537349cc55cSDimitry Andric       // Only arguments passed on the stack should make it here.
5380b57cec5SDimitry Andric       assert(VA.isMemLoc());
5390b57cec5SDimitry Andric       // Load the argument to a virtual register
5400b57cec5SDimitry Andric       unsigned ObjSize = VA.getLocVT().getStoreSize();
5410b57cec5SDimitry Andric       assert((ObjSize <= StackSlotSize) && "Unhandled argument");
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric       // Create the frame index object for this incoming parameter...
5440b57cec5SDimitry Andric       int FI = MFI.CreateFixedObject(ObjSize, VA.getLocMemOffset(), true);
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric       // Create the SelectionDAG nodes corresponding to a load
5470b57cec5SDimitry Andric       // from this parameter
5480b57cec5SDimitry Andric       SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
5490b57cec5SDimitry Andric       ArgIn = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN,
5500b57cec5SDimitry Andric                           MachinePointerInfo::getFixedStack(MF, FI));
5510b57cec5SDimitry Andric     }
5520b57cec5SDimitry Andric     const ArgDataPair ADP = {ArgIn, Ins[i].Flags};
5530b57cec5SDimitry Andric     ArgData.push_back(ADP);
5540b57cec5SDimitry Andric   }
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric   // 1b. CopyFromReg vararg registers.
5570b57cec5SDimitry Andric   if (IsVarArg) {
5580b57cec5SDimitry Andric     // Argument registers
5590b57cec5SDimitry Andric     static const MCPhysReg ArgRegs[] = {ARC::R0, ARC::R1, ARC::R2, ARC::R3,
5600b57cec5SDimitry Andric                                         ARC::R4, ARC::R5, ARC::R6, ARC::R7};
5610b57cec5SDimitry Andric     auto *AFI = MF.getInfo<ARCFunctionInfo>();
5620b57cec5SDimitry Andric     unsigned FirstVAReg = CCInfo.getFirstUnallocated(ArgRegs);
563bdd1243dSDimitry Andric     if (FirstVAReg < std::size(ArgRegs)) {
5640b57cec5SDimitry Andric       int Offset = 0;
5650b57cec5SDimitry Andric       // Save remaining registers, storing higher register numbers at a higher
5660b57cec5SDimitry Andric       // address
567bdd1243dSDimitry Andric       // There are (std::size(ArgRegs) - FirstVAReg) registers which
5680b57cec5SDimitry Andric       // need to be saved.
569bdd1243dSDimitry Andric       int VarFI = MFI.CreateFixedObject((std::size(ArgRegs) - FirstVAReg) * 4,
57006c3fb27SDimitry Andric                                         CCInfo.getStackSize(), true);
5710b57cec5SDimitry Andric       AFI->setVarArgsFrameIndex(VarFI);
5720b57cec5SDimitry Andric       SDValue FIN = DAG.getFrameIndex(VarFI, MVT::i32);
573bdd1243dSDimitry Andric       for (unsigned i = FirstVAReg; i < std::size(ArgRegs); i++) {
5740b57cec5SDimitry Andric         // Move argument from phys reg -> virt reg
5750b57cec5SDimitry Andric         unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass);
5760b57cec5SDimitry Andric         RegInfo.addLiveIn(ArgRegs[i], VReg);
5770b57cec5SDimitry Andric         SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32);
5780b57cec5SDimitry Andric         CFRegNode.push_back(Val.getValue(Val->getNumValues() - 1));
5790b57cec5SDimitry Andric         SDValue VAObj = DAG.getNode(ISD::ADD, dl, MVT::i32, FIN,
5800b57cec5SDimitry Andric                                     DAG.getConstant(Offset, dl, MVT::i32));
5810b57cec5SDimitry Andric         // Move argument from virt reg -> stack
5820b57cec5SDimitry Andric         SDValue Store =
5830b57cec5SDimitry Andric             DAG.getStore(Val.getValue(1), dl, Val, VAObj, MachinePointerInfo());
5840b57cec5SDimitry Andric         MemOps.push_back(Store);
5850b57cec5SDimitry Andric         Offset += 4;
5860b57cec5SDimitry Andric       }
5870b57cec5SDimitry Andric     } else {
5880b57cec5SDimitry Andric       llvm_unreachable("Too many var args parameters.");
5890b57cec5SDimitry Andric     }
5900b57cec5SDimitry Andric   }
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   // 2. Chain CopyFromReg nodes into a TokenFactor.
5930b57cec5SDimitry Andric   if (!CFRegNode.empty())
5940b57cec5SDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, CFRegNode);
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric   // 3. Memcpy 'byVal' args & push final InVals.
5970b57cec5SDimitry Andric   // Aggregates passed "byVal" need to be copied by the callee.
5980b57cec5SDimitry Andric   // The callee will use a pointer to this copy, rather than the original
5990b57cec5SDimitry Andric   // pointer.
6000b57cec5SDimitry Andric   for (const auto &ArgDI : ArgData) {
6010b57cec5SDimitry Andric     if (ArgDI.Flags.isByVal() && ArgDI.Flags.getByValSize()) {
6020b57cec5SDimitry Andric       unsigned Size = ArgDI.Flags.getByValSize();
6035ffd83dbSDimitry Andric       Align Alignment =
6045ffd83dbSDimitry Andric           std::max(Align(StackSlotSize), ArgDI.Flags.getNonZeroByValAlign());
6050b57cec5SDimitry Andric       // Create a new object on the stack and copy the pointee into it.
6065ffd83dbSDimitry Andric       int FI = MFI.CreateStackObject(Size, Alignment, false);
6070b57cec5SDimitry Andric       SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
6080b57cec5SDimitry Andric       InVals.push_back(FIN);
6090b57cec5SDimitry Andric       MemOps.push_back(DAG.getMemcpy(
6105ffd83dbSDimitry Andric           Chain, dl, FIN, ArgDI.SDV, DAG.getConstant(Size, dl, MVT::i32),
6115ffd83dbSDimitry Andric           Alignment, false, false, false, MachinePointerInfo(),
6125ffd83dbSDimitry Andric           MachinePointerInfo()));
6130b57cec5SDimitry Andric     } else {
6140b57cec5SDimitry Andric       InVals.push_back(ArgDI.SDV);
6150b57cec5SDimitry Andric     }
6160b57cec5SDimitry Andric   }
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric   // 4. Chain mem ops nodes into a TokenFactor.
6190b57cec5SDimitry Andric   if (!MemOps.empty()) {
6200b57cec5SDimitry Andric     MemOps.push_back(Chain);
6210b57cec5SDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);
6220b57cec5SDimitry Andric   }
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric   return Chain;
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6280b57cec5SDimitry Andric //               Return Value Calling Convention Implementation
6290b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6300b57cec5SDimitry Andric 
CanLowerReturn(CallingConv::ID CallConv,MachineFunction & MF,bool IsVarArg,const SmallVectorImpl<ISD::OutputArg> & Outs,LLVMContext & Context) const6310b57cec5SDimitry Andric bool ARCTargetLowering::CanLowerReturn(
6320b57cec5SDimitry Andric     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
6330b57cec5SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
6340b57cec5SDimitry Andric   SmallVector<CCValAssign, 16> RVLocs;
6350b57cec5SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
6360b57cec5SDimitry Andric   if (!CCInfo.CheckReturn(Outs, RetCC_ARC))
6370b57cec5SDimitry Andric     return false;
63806c3fb27SDimitry Andric   if (CCInfo.getStackSize() != 0 && IsVarArg)
6390b57cec5SDimitry Andric     return false;
6400b57cec5SDimitry Andric   return true;
6410b57cec5SDimitry Andric }
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric SDValue
LowerReturn(SDValue Chain,CallingConv::ID CallConv,bool IsVarArg,const SmallVectorImpl<ISD::OutputArg> & Outs,const SmallVectorImpl<SDValue> & OutVals,const SDLoc & dl,SelectionDAG & DAG) const6440b57cec5SDimitry Andric ARCTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
6450b57cec5SDimitry Andric                                bool IsVarArg,
6460b57cec5SDimitry Andric                                const SmallVectorImpl<ISD::OutputArg> &Outs,
6470b57cec5SDimitry Andric                                const SmallVectorImpl<SDValue> &OutVals,
6480b57cec5SDimitry Andric                                const SDLoc &dl, SelectionDAG &DAG) const {
6490b57cec5SDimitry Andric   auto *AFI = DAG.getMachineFunction().getInfo<ARCFunctionInfo>();
6500b57cec5SDimitry Andric   MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric   // CCValAssign - represent the assignment of
6530b57cec5SDimitry Andric   // the return value to a location
6540b57cec5SDimitry Andric   SmallVector<CCValAssign, 16> RVLocs;
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric   // CCState - Info about the registers and stack slot.
6570b57cec5SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
6580b57cec5SDimitry Andric                  *DAG.getContext());
6590b57cec5SDimitry Andric 
6600b57cec5SDimitry Andric   // Analyze return values.
6610b57cec5SDimitry Andric   if (!IsVarArg)
6625ffd83dbSDimitry Andric     CCInfo.AllocateStack(AFI->getReturnStackOffset(), Align(4));
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   CCInfo.AnalyzeReturn(Outs, RetCC_ARC);
6650b57cec5SDimitry Andric 
66606c3fb27SDimitry Andric   SDValue Glue;
6670b57cec5SDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
6680b57cec5SDimitry Andric   SmallVector<SDValue, 4> MemOpChains;
6690b57cec5SDimitry Andric   // Handle return values that must be copied to memory.
6700b57cec5SDimitry Andric   for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
6710b57cec5SDimitry Andric     CCValAssign &VA = RVLocs[i];
6720b57cec5SDimitry Andric     if (VA.isRegLoc())
6730b57cec5SDimitry Andric       continue;
6740b57cec5SDimitry Andric     assert(VA.isMemLoc());
6750b57cec5SDimitry Andric     if (IsVarArg) {
6760b57cec5SDimitry Andric       report_fatal_error("Can't return value from vararg function in memory");
6770b57cec5SDimitry Andric     }
6780b57cec5SDimitry Andric 
6790b57cec5SDimitry Andric     int Offset = VA.getLocMemOffset();
6800b57cec5SDimitry Andric     unsigned ObjSize = VA.getLocVT().getStoreSize();
6810b57cec5SDimitry Andric     // Create the frame index object for the memory location.
6820b57cec5SDimitry Andric     int FI = MFI.CreateFixedObject(ObjSize, Offset, false);
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric     // Create a SelectionDAG node corresponding to a store
6850b57cec5SDimitry Andric     // to this memory location.
6860b57cec5SDimitry Andric     SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
6870b57cec5SDimitry Andric     MemOpChains.push_back(DAG.getStore(
6880b57cec5SDimitry Andric         Chain, dl, OutVals[i], FIN,
6890b57cec5SDimitry Andric         MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)));
6900b57cec5SDimitry Andric   }
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   // Transform all store nodes into one single node because
6930b57cec5SDimitry Andric   // all stores are independent of each other.
6940b57cec5SDimitry Andric   if (!MemOpChains.empty())
6950b57cec5SDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric   // Now handle return values copied to registers.
6980b57cec5SDimitry Andric   for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
6990b57cec5SDimitry Andric     CCValAssign &VA = RVLocs[i];
7000b57cec5SDimitry Andric     if (!VA.isRegLoc())
7010b57cec5SDimitry Andric       continue;
7020b57cec5SDimitry Andric     // Copy the result values into the output registers.
70306c3fb27SDimitry Andric     Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Glue);
7040b57cec5SDimitry Andric 
7050b57cec5SDimitry Andric     // guarantee that all emitted copies are
7060b57cec5SDimitry Andric     // stuck together, avoiding something bad
70706c3fb27SDimitry Andric     Glue = Chain.getValue(1);
7080b57cec5SDimitry Andric     RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
7090b57cec5SDimitry Andric   }
7100b57cec5SDimitry Andric 
7110b57cec5SDimitry Andric   RetOps[0] = Chain; // Update chain.
7120b57cec5SDimitry Andric 
71306c3fb27SDimitry Andric   // Add the glue if we have it.
71406c3fb27SDimitry Andric   if (Glue.getNode())
71506c3fb27SDimitry Andric     RetOps.push_back(Glue);
7160b57cec5SDimitry Andric 
7170b57cec5SDimitry Andric   // What to do with the RetOps?
7180b57cec5SDimitry Andric   return DAG.getNode(ARCISD::RET, dl, MVT::Other, RetOps);
7190b57cec5SDimitry Andric }
7200b57cec5SDimitry Andric 
7210b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7220b57cec5SDimitry Andric // Target Optimization Hooks
7230b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7240b57cec5SDimitry Andric 
PerformDAGCombine(SDNode * N,DAGCombinerInfo & DCI) const7250b57cec5SDimitry Andric SDValue ARCTargetLowering::PerformDAGCombine(SDNode *N,
7260b57cec5SDimitry Andric                                              DAGCombinerInfo &DCI) const {
7270b57cec5SDimitry Andric   return {};
7280b57cec5SDimitry Andric }
7290b57cec5SDimitry Andric 
7300b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7310b57cec5SDimitry Andric //  Addressing mode description hooks
7320b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7330b57cec5SDimitry Andric 
7340b57cec5SDimitry Andric /// Return true if the addressing mode represented by AM is legal for this
7350b57cec5SDimitry Andric /// target, for a load/store of the specified type.
isLegalAddressingMode(const DataLayout & DL,const AddrMode & AM,Type * Ty,unsigned AS,Instruction * I) const7360b57cec5SDimitry Andric bool ARCTargetLowering::isLegalAddressingMode(const DataLayout &DL,
7370b57cec5SDimitry Andric                                               const AddrMode &AM, Type *Ty,
7380b57cec5SDimitry Andric                                               unsigned AS,
7390b57cec5SDimitry Andric                                               Instruction *I) const {
7400b57cec5SDimitry Andric   return AM.Scale == 0;
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric // Don't emit tail calls for the time being.
mayBeEmittedAsTailCall(const CallInst * CI) const7440b57cec5SDimitry Andric bool ARCTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
7450b57cec5SDimitry Andric   return false;
7460b57cec5SDimitry Andric }
7470b57cec5SDimitry Andric 
LowerFRAMEADDR(SDValue Op,SelectionDAG & DAG) const7480b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
7490b57cec5SDimitry Andric   const ARCRegisterInfo &ARI = *Subtarget.getRegisterInfo();
7500b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
7510b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
7520b57cec5SDimitry Andric   MFI.setFrameAddressIsTaken(true);
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric   EVT VT = Op.getValueType();
7550b57cec5SDimitry Andric   SDLoc dl(Op);
756647cbc5dSDimitry Andric   assert(Op.getConstantOperandVal(0) == 0 &&
7570b57cec5SDimitry Andric          "Only support lowering frame addr of current frame.");
7588bcb0991SDimitry Andric   Register FrameReg = ARI.getFrameRegister(MF);
7590b57cec5SDimitry Andric   return DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
7600b57cec5SDimitry Andric }
7610b57cec5SDimitry Andric 
LowerGlobalAddress(SDValue Op,SelectionDAG & DAG) const7620b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerGlobalAddress(SDValue Op,
7630b57cec5SDimitry Andric                                               SelectionDAG &DAG) const {
7640b57cec5SDimitry Andric   const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op);
7650b57cec5SDimitry Andric   const GlobalValue *GV = GN->getGlobal();
7660b57cec5SDimitry Andric   SDLoc dl(GN);
7670b57cec5SDimitry Andric   int64_t Offset = GN->getOffset();
7680b57cec5SDimitry Andric   SDValue GA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, Offset);
7690b57cec5SDimitry Andric   return DAG.getNode(ARCISD::GAWRAPPER, dl, MVT::i32, GA);
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric 
LowerVASTART(SDValue Op,SelectionDAG & DAG)7720b57cec5SDimitry Andric static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) {
7730b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
7740b57cec5SDimitry Andric   auto *FuncInfo = MF.getInfo<ARCFunctionInfo>();
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   // vastart just stores the address of the VarArgsFrameIndex slot into the
7770b57cec5SDimitry Andric   // memory location argument.
7780b57cec5SDimitry Andric   SDLoc dl(Op);
7790b57cec5SDimitry Andric   EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
7800b57cec5SDimitry Andric   SDValue FR = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT);
7810b57cec5SDimitry Andric   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
7820b57cec5SDimitry Andric   return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1),
7830b57cec5SDimitry Andric                       MachinePointerInfo(SV));
7840b57cec5SDimitry Andric }
7850b57cec5SDimitry Andric 
LowerOperation(SDValue Op,SelectionDAG & DAG) const7860b57cec5SDimitry Andric SDValue ARCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
7870b57cec5SDimitry Andric   switch (Op.getOpcode()) {
7880b57cec5SDimitry Andric   case ISD::GlobalAddress:
7890b57cec5SDimitry Andric     return LowerGlobalAddress(Op, DAG);
7900b57cec5SDimitry Andric   case ISD::FRAMEADDR:
7910b57cec5SDimitry Andric     return LowerFRAMEADDR(Op, DAG);
7920b57cec5SDimitry Andric   case ISD::SELECT_CC:
7930b57cec5SDimitry Andric     return LowerSELECT_CC(Op, DAG);
7940b57cec5SDimitry Andric   case ISD::BR_CC:
7950b57cec5SDimitry Andric     return LowerBR_CC(Op, DAG);
7960b57cec5SDimitry Andric   case ISD::SIGN_EXTEND_INREG:
7970b57cec5SDimitry Andric     return LowerSIGN_EXTEND_INREG(Op, DAG);
7980b57cec5SDimitry Andric   case ISD::JumpTable:
7990b57cec5SDimitry Andric     return LowerJumpTable(Op, DAG);
8000b57cec5SDimitry Andric   case ISD::VASTART:
8010b57cec5SDimitry Andric     return LowerVASTART(Op, DAG);
802349cc55cSDimitry Andric   case ISD::READCYCLECOUNTER:
803349cc55cSDimitry Andric     // As of LLVM 3.8, the lowering code insists that we customize it even
804349cc55cSDimitry Andric     // though we've declared the i32 version as legal. This is because it only
805349cc55cSDimitry Andric     // thinks i64 is the truly supported version. We've already converted the
806349cc55cSDimitry Andric     // i64 version to a widened i32.
807349cc55cSDimitry Andric     assert(Op.getSimpleValueType() == MVT::i32);
808349cc55cSDimitry Andric     return Op;
8090b57cec5SDimitry Andric   default:
8100b57cec5SDimitry Andric     llvm_unreachable("unimplemented operand");
8110b57cec5SDimitry Andric   }
8120b57cec5SDimitry Andric }
813