1 //===- XtensaISelDAGToDAG.cpp - A dag to dag inst selector for Xtensa -----===//
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 Xtensa target.
11 //===----------------------------------------------------------------------===//
14 #include "XtensaTargetMachine.h"
15 #include "XtensaUtils.h"
16 #include "llvm/CodeGen/MachineFunction.h"
17 #include "llvm/CodeGen/MachineRegisterInfo.h"
18 #include "llvm/CodeGen/SelectionDAGISel.h"
19 #include "llvm/IR/DiagnosticInfo.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/raw_ostream.h"
25 #define DEBUG_TYPE "xtensa-isel"
29 class XtensaDAGToDAGISel
: public SelectionDAGISel
{
30 const XtensaSubtarget
*Subtarget
= nullptr;
33 explicit XtensaDAGToDAGISel(XtensaTargetMachine
&TM
, CodeGenOptLevel OptLevel
)
34 : SelectionDAGISel(TM
, OptLevel
) {}
36 bool runOnMachineFunction(MachineFunction
&MF
) override
{
37 Subtarget
= &MF
.getSubtarget
<XtensaSubtarget
>();
38 return SelectionDAGISel::runOnMachineFunction(MF
);
41 void Select(SDNode
*Node
) override
;
43 bool SelectInlineAsmMemoryOperand(const SDValue
&Op
,
44 InlineAsm::ConstraintCode ConstraintID
,
45 std::vector
<SDValue
> &OutOps
) override
;
47 // For load/store instructions generate (base+offset) pair from
48 // memory address. The offset must be a multiple of scale argument.
49 bool selectMemRegAddr(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
,
51 EVT ValTy
= Addr
.getValueType();
53 // if Address is FI, get the TargetFrameIndex.
54 if (FrameIndexSDNode
*FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
)) {
55 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), ValTy
);
56 Offset
= CurDAG
->getTargetConstant(0, SDLoc(Addr
), ValTy
);
61 if (TM
.isPositionIndependent()) {
62 DiagnosticInfoUnsupported
Diag(CurDAG
->getMachineFunction().getFunction(),
63 "PIC relocations are not supported ",
65 CurDAG
->getContext()->diagnose(Diag
);
68 if ((Addr
.getOpcode() == ISD::TargetExternalSymbol
||
69 Addr
.getOpcode() == ISD::TargetGlobalAddress
))
72 // Addresses of the form FI+const
74 if (CurDAG
->isBaseWithConstantOffset(Addr
)) {
75 ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Addr
.getOperand(1));
76 int64_t OffsetVal
= CN
->getSExtValue();
78 Valid
= isValidAddrOffset(Scale
, OffsetVal
);
81 // If the first operand is a FI, get the TargetFI Node.
82 if (FrameIndexSDNode
*FIN
=
83 dyn_cast
<FrameIndexSDNode
>(Addr
.getOperand(0)))
84 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), ValTy
);
86 Base
= Addr
.getOperand(0);
89 CurDAG
->getTargetConstant(CN
->getZExtValue(), SDLoc(Addr
), ValTy
);
96 Offset
= CurDAG
->getTargetConstant(0, SDLoc(Addr
), Addr
.getValueType());
100 bool selectMemRegAddrISH1(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
) {
101 return selectMemRegAddr(Addr
, Base
, Offset
, 1);
104 bool selectMemRegAddrISH2(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
) {
105 return selectMemRegAddr(Addr
, Base
, Offset
, 2);
108 bool selectMemRegAddrISH4(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
) {
109 return selectMemRegAddr(Addr
, Base
, Offset
, 4);
112 // Include the pieces autogenerated from the target description.
113 #include "XtensaGenDAGISel.inc"
116 class XtensaDAGToDAGISelLegacy
: public SelectionDAGISelLegacy
{
120 XtensaDAGToDAGISelLegacy(XtensaTargetMachine
&TM
, CodeGenOptLevel OptLevel
)
121 : SelectionDAGISelLegacy(
122 ID
, std::make_unique
<XtensaDAGToDAGISel
>(TM
, OptLevel
)) {}
124 StringRef
getPassName() const override
{
125 return "Xtensa DAG->DAG Pattern Instruction Selection";
128 } // end anonymous namespace
130 char XtensaDAGToDAGISelLegacy::ID
= 0;
132 FunctionPass
*llvm::createXtensaISelDag(XtensaTargetMachine
&TM
,
133 CodeGenOptLevel OptLevel
) {
134 return new XtensaDAGToDAGISelLegacy(TM
, OptLevel
);
137 void XtensaDAGToDAGISel::Select(SDNode
*Node
) {
139 EVT VT
= Node
->getValueType(0);
141 // If we have a custom node, we already have selected!
142 if (Node
->isMachineOpcode()) {
147 switch (Node
->getOpcode()) {
149 SDValue N0
= Node
->getOperand(0);
150 SDValue N1
= Node
->getOperand(1);
151 auto *C
= dyn_cast
<ConstantSDNode
>(N1
);
152 // If C is constant in range [1..31] then we can generate SLLI
153 // instruction using pattern matching, otherwise generate SLL.
154 if (!C
|| C
->isZero()) {
155 SDNode
*SSL
= CurDAG
->getMachineNode(Xtensa::SSL
, DL
, MVT::Glue
, N1
);
157 CurDAG
->getMachineNode(Xtensa::SLL
, DL
, VT
, N0
, SDValue(SSL
, 0));
158 ReplaceNode(Node
, SLL
);
164 SDValue N0
= Node
->getOperand(0);
165 SDValue N1
= Node
->getOperand(1);
166 auto *C
= dyn_cast
<ConstantSDNode
>(N1
);
168 // If C is constant then we can generate SRLI
169 // instruction using pattern matching or EXTUI, otherwise generate SRL.
171 if (isUInt
<4>(C
->getZExtValue()))
173 unsigned ShAmt
= C
->getZExtValue();
174 SDNode
*EXTUI
= CurDAG
->getMachineNode(
175 Xtensa::EXTUI
, DL
, VT
, N0
, CurDAG
->getTargetConstant(ShAmt
, DL
, VT
),
176 CurDAG
->getTargetConstant(32 - ShAmt
, DL
, VT
));
177 ReplaceNode(Node
, EXTUI
);
181 SDNode
*SSR
= CurDAG
->getMachineNode(Xtensa::SSR
, DL
, MVT::Glue
, N1
);
183 CurDAG
->getMachineNode(Xtensa::SRL
, DL
, VT
, N0
, SDValue(SSR
, 0));
184 ReplaceNode(Node
, SRL
);
188 SDValue N0
= Node
->getOperand(0);
189 SDValue N1
= Node
->getOperand(1);
190 auto *C
= dyn_cast
<ConstantSDNode
>(N1
);
191 // If C is constant then we can generate SRAI
192 // instruction using pattern matching, otherwise generate SRA.
194 SDNode
*SSR
= CurDAG
->getMachineNode(Xtensa::SSR
, DL
, MVT::Glue
, N1
);
196 CurDAG
->getMachineNode(Xtensa::SRA
, DL
, VT
, N0
, SDValue(SSR
, 0));
197 ReplaceNode(Node
, SRA
);
202 case XtensaISD::SRCL
: {
203 SDValue N0
= Node
->getOperand(0);
204 SDValue N1
= Node
->getOperand(1);
205 SDValue N2
= Node
->getOperand(2);
206 SDNode
*SSL
= CurDAG
->getMachineNode(Xtensa::SSL
, DL
, MVT::Glue
, N2
);
208 CurDAG
->getMachineNode(Xtensa::SRC
, DL
, VT
, N0
, N1
, SDValue(SSL
, 0));
209 ReplaceNode(Node
, SRC
);
212 case XtensaISD::SRCR
: {
213 SDValue N0
= Node
->getOperand(0);
214 SDValue N1
= Node
->getOperand(1);
215 SDValue N2
= Node
->getOperand(2);
216 SDNode
*SSR
= CurDAG
->getMachineNode(Xtensa::SSR
, DL
, MVT::Glue
, N2
);
218 CurDAG
->getMachineNode(Xtensa::SRC
, DL
, VT
, N0
, N1
, SDValue(SSR
, 0));
219 ReplaceNode(Node
, SRC
);
227 bool XtensaDAGToDAGISel::SelectInlineAsmMemoryOperand(
228 const SDValue
&Op
, InlineAsm::ConstraintCode ConstraintID
,
229 std::vector
<SDValue
> &OutOps
) {
230 switch (ConstraintID
) {
232 llvm_unreachable("Unexpected asm memory constraint");
233 case InlineAsm::ConstraintCode::m
: {
234 SDValue Base
, Offset
;
236 selectMemRegAddr(Op
, Base
, Offset
, 4);
237 OutOps
.push_back(Base
);
238 OutOps
.push_back(Offset
);