xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARC/ARCISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
ARCDAGToDAGISel(ARCTargetMachine & TM,CodeGenOptLevel OptLevel)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;
ARCDAGToDAGISelLegacy(ARCTargetMachine & TM,CodeGenOptLevel OptLevel)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 
INITIALIZE_PASS(ARCDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)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 
SelectAddrModeImm(SDValue Addr,SDValue & Base,SDValue & Offset)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 
SelectAddrModeS9(SDValue Addr,SDValue & Base,SDValue & Offset)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 
SelectAddrModeFar(SDValue Addr,SDValue & Base,SDValue & Offset)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.
SelectFrameADDR_ri(SDValue Addr,SDValue & Base,SDValue & Offset)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 
Select(SDNode * N)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