//===- 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 "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(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(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(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(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(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(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(Addr.getOperand(0))) && (CN = dyn_cast(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); }