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