xref: /llvm-project/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp (revision 753028bc81c1a556eaaaf45ac77ca0cf4c7a3b4a)
1 //===- XtensaISelDAGToDAG.cpp - A dag to dag inst selector for Xtensa -----===//
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 Xtensa target.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "MCTargetDesc/XtensaMCTargetDesc.h"
14 #include "Xtensa.h"
15 #include "XtensaTargetMachine.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"
22 
23 using namespace llvm;
24 
25 #define DEBUG_TYPE "xtensa-isel"
26 
27 namespace {
28 
29 class XtensaDAGToDAGISel : public SelectionDAGISel {
30   const XtensaSubtarget *Subtarget = nullptr;
31 
32 public:
33   explicit XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel)
34       : SelectionDAGISel(TM, OptLevel) {}
35 
36   bool runOnMachineFunction(MachineFunction &MF) override {
37     Subtarget = &MF.getSubtarget<XtensaSubtarget>();
38     return SelectionDAGISel::runOnMachineFunction(MF);
39   }
40 
41   void Select(SDNode *Node) override;
42 
43   bool SelectInlineAsmMemoryOperand(const SDValue &Op,
44                                     InlineAsm::ConstraintCode ConstraintID,
45                                     std::vector<SDValue> &OutOps) override;
46 
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,
50                         int Scale) {
51     EVT ValTy = Addr.getValueType();
52 
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);
57 
58       return true;
59     }
60 
61     if (TM.isPositionIndependent()) {
62       DiagnosticInfoUnsupported Diag(CurDAG->getMachineFunction().getFunction(),
63                                      "PIC relocations are not supported ",
64                                      Addr.getDebugLoc());
65       CurDAG->getContext()->diagnose(Diag);
66     }
67 
68     if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
69          Addr.getOpcode() == ISD::TargetGlobalAddress))
70       return false;
71 
72     // Addresses of the form FI+const
73     bool Valid = false;
74     if (CurDAG->isBaseWithConstantOffset(Addr)) {
75       ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
76       int64_t OffsetVal = CN->getSExtValue();
77 
78       Valid = Xtensa::isValidAddrOffset(Scale, OffsetVal);
79 
80       if (Valid) {
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);
85         else
86           Base = Addr.getOperand(0);
87 
88         Offset =
89             CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), ValTy);
90         return true;
91       }
92     }
93 
94     // Last case
95     Base = Addr;
96     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Addr.getValueType());
97     return true;
98   }
99 
100   bool selectMemRegAddrISH1(SDValue Addr, SDValue &Base, SDValue &Offset) {
101     return selectMemRegAddr(Addr, Base, Offset, 1);
102   }
103 
104   bool selectMemRegAddrISH2(SDValue Addr, SDValue &Base, SDValue &Offset) {
105     return selectMemRegAddr(Addr, Base, Offset, 2);
106   }
107 
108   bool selectMemRegAddrISH4(SDValue Addr, SDValue &Base, SDValue &Offset) {
109     return selectMemRegAddr(Addr, Base, Offset, 4);
110   }
111 
112 // Include the pieces autogenerated from the target description.
113 #include "XtensaGenDAGISel.inc"
114 }; // namespace
115 
116 class XtensaDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
117 public:
118   static char ID;
119 
120   XtensaDAGToDAGISelLegacy(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel)
121       : SelectionDAGISelLegacy(
122             ID, std::make_unique<XtensaDAGToDAGISel>(TM, OptLevel)) {}
123 
124   StringRef getPassName() const override {
125     return "Xtensa DAG->DAG Pattern Instruction Selection";
126   }
127 };
128 } // end anonymous namespace
129 
130 char XtensaDAGToDAGISelLegacy::ID = 0;
131 
132 FunctionPass *llvm::createXtensaISelDag(XtensaTargetMachine &TM,
133                                         CodeGenOptLevel OptLevel) {
134   return new XtensaDAGToDAGISelLegacy(TM, OptLevel);
135 }
136 
137 void XtensaDAGToDAGISel::Select(SDNode *Node) {
138   SDLoc DL(Node);
139   EVT VT = Node->getValueType(0);
140 
141   // If we have a custom node, we already have selected!
142   if (Node->isMachineOpcode()) {
143     Node->setNodeId(-1);
144     return;
145   }
146 
147   switch (Node->getOpcode()) {
148   case ISD::SHL: {
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);
156       SDNode *SLL =
157           CurDAG->getMachineNode(Xtensa::SLL, DL, VT, N0, SDValue(SSL, 0));
158       ReplaceNode(Node, SLL);
159       return;
160     }
161     break;
162   }
163   case ISD::SRL: {
164     SDValue N0 = Node->getOperand(0);
165     SDValue N1 = Node->getOperand(1);
166     auto *C = dyn_cast<ConstantSDNode>(N1);
167 
168     // If C is constant then we can generate SRLI
169     // instruction using pattern matching or EXTUI, otherwise generate SRL.
170     if (C) {
171       if (isUInt<4>(C->getZExtValue()))
172         break;
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);
178       return;
179     }
180 
181     SDNode *SSR = CurDAG->getMachineNode(Xtensa::SSR, DL, MVT::Glue, N1);
182     SDNode *SRL =
183         CurDAG->getMachineNode(Xtensa::SRL, DL, VT, N0, SDValue(SSR, 0));
184     ReplaceNode(Node, SRL);
185     return;
186   }
187   case ISD::SRA: {
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.
193     if (!C) {
194       SDNode *SSR = CurDAG->getMachineNode(Xtensa::SSR, DL, MVT::Glue, N1);
195       SDNode *SRA =
196           CurDAG->getMachineNode(Xtensa::SRA, DL, VT, N0, SDValue(SSR, 0));
197       ReplaceNode(Node, SRA);
198       return;
199     }
200     break;
201   }
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);
207     SDNode *SRC =
208         CurDAG->getMachineNode(Xtensa::SRC, DL, VT, N0, N1, SDValue(SSL, 0));
209     ReplaceNode(Node, SRC);
210     return;
211   }
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);
217     SDNode *SRC =
218         CurDAG->getMachineNode(Xtensa::SRC, DL, VT, N0, N1, SDValue(SSR, 0));
219     ReplaceNode(Node, SRC);
220     return;
221   }
222   }
223 
224   SelectCode(Node);
225 }
226 
227 bool XtensaDAGToDAGISel::SelectInlineAsmMemoryOperand(
228     const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
229     std::vector<SDValue> &OutOps) {
230   switch (ConstraintID) {
231   default:
232     llvm_unreachable("Unexpected asm memory constraint");
233   case InlineAsm::ConstraintCode::m: {
234     SDValue Base, Offset;
235 
236     selectMemRegAddr(Op, Base, Offset, 4);
237     OutOps.push_back(Base);
238     OutOps.push_back(Offset);
239 
240     return false;
241   }
242   }
243   return false;
244 }
245