10b57cec5SDimitry Andric //===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- 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 defines an instruction selector for the ARC target. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "ARC.h" 140b57cec5SDimitry Andric #include "ARCTargetMachine.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 220b57cec5SDimitry Andric #include "llvm/IR/CallingConv.h" 230b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 240b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 250b57cec5SDimitry Andric #include "llvm/IR/Function.h" 260b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 270b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 280b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 290b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 300b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 310b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric using namespace llvm; 340b57cec5SDimitry Andric 35bdd1243dSDimitry Andric #define DEBUG_TYPE "arc-isel" 36bdd1243dSDimitry Andric #define PASS_NAME "ARC DAG->DAG Pattern Instruction Selection" 37bdd1243dSDimitry Andric 380b57cec5SDimitry Andric /// ARCDAGToDAGISel - ARC specific code to select ARC machine 390b57cec5SDimitry Andric /// instructions for SelectionDAG operations. 400b57cec5SDimitry Andric namespace { 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric class ARCDAGToDAGISel : public SelectionDAGISel { 430b57cec5SDimitry Andric public: 44bdd1243dSDimitry Andric ARCDAGToDAGISel() = delete; 45bdd1243dSDimitry Andric 465f757f3fSDimitry Andric ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOptLevel OptLevel) 47*0fca6ea1SDimitry Andric : SelectionDAGISel(TM, OptLevel) {} 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric void Select(SDNode *N) override; 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric // Complex Pattern Selectors. 520b57cec5SDimitry Andric bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset); 530b57cec5SDimitry Andric bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset); 540b57cec5SDimitry Andric bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset); 550b57cec5SDimitry Andric bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset); 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // Include the pieces autogenerated from the target description. 580b57cec5SDimitry Andric #include "ARCGenDAGISel.inc" 590b57cec5SDimitry Andric }; 600b57cec5SDimitry Andric 61*0fca6ea1SDimitry Andric class ARCDAGToDAGISelLegacy : public SelectionDAGISelLegacy { 62*0fca6ea1SDimitry Andric public: 63*0fca6ea1SDimitry Andric static char ID; 64*0fca6ea1SDimitry Andric explicit ARCDAGToDAGISelLegacy(ARCTargetMachine &TM, CodeGenOptLevel OptLevel) 65*0fca6ea1SDimitry Andric : SelectionDAGISelLegacy( 66*0fca6ea1SDimitry Andric ID, std::make_unique<ARCDAGToDAGISel>(TM, OptLevel)) {} 67*0fca6ea1SDimitry Andric }; 68*0fca6ea1SDimitry Andric 69*0fca6ea1SDimitry Andric char ARCDAGToDAGISelLegacy::ID; 70bdd1243dSDimitry Andric 710b57cec5SDimitry Andric } // end anonymous namespace 720b57cec5SDimitry Andric 73*0fca6ea1SDimitry Andric INITIALIZE_PASS(ARCDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) 74bdd1243dSDimitry Andric 750b57cec5SDimitry Andric /// This pass converts a legalized DAG into a ARC-specific DAG, ready for 760b57cec5SDimitry Andric /// instruction scheduling. 770b57cec5SDimitry Andric FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM, 785f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 79*0fca6ea1SDimitry Andric return new ARCDAGToDAGISelLegacy(TM, OptLevel); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base, 830b57cec5SDimitry Andric SDValue &Offset) { 840b57cec5SDimitry Andric if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 850b57cec5SDimitry Andric Base = Addr.getOperand(0); 860b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 870b57cec5SDimitry Andric return true; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric return false; 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base, 930b57cec5SDimitry Andric SDValue &Offset) { 940b57cec5SDimitry Andric if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 950b57cec5SDimitry Andric return false; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB && 990b57cec5SDimitry Andric !CurDAG->isBaseWithConstantOffset(Addr)) { 1000b57cec5SDimitry Andric if (Addr.getOpcode() == ISD::FrameIndex) { 1010b57cec5SDimitry Andric // Match frame index. 1020b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Addr)->getIndex(); 1030b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex( 1040b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 1050b57cec5SDimitry Andric } else { 1060b57cec5SDimitry Andric Base = Addr; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 1090b57cec5SDimitry Andric return true; 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 1130b57cec5SDimitry Andric int32_t RHSC = RHS->getSExtValue(); 1140b57cec5SDimitry Andric if (Addr.getOpcode() == ISD::SUB) 1150b57cec5SDimitry Andric RHSC = -RHSC; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // Do we need more than 9 bits to encode? 1180b57cec5SDimitry Andric if (!isInt<9>(RHSC)) 1190b57cec5SDimitry Andric return false; 1200b57cec5SDimitry Andric Base = Addr.getOperand(0); 1210b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 1220b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 1230b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex( 1240b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); 1270b57cec5SDimitry Andric return true; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric Base = Addr; 1300b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 1310b57cec5SDimitry Andric return true; 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base, 1350b57cec5SDimitry Andric SDValue &Offset) { 1360b57cec5SDimitry Andric if (SelectAddrModeS9(Addr, Base, Offset)) 1370b57cec5SDimitry Andric return false; 1380b57cec5SDimitry Andric if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 1390b57cec5SDimitry Andric return false; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 1420b57cec5SDimitry Andric int32_t RHSC = RHS->getSExtValue(); 1430b57cec5SDimitry Andric if (Addr.getOpcode() == ISD::SUB) 1440b57cec5SDimitry Andric RHSC = -RHSC; 1450b57cec5SDimitry Andric Base = Addr.getOperand(0); 1460b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); 1470b57cec5SDimitry Andric return true; 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric return false; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric // Is this a legal frame index addressing expression. 1530b57cec5SDimitry Andric bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base, 1540b57cec5SDimitry Andric SDValue &Offset) { 1550b57cec5SDimitry Andric FrameIndexSDNode *FIN = nullptr; 1560b57cec5SDimitry Andric if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { 1570b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1580b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 1590b57cec5SDimitry Andric return true; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric if (Addr.getOpcode() == ISD::ADD) { 1620b57cec5SDimitry Andric ConstantSDNode *CN = nullptr; 1630b57cec5SDimitry Andric if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) && 1640b57cec5SDimitry Andric (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && 1650b57cec5SDimitry Andric (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { 1660b57cec5SDimitry Andric // Constant positive word offset from frame index 1670b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1680b57cec5SDimitry Andric Offset = 1690b57cec5SDimitry Andric CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32); 1700b57cec5SDimitry Andric return true; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric return false; 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric void ARCDAGToDAGISel::Select(SDNode *N) { 1770b57cec5SDimitry Andric switch (N->getOpcode()) { 1780b57cec5SDimitry Andric case ISD::Constant: { 1791db9f3b2SDimitry Andric uint64_t CVal = N->getAsZExtVal(); 1800b57cec5SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode( 1810b57cec5SDimitry Andric isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm, 1820b57cec5SDimitry Andric SDLoc(N), MVT::i32, 1830b57cec5SDimitry Andric CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32))); 1840b57cec5SDimitry Andric return; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric SelectCode(N); 1880b57cec5SDimitry Andric } 189