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 static char ID;
52
53 LanaiDAGToDAGISel() = delete;
54
55 explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine)
57
58 bool runOnMachineFunction(MachineFunction &MF) override {
60 }
61
63 InlineAsm::ConstraintCode ConstraintCode,
64 std::vector<SDValue> &OutOps) override;
65
66private:
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
90private:
91 bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
92 SDValue &AluOp, bool RiMode);
93};
94
95bool 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
102char LanaiDAGToDAGISel::ID = 0;
103
104INITIALIZE_PASS(LanaiDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
105
106// Helper functions for ComplexPattern used on LanaiInstrInfo
107// Used on Lanai Load/Store instructions.
108bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) {
109 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
110 SDLoc DL(Addr);
111 // Loading from a constant address.
112 if (canBeRepresentedAsSls(*CN)) {
113 int32_t Imm = CN->getSExtValue();
114 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
115 return true;
116 }
117 }
118 if (Addr.getOpcode() == ISD::OR &&
119 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) {
120 Offset = Addr.getOperand(1).getOperand(0);
121 return true;
122 }
123 return false;
124}
125
126bool 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>(Addr)) {
132 if (RiMode) {
133 // Fits in 16-bit signed immediate.
134 if (isInt<16>(CN->getSExtValue())) {
135 int16_t Imm = CN->getSExtValue();
136 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(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))
144 return false;
145 } else {
146 // Fits in 10-bit signed immediate.
147 if (isInt<10>(CN->getSExtValue())) {
148 int16_t Imm = CN->getSExtValue();
149 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(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>(Addr)) {
159 Base = CurDAG->getTargetFrameIndex(
160 FIN->getIndex(),
161 getTargetLowering()->getPointerTy(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>(Addr.getOperand(1)))
178 if ((RiMode && isInt<16>(CN->getSExtValue())) ||
179 (!RiMode && isInt<10>(CN->getSExtValue()))) {
180 // If the first operand is a FI, get the TargetFI Node
181 if (FrameIndexSDNode *FIN =
182 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
183 Base = CurDAG->getTargetFrameIndex(
184 FIN->getIndex(),
185 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
186 } else {
187 Base = Addr.getOperand(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(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
206bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base,
207 SDValue &Offset, SDValue &AluOp) {
208 return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/true);
209}
210
211bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base,
212 SDValue &Offset, SDValue &AluOp) {
213 return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false);
214}
215
216namespace llvm {
217namespace LPAC {
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
247bool 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());
261 if (AluCode != LPAC::UNKNOWN) {
262 // Skip addresses of the form FI OP const
263 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
264 if (isInt<16>(CN->getSExtValue()))
265 return false;
266
267 // Skip addresses with hi/lo operands
268 if (Addr.getOperand(0).getOpcode() == LanaiISD::HI ||
269 Addr.getOperand(0).getOpcode() == LanaiISD::LO ||
270 Addr.getOperand(0).getOpcode() == LanaiISD::SMALL ||
271 Addr.getOperand(1).getOpcode() == LanaiISD::HI ||
272 Addr.getOperand(1).getOpcode() == LanaiISD::LO ||
273 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
274 return false;
275
276 // Addresses of the form register OP register
277 R1 = Addr.getOperand(0);
278 R2 = Addr.getOperand(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
287bool 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(Op, Op0, Op1, AluOp) &&
296 !selectAddrRi(Op, Op0, Op1, AluOp))
297 return true;
298 break;
299 }
300
301 OutOps.push_back(Op0);
302 OutOps.push_back(Op1);
303 OutOps.push_back(AluOp);
304 return false;
305}
306
307// Select instructions not customized! Used for
308// expanded, promoted and normal instructions
309void 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(0);
321 switch (Opcode) {
322 case ISD::Constant:
323 if (VT == MVT::i32) {
324 ConstantSDNode *ConstNode = cast<ConstantSDNode>(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(Node, 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(Node, New.getNode());
338 }
339 }
340 break;
341 case ISD::FrameIndex:
342 selectFrameIndex(Node);
343 return;
344 default:
345 break;
346 }
347
348 // Select the default instruction
349 SelectCode(Node);
350}
351
352void LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) {
353 SDLoc DL(Node);
354 SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32);
355 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
356 EVT VT = Node->getValueType(0);
357 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
358 unsigned Opc = Lanai::ADD_I_LO;
359 if (Node->hasOneUse()) {
360 CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm);
361 return;
362 }
363 ReplaceNode(Node, CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm));
364}
365
366// createLanaiISelDag - This pass converts a legalized DAG into a
367// Lanai-specific DAG, ready for instruction scheduling.
369 return new LanaiDAGToDAGISel(TM);
370}
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,...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:76
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:239
@ FrameIndex
Definition: ISDOpcodes.h:80
@ TargetExternalSymbol
Definition: ISDOpcodes.h:169
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
Definition: ISDOpcodes.h:164
@ SHL
Shift and rotation operations.
Definition: ISDOpcodes.h:705
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:680
@ ADDE
Carry-using nodes for multiple precision addition and subtraction.
Definition: ISDOpcodes.h:279
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:456
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