1 //===-- LanaiISelDAGToDAG.cpp - A dag to dag inst selector for Lanai ------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines an instruction selector for the Lanai target.
11 //===----------------------------------------------------------------------===//
13 #include "LanaiAluCode.h"
14 #include "LanaiTargetMachine.h"
15 #include "llvm/CodeGen/MachineConstantPool.h"
16 #include "llvm/CodeGen/MachineFrameInfo.h"
17 #include "llvm/CodeGen/MachineFunction.h"
18 #include "llvm/CodeGen/SelectionDAGISel.h"
19 #include "llvm/IR/Instructions.h"
20 #include "llvm/IR/Type.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/ErrorHandling.h"
23 #include "llvm/Support/raw_ostream.h"
27 #define DEBUG_TYPE "lanai-isel"
28 #define PASS_NAME "Lanai DAG->DAG Pattern Instruction Selection"
30 //===----------------------------------------------------------------------===//
31 // Instruction Selector Implementation
32 //===----------------------------------------------------------------------===//
34 //===----------------------------------------------------------------------===//
35 // LanaiDAGToDAGISel - Lanai specific code to select Lanai machine
36 // instructions for SelectionDAG operations.
37 //===----------------------------------------------------------------------===//
40 class LanaiDAGToDAGISel
: public SelectionDAGISel
{
42 LanaiDAGToDAGISel() = delete;
44 explicit LanaiDAGToDAGISel(LanaiTargetMachine
&TargetMachine
)
45 : SelectionDAGISel(TargetMachine
) {}
47 bool SelectInlineAsmMemoryOperand(const SDValue
&Op
,
48 InlineAsm::ConstraintCode ConstraintCode
,
49 std::vector
<SDValue
> &OutOps
) override
;
52 // Include the pieces autogenerated from the target description.
53 #include "LanaiGenDAGISel.inc"
55 // Instruction Selection not handled by the auto-generated tablgen
56 void Select(SDNode
*N
) override
;
58 // Support functions for the opcodes of Instruction Selection
59 // not handled by the auto-generated tablgen
60 void selectFrameIndex(SDNode
*N
);
62 // Complex Pattern for address selection.
63 bool selectAddrRi(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
,
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
,
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
);
76 bool selectAddrRiSpls(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
,
77 SDValue
&AluOp
, bool RiMode
);
80 bool 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);
85 class LanaiDAGToDAGISelLegacy
: public SelectionDAGISelLegacy
{
88 explicit LanaiDAGToDAGISelLegacy(LanaiTargetMachine
&TM
)
89 : SelectionDAGISelLegacy(ID
, std::make_unique
<LanaiDAGToDAGISel
>(TM
)) {}
94 char LanaiDAGToDAGISelLegacy::ID
= 0;
96 INITIALIZE_PASS(LanaiDAGToDAGISelLegacy
, DEBUG_TYPE
, PASS_NAME
, false, false)
98 // Helper functions for ComplexPattern used on LanaiInstrInfo
99 // Used on Lanai Load/Store instructions.
100 bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr
, SDValue
&Offset
) {
101 if (ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(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));
110 if (Addr
.getOpcode() == ISD::OR
&&
111 Addr
.getOperand(1).getOpcode() == LanaiISD::SMALL
) {
112 Offset
= Addr
.getOperand(1).getOperand(0);
118 bool LanaiDAGToDAGISel::selectAddrRiSpls(SDValue Addr
, SDValue
&Base
,
119 SDValue
&Offset
, SDValue
&AluOp
,
123 if (ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Addr
)) {
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
);
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
))
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
);
149 // if Address is FI, get the TargetFrameIndex.
150 if (FrameIndexSDNode
*FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
)) {
151 Base
= CurDAG
->getTargetFrameIndex(
153 getTargetLowering()->getPointerTy(CurDAG
->getDataLayout()));
154 Offset
= CurDAG
->getTargetConstant(0, DL
, MVT::i32
);
155 AluOp
= CurDAG
->getTargetConstant(LPAC::ADD
, DL
, MVT::i32
);
160 if ((Addr
.getOpcode() == ISD::TargetExternalSymbol
||
161 Addr
.getOpcode() == ISD::TargetGlobalAddress
))
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(
177 getTargetLowering()->getPointerTy(CurDAG
->getDataLayout()));
179 Base
= Addr
.getOperand(0);
182 Offset
= CurDAG
->getTargetConstant(CN
->getSExtValue(), DL
, MVT::i32
);
187 // Let SLS match SMALL instead of RI.
188 if (AluOperator
== ISD::OR
&& RiMode
&&
189 Addr
.getOperand(1).getOpcode() == LanaiISD::SMALL
)
193 Offset
= CurDAG
->getTargetConstant(0, DL
, MVT::i32
);
194 AluOp
= CurDAG
->getTargetConstant(LPAC::ADD
, DL
, MVT::i32
);
198 bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr
, SDValue
&Base
,
199 SDValue
&Offset
, SDValue
&AluOp
) {
200 return selectAddrRiSpls(Addr
, Base
, Offset
, AluOp
, /*RiMode=*/true);
203 bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr
, SDValue
&Base
,
204 SDValue
&Offset
, SDValue
&AluOp
) {
205 return selectAddrRiSpls(Addr
, Base
, Offset
, AluOp
, /*RiMode=*/false);
210 static AluCode
isdToLanaiAluCode(ISD::NodeType Node_type
) {
215 return AluCode::ADDC
;
219 return AluCode::SUBB
;
233 return AluCode::UNKNOWN
;
239 bool LanaiDAGToDAGISel::selectAddrRr(SDValue Addr
, SDValue
&R1
, SDValue
&R2
,
241 // if Address is FI, get the TargetFrameIndex.
242 if (Addr
.getOpcode() == ISD::FrameIndex
)
246 if ((Addr
.getOpcode() == ISD::TargetExternalSymbol
||
247 Addr
.getOpcode() == ISD::TargetGlobalAddress
))
250 // Address of the form OP + OP
251 ISD::NodeType AluOperator
= static_cast<ISD::NodeType
>(Addr
.getOpcode());
252 LPAC::AluCode AluCode
= LPAC::isdToLanaiAluCode(AluOperator
);
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()))
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
)
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
);
275 // Skip addresses with zero offset
279 bool LanaiDAGToDAGISel::SelectInlineAsmMemoryOperand(
280 const SDValue
&Op
, InlineAsm::ConstraintCode ConstraintCode
,
281 std::vector
<SDValue
> &OutOps
) {
282 SDValue Op0
, Op1
, AluOp
;
283 switch (ConstraintCode
) {
286 case InlineAsm::ConstraintCode::m
: // memory
287 if (!selectAddrRr(Op
, Op0
, Op1
, AluOp
) &&
288 !selectAddrRi(Op
, Op0
, Op1
, AluOp
))
293 OutOps
.push_back(Op0
);
294 OutOps
.push_back(Op1
);
295 OutOps
.push_back(AluOp
);
299 // Select instructions not customized! Used for
300 // expanded, promoted and normal instructions
301 void LanaiDAGToDAGISel::Select(SDNode
*Node
) {
302 unsigned Opcode
= Node
->getOpcode();
304 // If we have a custom node, we already have selected!
305 if (Node
->isMachineOpcode()) {
306 LLVM_DEBUG(errs() << "== "; Node
->dump(CurDAG
); errs() << "\n");
310 // Instruction Selection not handled by the auto-generated tablegen selection
311 // should be handled here.
312 EVT VT
= Node
->getValueType(0);
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());
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());
333 case ISD::FrameIndex
:
334 selectFrameIndex(Node
);
340 // Select the default instruction
344 void LanaiDAGToDAGISel::selectFrameIndex(SDNode
*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
);
355 ReplaceNode(Node
, CurDAG
->getMachineNode(Opc
, DL
, VT
, TFI
, Imm
));
358 // createLanaiISelDag - This pass converts a legalized DAG into a
359 // Lanai-specific DAG, ready for instruction scheduling.
360 FunctionPass
*llvm::createLanaiISelDag(LanaiTargetMachine
&TM
) {
361 return new LanaiDAGToDAGISelLegacy(TM
);