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