1 | //===-- LanaiISelDAGToDAG.cpp - A dag to dag inst selector for Lanai ------===// |
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 Lanai target. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "LanaiAluCode.h" |
14 | #include "LanaiTargetMachine.h" |
15 | #include "llvm/CodeGen/MachineConstantPool.h" |
16 | #include "llvm/CodeGen/MachineFrameInfo.h" |
17 | #include "llvm/CodeGen/MachineFunction.h" |
18 | #include "llvm/CodeGen/SelectionDAGISel.h" |
19 | #include "llvm/IR/Instructions.h" |
20 | #include "llvm/IR/Type.h" |
21 | #include "llvm/Support/Debug.h" |
22 | #include "llvm/Support/ErrorHandling.h" |
23 | #include "llvm/Support/raw_ostream.h" |
24 | |
25 | using namespace llvm; |
26 | |
27 | #define DEBUG_TYPE "lanai-isel" |
28 | #define PASS_NAME "Lanai DAG->DAG Pattern Instruction Selection" |
29 | |
30 | //===----------------------------------------------------------------------===// |
31 | // Instruction Selector Implementation |
32 | //===----------------------------------------------------------------------===// |
33 | |
34 | //===----------------------------------------------------------------------===// |
35 | // LanaiDAGToDAGISel - Lanai specific code to select Lanai machine |
36 | // instructions for SelectionDAG operations. |
37 | //===----------------------------------------------------------------------===// |
38 | namespace { |
39 | |
40 | class LanaiDAGToDAGISel : public SelectionDAGISel { |
41 | public: |
42 | LanaiDAGToDAGISel() = delete; |
43 | |
44 | explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine) |
45 | : SelectionDAGISel(TargetMachine) {} |
46 | |
47 | bool SelectInlineAsmMemoryOperand(const SDValue &Op, |
48 | InlineAsm::ConstraintCode ConstraintCode, |
49 | std::vector<SDValue> &OutOps) override; |
50 | |
51 | private: |
52 | // Include the pieces autogenerated from the target description. |
53 | #include "LanaiGenDAGISel.inc" |
54 | |
55 | // Instruction Selection not handled by the auto-generated tablgen |
56 | void Select(SDNode *N) override; |
57 | |
58 | // Support functions for the opcodes of Instruction Selection |
59 | // not handled by the auto-generated tablgen |
60 | void selectFrameIndex(SDNode *N); |
61 | |
62 | // Complex Pattern for address selection. |
63 | bool selectAddrRi(SDValue Addr, SDValue &Base, SDValue &Offset, |
64 | SDValue &AluOp); |
65 | bool selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, SDValue &AluOp); |
66 | bool selectAddrSls(SDValue Addr, SDValue &Offset); |
67 | bool selectAddrSpls(SDValue Addr, SDValue &Base, SDValue &Offset, |
68 | SDValue &AluOp); |
69 | |
70 | // getI32Imm - Return a target constant with the specified value, of type i32. |
71 | inline SDValue getI32Imm(unsigned Imm, const SDLoc &DL) { |
72 | return CurDAG->getTargetConstant(Val: Imm, DL, VT: MVT::i32); |
73 | } |
74 | |
75 | private: |
76 | bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset, |
77 | SDValue &AluOp, bool RiMode); |
78 | }; |
79 | |
80 | bool canBeRepresentedAsSls(const ConstantSDNode &CN) { |
81 | // Fits in 21-bit signed immediate and two low-order bits are zero. |
82 | return isInt<21>(x: CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0); |
83 | } |
84 | |
85 | class LanaiDAGToDAGISelLegacy : public SelectionDAGISelLegacy { |
86 | public: |
87 | static char ID; |
88 | explicit LanaiDAGToDAGISelLegacy(LanaiTargetMachine &TM) |
89 | : SelectionDAGISelLegacy(ID, std::make_unique<LanaiDAGToDAGISel>(args&: TM)) {} |
90 | }; |
91 | |
92 | } // namespace |
93 | |
94 | char LanaiDAGToDAGISelLegacy::ID = 0; |
95 | |
96 | INITIALIZE_PASS(LanaiDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) |
97 | |
98 | // Helper functions for ComplexPattern used on LanaiInstrInfo |
99 | // Used on Lanai Load/Store instructions. |
100 | bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) { |
101 | if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val&: Addr)) { |
102 | SDLoc DL(Addr); |
103 | // Loading from a constant address. |
104 | if (canBeRepresentedAsSls(CN: *CN)) { |
105 | int32_t Imm = CN->getSExtValue(); |
106 | Offset = CurDAG->getTargetConstant(Val: Imm, DL, VT: CN->getValueType(ResNo: 0)); |
107 | return true; |
108 | } |
109 | } |
110 | if (Addr.getOpcode() == ISD::OR && |
111 | Addr.getOperand(i: 1).getOpcode() == LanaiISD::SMALL) { |
112 | Offset = Addr.getOperand(i: 1).getOperand(i: 0); |
113 | return true; |
114 | } |
115 | return false; |
116 | } |
117 | |
118 | bool LanaiDAGToDAGISel::selectAddrRiSpls(SDValue Addr, SDValue &Base, |
119 | SDValue &Offset, SDValue &AluOp, |
120 | bool RiMode) { |
121 | SDLoc DL(Addr); |
122 | |
123 | if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val&: Addr)) { |
124 | if (RiMode) { |
125 | // Fits in 16-bit signed immediate. |
126 | if (isInt<16>(x: CN->getSExtValue())) { |
127 | int16_t Imm = CN->getSExtValue(); |
128 | Offset = CurDAG->getTargetConstant(Val: Imm, DL, VT: CN->getValueType(ResNo: 0)); |
129 | Base = CurDAG->getRegister(Reg: Lanai::R0, VT: CN->getValueType(ResNo: 0)); |
130 | AluOp = CurDAG->getTargetConstant(Val: LPAC::ADD, DL, VT: MVT::i32); |
131 | return true; |
132 | } |
133 | // Allow SLS to match if the constant doesn't fit in 16 bits but can be |
134 | // represented as an SLS. |
135 | if (canBeRepresentedAsSls(CN: *CN)) |
136 | return false; |
137 | } else { |
138 | // Fits in 10-bit signed immediate. |
139 | if (isInt<10>(x: CN->getSExtValue())) { |
140 | int16_t Imm = CN->getSExtValue(); |
141 | Offset = CurDAG->getTargetConstant(Val: Imm, DL, VT: CN->getValueType(ResNo: 0)); |
142 | Base = CurDAG->getRegister(Reg: Lanai::R0, VT: CN->getValueType(ResNo: 0)); |
143 | AluOp = CurDAG->getTargetConstant(Val: LPAC::ADD, DL, VT: MVT::i32); |
144 | return true; |
145 | } |
146 | } |
147 | } |
148 | |
149 | // if Address is FI, get the TargetFrameIndex. |
150 | if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Val&: Addr)) { |
151 | Base = CurDAG->getTargetFrameIndex( |
152 | FI: FIN->getIndex(), |
153 | VT: getTargetLowering()->getPointerTy(DL: CurDAG->getDataLayout())); |
154 | Offset = CurDAG->getTargetConstant(Val: 0, DL, VT: MVT::i32); |
155 | AluOp = CurDAG->getTargetConstant(Val: LPAC::ADD, DL, VT: MVT::i32); |
156 | return true; |
157 | } |
158 | |
159 | // Skip direct calls |
160 | if ((Addr.getOpcode() == ISD::TargetExternalSymbol || |
161 | Addr.getOpcode() == ISD::TargetGlobalAddress)) |
162 | return false; |
163 | |
164 | // Address of the form imm + reg |
165 | ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode()); |
166 | if (AluOperator == ISD::ADD) { |
167 | AluOp = CurDAG->getTargetConstant(Val: LPAC::ADD, DL, VT: MVT::i32); |
168 | // Addresses of the form FI+const |
169 | if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val: Addr.getOperand(i: 1))) |
170 | if ((RiMode && isInt<16>(x: CN->getSExtValue())) || |
171 | (!RiMode && isInt<10>(x: CN->getSExtValue()))) { |
172 | // If the first operand is a FI, get the TargetFI Node |
173 | if (FrameIndexSDNode *FIN = |
174 | dyn_cast<FrameIndexSDNode>(Val: Addr.getOperand(i: 0))) { |
175 | Base = CurDAG->getTargetFrameIndex( |
176 | FI: FIN->getIndex(), |
177 | VT: getTargetLowering()->getPointerTy(DL: CurDAG->getDataLayout())); |
178 | } else { |
179 | Base = Addr.getOperand(i: 0); |
180 | } |
181 | |
182 | Offset = CurDAG->getTargetConstant(Val: CN->getSExtValue(), DL, VT: MVT::i32); |
183 | return true; |
184 | } |
185 | } |
186 | |
187 | // Let SLS match SMALL instead of RI. |
188 | if (AluOperator == ISD::OR && RiMode && |
189 | Addr.getOperand(i: 1).getOpcode() == LanaiISD::SMALL) |
190 | return false; |
191 | |
192 | Base = Addr; |
193 | Offset = CurDAG->getTargetConstant(Val: 0, DL, VT: MVT::i32); |
194 | AluOp = CurDAG->getTargetConstant(Val: LPAC::ADD, DL, VT: MVT::i32); |
195 | return true; |
196 | } |
197 | |
198 | bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base, |
199 | SDValue &Offset, SDValue &AluOp) { |
200 | return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/true); |
201 | } |
202 | |
203 | bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base, |
204 | SDValue &Offset, SDValue &AluOp) { |
205 | return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false); |
206 | } |
207 | |
208 | namespace llvm { |
209 | namespace LPAC { |
210 | static AluCode isdToLanaiAluCode(ISD::NodeType Node_type) { |
211 | switch (Node_type) { |
212 | case ISD::ADD: |
213 | return AluCode::ADD; |
214 | case ISD::ADDE: |
215 | return AluCode::ADDC; |
216 | case ISD::SUB: |
217 | return AluCode::SUB; |
218 | case ISD::SUBE: |
219 | return AluCode::SUBB; |
220 | case ISD::AND: |
221 | return AluCode::AND; |
222 | case ISD::OR: |
223 | return AluCode::OR; |
224 | case ISD::XOR: |
225 | return AluCode::XOR; |
226 | case ISD::SHL: |
227 | return AluCode::SHL; |
228 | case ISD::SRL: |
229 | return AluCode::SRL; |
230 | case ISD::SRA: |
231 | return AluCode::SRA; |
232 | default: |
233 | return AluCode::UNKNOWN; |
234 | } |
235 | } |
236 | } // namespace LPAC |
237 | } // namespace llvm |
238 | |
239 | bool LanaiDAGToDAGISel::selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, |
240 | SDValue &AluOp) { |
241 | // if Address is FI, get the TargetFrameIndex. |
242 | if (Addr.getOpcode() == ISD::FrameIndex) |
243 | return false; |
244 | |
245 | // Skip direct calls |
246 | if ((Addr.getOpcode() == ISD::TargetExternalSymbol || |
247 | Addr.getOpcode() == ISD::TargetGlobalAddress)) |
248 | return false; |
249 | |
250 | // Address of the form OP + OP |
251 | ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode()); |
252 | LPAC::AluCode AluCode = LPAC::isdToLanaiAluCode(Node_type: AluOperator); |
253 | if (AluCode != LPAC::UNKNOWN) { |
254 | // Skip addresses of the form FI OP const |
255 | if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val: Addr.getOperand(i: 1))) |
256 | if (isInt<16>(x: CN->getSExtValue())) |
257 | return false; |
258 | |
259 | // Skip addresses with hi/lo operands |
260 | if (Addr.getOperand(i: 0).getOpcode() == LanaiISD::HI || |
261 | Addr.getOperand(i: 0).getOpcode() == LanaiISD::LO || |
262 | Addr.getOperand(i: 0).getOpcode() == LanaiISD::SMALL || |
263 | Addr.getOperand(i: 1).getOpcode() == LanaiISD::HI || |
264 | Addr.getOperand(i: 1).getOpcode() == LanaiISD::LO || |
265 | Addr.getOperand(i: 1).getOpcode() == LanaiISD::SMALL) |
266 | return false; |
267 | |
268 | // Addresses of the form register OP register |
269 | R1 = Addr.getOperand(i: 0); |
270 | R2 = Addr.getOperand(i: 1); |
271 | AluOp = CurDAG->getTargetConstant(Val: AluCode, DL: SDLoc(Addr), VT: MVT::i32); |
272 | return true; |
273 | } |
274 | |
275 | // Skip addresses with zero offset |
276 | return false; |
277 | } |
278 | |
279 | bool LanaiDAGToDAGISel::SelectInlineAsmMemoryOperand( |
280 | const SDValue &Op, InlineAsm::ConstraintCode ConstraintCode, |
281 | std::vector<SDValue> &OutOps) { |
282 | SDValue Op0, Op1, AluOp; |
283 | switch (ConstraintCode) { |
284 | default: |
285 | return true; |
286 | case InlineAsm::ConstraintCode::m: // memory |
287 | if (!selectAddrRr(Addr: Op, R1&: Op0, R2&: Op1, AluOp) && |
288 | !selectAddrRi(Addr: Op, Base&: Op0, Offset&: Op1, AluOp)) |
289 | return true; |
290 | break; |
291 | } |
292 | |
293 | OutOps.push_back(x: Op0); |
294 | OutOps.push_back(x: Op1); |
295 | OutOps.push_back(x: AluOp); |
296 | return false; |
297 | } |
298 | |
299 | // Select instructions not customized! Used for |
300 | // expanded, promoted and normal instructions |
301 | void LanaiDAGToDAGISel::Select(SDNode *Node) { |
302 | unsigned Opcode = Node->getOpcode(); |
303 | |
304 | // If we have a custom node, we already have selected! |
305 | if (Node->isMachineOpcode()) { |
306 | LLVM_DEBUG(errs() << "== " ; Node->dump(CurDAG); errs() << "\n" ); |
307 | return; |
308 | } |
309 | |
310 | // Instruction Selection not handled by the auto-generated tablegen selection |
311 | // should be handled here. |
312 | EVT VT = Node->getValueType(ResNo: 0); |
313 | switch (Opcode) { |
314 | case ISD::Constant: |
315 | if (VT == MVT::i32) { |
316 | ConstantSDNode *ConstNode = cast<ConstantSDNode>(Val: Node); |
317 | // Materialize zero constants as copies from R0. This allows the coalescer |
318 | // to propagate these into other instructions. |
319 | if (ConstNode->isZero()) { |
320 | SDValue New = CurDAG->getCopyFromReg(Chain: CurDAG->getEntryNode(), |
321 | dl: SDLoc(Node), Reg: Lanai::R0, VT: MVT::i32); |
322 | return ReplaceNode(F: Node, T: New.getNode()); |
323 | } |
324 | // Materialize all ones constants as copies from R1. This allows the |
325 | // coalescer to propagate these into other instructions. |
326 | if (ConstNode->isAllOnes()) { |
327 | SDValue New = CurDAG->getCopyFromReg(Chain: CurDAG->getEntryNode(), |
328 | dl: SDLoc(Node), Reg: Lanai::R1, VT: MVT::i32); |
329 | return ReplaceNode(F: Node, T: New.getNode()); |
330 | } |
331 | } |
332 | break; |
333 | case ISD::FrameIndex: |
334 | selectFrameIndex(N: Node); |
335 | return; |
336 | default: |
337 | break; |
338 | } |
339 | |
340 | // Select the default instruction |
341 | SelectCode(N: Node); |
342 | } |
343 | |
344 | void LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) { |
345 | SDLoc DL(Node); |
346 | SDValue Imm = CurDAG->getTargetConstant(Val: 0, DL, VT: MVT::i32); |
347 | int FI = cast<FrameIndexSDNode>(Val: Node)->getIndex(); |
348 | EVT VT = Node->getValueType(ResNo: 0); |
349 | SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); |
350 | unsigned Opc = Lanai::ADD_I_LO; |
351 | if (Node->hasOneUse()) { |
352 | CurDAG->SelectNodeTo(N: Node, MachineOpc: Opc, VT, Op1: TFI, Op2: Imm); |
353 | return; |
354 | } |
355 | ReplaceNode(F: Node, T: CurDAG->getMachineNode(Opcode: Opc, dl: DL, VT, Op1: TFI, Op2: Imm)); |
356 | } |
357 | |
358 | // createLanaiISelDag - This pass converts a legalized DAG into a |
359 | // Lanai-specific DAG, ready for instruction scheduling. |
360 | FunctionPass *llvm::createLanaiISelDag(LanaiTargetMachine &TM) { |
361 | return new LanaiDAGToDAGISelLegacy(TM); |
362 | } |
363 | |