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