LLVM 19.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"
15#include "LanaiRegisterInfo.h"
16#include "LanaiSubtarget.h"
17#include "LanaiTargetMachine.h"
24#include "llvm/IR/CFG.h"
25#include "llvm/IR/GlobalValue.h"
27#include "llvm/IR/Intrinsics.h"
28#include "llvm/IR/Type.h"
29#include "llvm/Support/Debug.h"
33
34using 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//===----------------------------------------------------------------------===//
47namespace {
48
49class LanaiDAGToDAGISel : public SelectionDAGISel {
50public:
51 LanaiDAGToDAGISel() = delete;
52
53 explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine)
55
57 InlineAsm::ConstraintCode ConstraintCode,
58 std::vector<SDValue> &OutOps) override;
59
60private:
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(Imm, DL, MVT::i32);
82 }
83
84private:
85 bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
86 SDValue &AluOp, bool RiMode);
87};
88
89bool canBeRepresentedAsSls(const ConstantSDNode &CN) {
90 // Fits in 21-bit signed immediate and two low-order bits are zero.
91 return isInt<21>(CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0);
92}
93
94class LanaiDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
95public:
96 static char ID;
97 explicit LanaiDAGToDAGISelLegacy(LanaiTargetMachine &TM)
98 : SelectionDAGISelLegacy(ID, std::make_unique<LanaiDAGToDAGISel>(TM)) {}
99};
100
101} // namespace
102
103char LanaiDAGToDAGISelLegacy::ID = 0;
104
105INITIALIZE_PASS(LanaiDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
106
107// Helper functions for ComplexPattern used on LanaiInstrInfo
108// Used on Lanai Load/Store instructions.
109bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) {
110 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
111 SDLoc DL(Addr);
112 // Loading from a constant address.
113 if (canBeRepresentedAsSls(*CN)) {
114 int32_t Imm = CN->getSExtValue();
115 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
116 return true;
117 }
118 }
119 if (Addr.getOpcode() == ISD::OR &&
120 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) {
121 Offset = Addr.getOperand(1).getOperand(0);
122 return true;
123 }
124 return false;
125}
126
127bool 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>(Addr)) {
133 if (RiMode) {
134 // Fits in 16-bit signed immediate.
135 if (isInt<16>(CN->getSExtValue())) {
136 int16_t Imm = CN->getSExtValue();
137 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
138 Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
139 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, 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))
145 return false;
146 } else {
147 // Fits in 10-bit signed immediate.
148 if (isInt<10>(CN->getSExtValue())) {
149 int16_t Imm = CN->getSExtValue();
150 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
151 Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
152 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
153 return true;
154 }
155 }
156 }
157
158 // if Address is FI, get the TargetFrameIndex.
159 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
160 Base = CurDAG->getTargetFrameIndex(
161 FIN->getIndex(),
162 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
163 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
164 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, 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(LPAC::ADD, DL, MVT::i32);
177 // Addresses of the form FI+const
178 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
179 if ((RiMode && isInt<16>(CN->getSExtValue())) ||
180 (!RiMode && isInt<10>(CN->getSExtValue()))) {
181 // If the first operand is a FI, get the TargetFI Node
182 if (FrameIndexSDNode *FIN =
183 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
184 Base = CurDAG->getTargetFrameIndex(
185 FIN->getIndex(),
186 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
187 } else {
188 Base = Addr.getOperand(0);
189 }
190
191 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, 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(1).getOpcode() == LanaiISD::SMALL)
199 return false;
200
201 Base = Addr;
202 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
203 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
204 return true;
205}
206
207bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base,
208 SDValue &Offset, SDValue &AluOp) {
209 return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/true);
210}
211
212bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base,
213 SDValue &Offset, SDValue &AluOp) {
214 return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false);
215}
216
217namespace llvm {
218namespace LPAC {
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
248bool 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());
262 if (AluCode != LPAC::UNKNOWN) {
263 // Skip addresses of the form FI OP const
264 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
265 if (isInt<16>(CN->getSExtValue()))
266 return false;
267
268 // Skip addresses with hi/lo operands
269 if (Addr.getOperand(0).getOpcode() == LanaiISD::HI ||
270 Addr.getOperand(0).getOpcode() == LanaiISD::LO ||
271 Addr.getOperand(0).getOpcode() == LanaiISD::SMALL ||
272 Addr.getOperand(1).getOpcode() == LanaiISD::HI ||
273 Addr.getOperand(1).getOpcode() == LanaiISD::LO ||
274 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
275 return false;
276
277 // Addresses of the form register OP register
278 R1 = Addr.getOperand(0);
279 R2 = Addr.getOperand(1);
280 AluOp = CurDAG->getTargetConstant(AluCode, SDLoc(Addr), MVT::i32);
281 return true;
282 }
283
284 // Skip addresses with zero offset
285 return false;
286}
287
288bool 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(Op, Op0, Op1, AluOp) &&
297 !selectAddrRi(Op, Op0, Op1, AluOp))
298 return true;
299 break;
300 }
301
302 OutOps.push_back(Op0);
303 OutOps.push_back(Op1);
304 OutOps.push_back(AluOp);
305 return false;
306}
307
308// Select instructions not customized! Used for
309// expanded, promoted and normal instructions
310void 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(0);
322 switch (Opcode) {
323 case ISD::Constant:
324 if (VT == MVT::i32) {
325 ConstantSDNode *ConstNode = cast<ConstantSDNode>(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(CurDAG->getEntryNode(),
330 SDLoc(Node), Lanai::R0, MVT::i32);
331 return ReplaceNode(Node, 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(CurDAG->getEntryNode(),
337 SDLoc(Node), Lanai::R1, MVT::i32);
338 return ReplaceNode(Node, New.getNode());
339 }
340 }
341 break;
342 case ISD::FrameIndex:
343 selectFrameIndex(Node);
344 return;
345 default:
346 break;
347 }
348
349 // Select the default instruction
350 SelectCode(Node);
351}
352
353void LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) {
354 SDLoc DL(Node);
355 SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32);
356 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
357 EVT VT = Node->getValueType(0);
358 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
359 unsigned Opc = Lanai::ADD_I_LO;
360 if (Node->hasOneUse()) {
361 CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm);
362 return;
363 }
364 ReplaceNode(Node, CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm));
365}
366
367// createLanaiISelDag - This pass converts a legalized DAG into a
368// Lanai-specific DAG, ready for instruction scheduling.
370 return new LanaiDAGToDAGISelLegacy(TM);
371}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
#define LLVM_DEBUG(X)
Definition: Debug.h:101
uint64_t Addr
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
#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)
const char LLVMTargetMachineRef TM
#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:311
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:719
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:694
@ 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:34