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   static char ID;
45bdd1243dSDimitry Andric 
46bdd1243dSDimitry Andric   ARCDAGToDAGISel() = delete;
47bdd1243dSDimitry Andric 
ARCDAGToDAGISel(ARCTargetMachine & TM,CodeGenOptLevel OptLevel)485f757f3fSDimitry Andric   ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOptLevel OptLevel)
49bdd1243dSDimitry Andric       : SelectionDAGISel(ID, TM, OptLevel) {}
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   void Select(SDNode *N) override;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   // Complex Pattern Selectors.
540b57cec5SDimitry Andric   bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset);
550b57cec5SDimitry Andric   bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset);
560b57cec5SDimitry Andric   bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset);
570b57cec5SDimitry Andric   bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset);
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric // Include the pieces autogenerated from the target description.
600b57cec5SDimitry Andric #include "ARCGenDAGISel.inc"
610b57cec5SDimitry Andric };
620b57cec5SDimitry Andric 
63bdd1243dSDimitry Andric char ARCDAGToDAGISel::ID;
64bdd1243dSDimitry Andric 
650b57cec5SDimitry Andric } // end anonymous namespace
660b57cec5SDimitry Andric 
INITIALIZE_PASS(ARCDAGToDAGISel,DEBUG_TYPE,PASS_NAME,false,false)67bdd1243dSDimitry Andric INITIALIZE_PASS(ARCDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
68bdd1243dSDimitry Andric 
690b57cec5SDimitry Andric /// This pass converts a legalized DAG into a ARC-specific DAG, ready for
700b57cec5SDimitry Andric /// instruction scheduling.
710b57cec5SDimitry Andric FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM,
725f757f3fSDimitry Andric                                      CodeGenOptLevel OptLevel) {
730b57cec5SDimitry Andric   return new ARCDAGToDAGISel(TM, OptLevel);
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric 
SelectAddrModeImm(SDValue Addr,SDValue & Base,SDValue & Offset)760b57cec5SDimitry Andric bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base,
770b57cec5SDimitry Andric                                         SDValue &Offset) {
780b57cec5SDimitry Andric   if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
790b57cec5SDimitry Andric     Base = Addr.getOperand(0);
800b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
810b57cec5SDimitry Andric     return true;
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric   return false;
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
SelectAddrModeS9(SDValue Addr,SDValue & Base,SDValue & Offset)860b57cec5SDimitry Andric bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base,
870b57cec5SDimitry Andric                                        SDValue &Offset) {
880b57cec5SDimitry Andric   if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
890b57cec5SDimitry Andric     return false;
900b57cec5SDimitry Andric   }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB &&
930b57cec5SDimitry Andric       !CurDAG->isBaseWithConstantOffset(Addr)) {
940b57cec5SDimitry Andric     if (Addr.getOpcode() == ISD::FrameIndex) {
950b57cec5SDimitry Andric       // Match frame index.
960b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
970b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
980b57cec5SDimitry Andric           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
990b57cec5SDimitry Andric     } else {
1000b57cec5SDimitry Andric       Base = Addr;
1010b57cec5SDimitry Andric     }
1020b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
1030b57cec5SDimitry Andric     return true;
1040b57cec5SDimitry Andric   }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
1070b57cec5SDimitry Andric     int32_t RHSC = RHS->getSExtValue();
1080b57cec5SDimitry Andric     if (Addr.getOpcode() == ISD::SUB)
1090b57cec5SDimitry Andric       RHSC = -RHSC;
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric     // Do we need more than 9 bits to encode?
1120b57cec5SDimitry Andric     if (!isInt<9>(RHSC))
1130b57cec5SDimitry Andric       return false;
1140b57cec5SDimitry Andric     Base = Addr.getOperand(0);
1150b57cec5SDimitry Andric     if (Base.getOpcode() == ISD::FrameIndex) {
1160b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(Base)->getIndex();
1170b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
1180b57cec5SDimitry Andric           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
1190b57cec5SDimitry Andric     }
1200b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
1210b57cec5SDimitry Andric     return true;
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric   Base = Addr;
1240b57cec5SDimitry Andric   Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
1250b57cec5SDimitry Andric   return true;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
SelectAddrModeFar(SDValue Addr,SDValue & Base,SDValue & Offset)1280b57cec5SDimitry Andric bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base,
1290b57cec5SDimitry Andric                                         SDValue &Offset) {
1300b57cec5SDimitry Andric   if (SelectAddrModeS9(Addr, Base, Offset))
1310b57cec5SDimitry Andric     return false;
1320b57cec5SDimitry Andric   if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
1330b57cec5SDimitry Andric     return false;
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric   if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
1360b57cec5SDimitry Andric     int32_t RHSC = RHS->getSExtValue();
1370b57cec5SDimitry Andric     if (Addr.getOpcode() == ISD::SUB)
1380b57cec5SDimitry Andric       RHSC = -RHSC;
1390b57cec5SDimitry Andric     Base = Addr.getOperand(0);
1400b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
1410b57cec5SDimitry Andric     return true;
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric   return false;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric // Is this a legal frame index addressing expression.
SelectFrameADDR_ri(SDValue Addr,SDValue & Base,SDValue & Offset)1470b57cec5SDimitry Andric bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base,
1480b57cec5SDimitry Andric                                          SDValue &Offset) {
1490b57cec5SDimitry Andric   FrameIndexSDNode *FIN = nullptr;
1500b57cec5SDimitry Andric   if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
1510b57cec5SDimitry Andric     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
1520b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
1530b57cec5SDimitry Andric     return true;
1540b57cec5SDimitry Andric   }
1550b57cec5SDimitry Andric   if (Addr.getOpcode() == ISD::ADD) {
1560b57cec5SDimitry Andric     ConstantSDNode *CN = nullptr;
1570b57cec5SDimitry Andric     if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
1580b57cec5SDimitry Andric         (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
1590b57cec5SDimitry Andric         (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
1600b57cec5SDimitry Andric       // Constant positive word offset from frame index
1610b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
1620b57cec5SDimitry Andric       Offset =
1630b57cec5SDimitry Andric           CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32);
1640b57cec5SDimitry Andric       return true;
1650b57cec5SDimitry Andric     }
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric   return false;
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
Select(SDNode * N)1700b57cec5SDimitry Andric void ARCDAGToDAGISel::Select(SDNode *N) {
1710b57cec5SDimitry Andric   switch (N->getOpcode()) {
1720b57cec5SDimitry Andric   case ISD::Constant: {
1731db9f3b2SDimitry Andric     uint64_t CVal = N->getAsZExtVal();
1740b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(
1750b57cec5SDimitry Andric                        isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm,
1760b57cec5SDimitry Andric                        SDLoc(N), MVT::i32,
1770b57cec5SDimitry Andric                        CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32)));
1780b57cec5SDimitry Andric     return;
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric   }
1810b57cec5SDimitry Andric   SelectCode(N);
1820b57cec5SDimitry Andric }
183