768 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			768 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- 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), 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: {
 | |
|         LLVM_DEBUG(errs() << "LowerFormalArguments Unhandled argument type: "
 | |
|                           << (unsigned)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");
 | |
|   }
 | |
| }
 |