1//===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines an instruction selector for the ARC target.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ARC.h"
14#include "ARCTargetMachine.h"
15#include "llvm/CodeGen/MachineFrameInfo.h"
16#include "llvm/CodeGen/MachineFunction.h"
17#include "llvm/CodeGen/MachineInstrBuilder.h"
18#include "llvm/CodeGen/MachineRegisterInfo.h"
19#include "llvm/CodeGen/SelectionDAG.h"
20#include "llvm/CodeGen/SelectionDAGISel.h"
21#include "llvm/CodeGen/TargetLowering.h"
22#include "llvm/IR/CallingConv.h"
23#include "llvm/IR/Constants.h"
24#include "llvm/IR/DerivedTypes.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/Intrinsics.h"
27#include "llvm/IR/LLVMContext.h"
28#include "llvm/Support/Compiler.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/raw_ostream.h"
32
33using namespace llvm;
34
35/// ARCDAGToDAGISel - ARC specific code to select ARC machine
36/// instructions for SelectionDAG operations.
37namespace {
38
39class ARCDAGToDAGISel : public SelectionDAGISel {
40public:
41  ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOpt::Level OptLevel)
42      : SelectionDAGISel(TM, OptLevel) {}
43
44  void Select(SDNode *N) override;
45
46  // Complex Pattern Selectors.
47  bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset);
48  bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset);
49  bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset);
50  bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset);
51  bool SelectCMOVPred(SDValue N, SDValue &Pred, SDValue &Reg) {
52    const ConstantSDNode *CN = cast<ConstantSDNode>(N);
53    Pred = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), MVT::i32);
54    Reg = CurDAG->getRegister(ARC::STATUS32, MVT::i32);
55    return true;
56  }
57
58  StringRef getPassName() const override {
59    return "ARC DAG->DAG Pattern Instruction Selection";
60  }
61
62// Include the pieces autogenerated from the target description.
63#include "ARCGenDAGISel.inc"
64};
65
66} // end anonymous namespace
67
68/// This pass converts a legalized DAG into a ARC-specific DAG, ready for
69/// instruction scheduling.
70FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM,
71                                     CodeGenOpt::Level OptLevel) {
72  return new ARCDAGToDAGISel(TM, OptLevel);
73}
74
75bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base,
76                                        SDValue &Offset) {
77  if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
78    Base = Addr.getOperand(0);
79    Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
80    return true;
81  }
82  return false;
83}
84
85bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base,
86                                       SDValue &Offset) {
87  if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
88    return false;
89  }
90
91  if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB &&
92      !CurDAG->isBaseWithConstantOffset(Addr)) {
93    if (Addr.getOpcode() == ISD::FrameIndex) {
94      // Match frame index.
95      int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
96      Base = CurDAG->getTargetFrameIndex(
97          FI, TLI->getPointerTy(CurDAG->getDataLayout()));
98    } else {
99      Base = Addr;
100    }
101    Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
102    return true;
103  }
104
105  if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
106    int32_t RHSC = RHS->getSExtValue();
107    if (Addr.getOpcode() == ISD::SUB)
108      RHSC = -RHSC;
109
110    // Do we need more than 9 bits to encode?
111    if (!isInt<9>(RHSC))
112      return false;
113    Base = Addr.getOperand(0);
114    if (Base.getOpcode() == ISD::FrameIndex) {
115      int FI = cast<FrameIndexSDNode>(Base)->getIndex();
116      Base = CurDAG->getTargetFrameIndex(
117          FI, TLI->getPointerTy(CurDAG->getDataLayout()));
118    }
119    Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
120    return true;
121  }
122  Base = Addr;
123  Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
124  return true;
125}
126
127bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base,
128                                        SDValue &Offset) {
129  if (SelectAddrModeS9(Addr, Base, Offset))
130    return false;
131  if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
132    return false;
133  }
134  if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
135    int32_t RHSC = RHS->getSExtValue();
136    if (Addr.getOpcode() == ISD::SUB)
137      RHSC = -RHSC;
138    Base = Addr.getOperand(0);
139    Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
140    return true;
141  }
142  return false;
143}
144
145// Is this a legal frame index addressing expression.
146bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base,
147                                         SDValue &Offset) {
148  FrameIndexSDNode *FIN = nullptr;
149  if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
150    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
151    Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
152    return true;
153  }
154  if (Addr.getOpcode() == ISD::ADD) {
155    ConstantSDNode *CN = nullptr;
156    if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
157        (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
158        (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
159      // Constant positive word offset from frame index
160      Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
161      Offset =
162          CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32);
163      return true;
164    }
165  }
166  return false;
167}
168
169void ARCDAGToDAGISel::Select(SDNode *N) {
170  switch (N->getOpcode()) {
171  case ISD::Constant: {
172    uint64_t CVal = cast<ConstantSDNode>(N)->getZExtValue();
173    ReplaceNode(N, CurDAG->getMachineNode(
174                       isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm,
175                       SDLoc(N), MVT::i32,
176                       CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32)));
177    return;
178  }
179  }
180  SelectCode(N);
181}
182