LLVM 20.0.0git
LanaiISelDAGToDAG.cpp
Go to the documentation of this file.
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"
20#include "llvm/IR/Type.h"
21#include "llvm/Support/Debug.h"
24
25using 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//===----------------------------------------------------------------------===//
38namespace {
39
40class LanaiDAGToDAGISel : public SelectionDAGISel {
41public:
42 LanaiDAGToDAGISel() = delete;
43
44 explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine)
46
48 InlineAsm::ConstraintCode ConstraintCode,
49 std::vector<SDValue> &OutOps) override;
50
51private:
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(Imm, DL, MVT::i32);
73 }
74
75private:
76 bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
77 SDValue &AluOp, bool RiMode);
78};
79
80bool canBeRepresentedAsSls(const ConstantSDNode &CN) {
81 // Fits in 21-bit signed immediate and two low-order bits are zero.
82 return isInt<21>(CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0);
83}
84
85class LanaiDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
86public:
87 static char ID;
88 explicit LanaiDAGToDAGISelLegacy(LanaiTargetMachine &TM)
89 : SelectionDAGISelLegacy(ID, std::make_unique<LanaiDAGToDAGISel>(TM)) {}
90};
91
92} // namespace
93
94char LanaiDAGToDAGISelLegacy::ID = 0;
95
96INITIALIZE_PASS(LanaiDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
97
98// Helper functions for ComplexPattern used on LanaiInstrInfo
99// Used on Lanai Load/Store instructions.
100bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) {
101 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
102 SDLoc DL(Addr);
103 // Loading from a constant address.
104 if (canBeRepresentedAsSls(*CN)) {
105 int32_t Imm = CN->getSExtValue();
106 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
107 return true;
108 }
109 }
110 if (Addr.getOpcode() == ISD::OR &&
111 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) {
112 Offset = Addr.getOperand(1).getOperand(0);
113 return true;
114 }
115 return false;
116}
117
118bool 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>(Addr)) {
124 if (RiMode) {
125 // Fits in 16-bit signed immediate.
126 if (isInt<16>(CN->getSExtValue())) {
127 int16_t Imm = CN->getSExtValue();
128 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
129 Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
130 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, 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))
136 return false;
137 } else {
138 // Fits in 10-bit signed immediate.
139 if (isInt<10>(CN->getSExtValue())) {
140 int16_t Imm = CN->getSExtValue();
141 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
142 Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
143 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
144 return true;
145 }
146 }
147 }
148
149 // if Address is FI, get the TargetFrameIndex.
150 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
151 Base = CurDAG->getTargetFrameIndex(
152 FIN->getIndex(),
153 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
154 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
155 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, 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(LPAC::ADD, DL, MVT::i32);
168 // Addresses of the form FI+const
169 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
170 if ((RiMode && isInt<16>(CN->getSExtValue())) ||
171 (!RiMode && isInt<10>(CN->getSExtValue()))) {
172 // If the first operand is a FI, get the TargetFI Node
173 if (FrameIndexSDNode *FIN =
174 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
175 Base = CurDAG->getTargetFrameIndex(
176 FIN->getIndex(),
177 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
178 } else {
179 Base = Addr.getOperand(0);
180 }
181
182 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, 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(1).getOpcode() == LanaiISD::SMALL)
190 return false;
191
192 Base = Addr;
193 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
194 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
195 return true;
196}
197
198bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base,
199 SDValue &Offset, SDValue &AluOp) {
200 return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/true);
201}
202
203bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base,
204 SDValue &Offset, SDValue &AluOp) {
205 return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false);
206}
207
208namespace llvm {
209namespace LPAC {
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
239bool 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());
253 if (AluCode != LPAC::UNKNOWN) {
254 // Skip addresses of the form FI OP const
255 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
256 if (isInt<16>(CN->getSExtValue()))
257 return false;
258
259 // Skip addresses with hi/lo operands
260 if (Addr.getOperand(0).getOpcode() == LanaiISD::HI ||
261 Addr.getOperand(0).getOpcode() == LanaiISD::LO ||
262 Addr.getOperand(0).getOpcode() == LanaiISD::SMALL ||
263 Addr.getOperand(1).getOpcode() == LanaiISD::HI ||
264 Addr.getOperand(1).getOpcode() == LanaiISD::LO ||
265 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
266 return false;
267
268 // Addresses of the form register OP register
269 R1 = Addr.getOperand(0);
270 R2 = Addr.getOperand(1);
271 AluOp = CurDAG->getTargetConstant(AluCode, SDLoc(Addr), MVT::i32);
272 return true;
273 }
274
275 // Skip addresses with zero offset
276 return false;
277}
278
279bool 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(Op, Op0, Op1, AluOp) &&
288 !selectAddrRi(Op, Op0, Op1, AluOp))
289 return true;
290 break;
291 }
292
293 OutOps.push_back(Op0);
294 OutOps.push_back(Op1);
295 OutOps.push_back(AluOp);
296 return false;
297}
298
299// Select instructions not customized! Used for
300// expanded, promoted and normal instructions
301void 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(0);
313 switch (Opcode) {
314 case ISD::Constant:
315 if (VT == MVT::i32) {
316 ConstantSDNode *ConstNode = cast<ConstantSDNode>(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(CurDAG->getEntryNode(),
321 SDLoc(Node), Lanai::R0, MVT::i32);
322 return ReplaceNode(Node, 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(CurDAG->getEntryNode(),
328 SDLoc(Node), Lanai::R1, MVT::i32);
329 return ReplaceNode(Node, New.getNode());
330 }
331 }
332 break;
333 case ISD::FrameIndex:
334 selectFrameIndex(Node);
335 return;
336 default:
337 break;
338 }
339
340 // Select the default instruction
341 SelectCode(Node);
342}
343
344void LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) {
345 SDLoc DL(Node);
346 SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32);
347 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
348 EVT VT = Node->getValueType(0);
349 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
350 unsigned Opc = Lanai::ADD_I_LO;
351 if (Node->hasOneUse()) {
352 CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm);
353 return;
354 }
355 ReplaceNode(Node, CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm));
356}
357
358// createLanaiISelDag - This pass converts a legalized DAG into a
359// Lanai-specific DAG, ready for instruction scheduling.
361 return new LanaiDAGToDAGISelLegacy(TM);
362}
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_DEBUG(...)
Definition: Debug.h:106
uint64_t Addr
#define PASS_NAME
#define DEBUG_TYPE
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
#define R2(n)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
DEMANGLE_DUMP_METHOD void dump() const
int64_t getSExtValue() const
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:77
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
NodeType
ISD::NodeType enum - This enum defines the target-independent operators for a SelectionDAG.
Definition: ISDOpcodes.h:40
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:246
@ FrameIndex
Definition: ISDOpcodes.h:80
@ TargetExternalSymbol
Definition: ISDOpcodes.h:175
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
Definition: ISDOpcodes.h:170
@ SHL
Shift and rotation operations.
Definition: ISDOpcodes.h:735
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:709
@ ADDE
Carry-using nodes for multiple precision addition and subtraction.
Definition: ISDOpcodes.h:286
static AluCode isdToLanaiAluCode(ISD::NodeType Node_type)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
FunctionPass * createLanaiISelDag(LanaiTargetMachine &TM)
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
#define N
Extended Value Type.
Definition: ValueTypes.h:35