|  | //===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines an instruction selector for the ARC target. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "ARC.h" | 
|  | #include "ARCSelectionDAGInfo.h" | 
|  | #include "ARCTargetMachine.h" | 
|  | #include "llvm/CodeGen/MachineFrameInfo.h" | 
|  | #include "llvm/CodeGen/MachineFunction.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | #include "llvm/CodeGen/SelectionDAG.h" | 
|  | #include "llvm/CodeGen/SelectionDAGISel.h" | 
|  | #include "llvm/CodeGen/TargetLowering.h" | 
|  | #include "llvm/IR/CallingConv.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/DerivedTypes.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/Intrinsics.h" | 
|  | #include "llvm/IR/LLVMContext.h" | 
|  | #include "llvm/Support/Compiler.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "arc-isel" | 
|  | #define PASS_NAME "ARC DAG->DAG Pattern Instruction Selection" | 
|  |  | 
|  | /// ARCDAGToDAGISel - ARC specific code to select ARC machine | 
|  | /// instructions for SelectionDAG operations. | 
|  | namespace { | 
|  |  | 
|  | class ARCDAGToDAGISel : public SelectionDAGISel { | 
|  | public: | 
|  | ARCDAGToDAGISel() = delete; | 
|  |  | 
|  | ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOptLevel OptLevel) | 
|  | : SelectionDAGISel(TM, OptLevel) {} | 
|  |  | 
|  | void Select(SDNode *N) override; | 
|  |  | 
|  | // Complex Pattern Selectors. | 
|  | bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset); | 
|  | bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset); | 
|  | bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset); | 
|  | bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset); | 
|  |  | 
|  | // Include the pieces autogenerated from the target description. | 
|  | #include "ARCGenDAGISel.inc" | 
|  | }; | 
|  |  | 
|  | class ARCDAGToDAGISelLegacy : public SelectionDAGISelLegacy { | 
|  | public: | 
|  | static char ID; | 
|  | explicit ARCDAGToDAGISelLegacy(ARCTargetMachine &TM, CodeGenOptLevel OptLevel) | 
|  | : SelectionDAGISelLegacy( | 
|  | ID, std::make_unique<ARCDAGToDAGISel>(TM, OptLevel)) {} | 
|  | }; | 
|  |  | 
|  | char ARCDAGToDAGISelLegacy::ID; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | INITIALIZE_PASS(ARCDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) | 
|  |  | 
|  | /// This pass converts a legalized DAG into a ARC-specific DAG, ready for | 
|  | /// instruction scheduling. | 
|  | FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM, | 
|  | CodeGenOptLevel OptLevel) { | 
|  | return new ARCDAGToDAGISelLegacy(TM, OptLevel); | 
|  | } | 
|  |  | 
|  | bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base, | 
|  | SDValue &Offset) { | 
|  | if (Addr.getOpcode() == ARCISD::GAWRAPPER) { | 
|  | Base = Addr.getOperand(0); | 
|  | Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base, | 
|  | SDValue &Offset) { | 
|  | if (Addr.getOpcode() == ARCISD::GAWRAPPER) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB && | 
|  | !CurDAG->isBaseWithConstantOffset(Addr)) { | 
|  | if (Addr.getOpcode() == ISD::FrameIndex) { | 
|  | // Match frame index. | 
|  | int FI = cast<FrameIndexSDNode>(Addr)->getIndex(); | 
|  | Base = CurDAG->getTargetFrameIndex( | 
|  | FI, TLI->getPointerTy(CurDAG->getDataLayout())); | 
|  | } else { | 
|  | Base = Addr; | 
|  | } | 
|  | Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { | 
|  | int32_t RHSC = RHS->getSExtValue(); | 
|  | if (Addr.getOpcode() == ISD::SUB) | 
|  | RHSC = -RHSC; | 
|  |  | 
|  | // Do we need more than 9 bits to encode? | 
|  | if (!isInt<9>(RHSC)) | 
|  | return false; | 
|  | Base = Addr.getOperand(0); | 
|  | if (Base.getOpcode() == ISD::FrameIndex) { | 
|  | int FI = cast<FrameIndexSDNode>(Base)->getIndex(); | 
|  | Base = CurDAG->getTargetFrameIndex( | 
|  | FI, TLI->getPointerTy(CurDAG->getDataLayout())); | 
|  | } | 
|  | Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); | 
|  | return true; | 
|  | } | 
|  | Base = Addr; | 
|  | Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base, | 
|  | SDValue &Offset) { | 
|  | if (SelectAddrModeS9(Addr, Base, Offset)) | 
|  | return false; | 
|  | if (Addr.getOpcode() == ARCISD::GAWRAPPER) { | 
|  | return false; | 
|  | } | 
|  | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { | 
|  | int32_t RHSC = RHS->getSExtValue(); | 
|  | if (Addr.getOpcode() == ISD::SUB) | 
|  | RHSC = -RHSC; | 
|  | Base = Addr.getOperand(0); | 
|  | Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Is this a legal frame index addressing expression. | 
|  | bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base, | 
|  | SDValue &Offset) { | 
|  | FrameIndexSDNode *FIN = nullptr; | 
|  | if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { | 
|  | Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); | 
|  | Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); | 
|  | return true; | 
|  | } | 
|  | if (Addr.getOpcode() == ISD::ADD) { | 
|  | ConstantSDNode *CN = nullptr; | 
|  | if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) && | 
|  | (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && | 
|  | (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { | 
|  | // Constant positive word offset from frame index | 
|  | Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); | 
|  | Offset = | 
|  | CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void ARCDAGToDAGISel::Select(SDNode *N) { | 
|  | switch (N->getOpcode()) { | 
|  | case ISD::Constant: { | 
|  | uint64_t CVal = N->getAsZExtVal(); | 
|  | ReplaceNode(N, CurDAG->getMachineNode( | 
|  | isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm, | 
|  | SDLoc(N), MVT::i32, | 
|  | CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32))); | 
|  | return; | 
|  | } | 
|  | } | 
|  | SelectCode(N); | 
|  | } |