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