1//===-- VEISelDAGToDAG.cpp - A dag to dag inst selector for VE ------------===//
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 VE target.
10//
11//===----------------------------------------------------------------------===//
12
13#include "VE.h"
14#include "VETargetMachine.h"
15#include "llvm/CodeGen/SelectionDAGISel.h"
16#include "llvm/Support/ErrorHandling.h"
17using namespace llvm;
18
19#define DEBUG_TYPE "ve-isel"
20#define PASS_NAME "VE DAG->DAG Pattern Instruction Selection"
21
22//===--------------------------------------------------------------------===//
23/// VEDAGToDAGISel - VE specific code to select VE machine
24/// instructions for SelectionDAG operations.
25///
26namespace {
27class VEDAGToDAGISel : public SelectionDAGISel {
28 /// Subtarget - Keep a pointer to the VE Subtarget around so that we can
29 /// make the right decision when generating code for different targets.
30 const VESubtarget *Subtarget;
31
32public:
33 VEDAGToDAGISel() = delete;
34
35 explicit VEDAGToDAGISel(VETargetMachine &tm) : SelectionDAGISel(tm) {}
36
37 bool runOnMachineFunction(MachineFunction &MF) override {
38 Subtarget = &MF.getSubtarget<VESubtarget>();
39 return SelectionDAGISel::runOnMachineFunction(mf&: MF);
40 }
41
42 void Select(SDNode *N) override;
43
44 // Complex Pattern Selectors.
45 bool selectADDRrri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
46 bool selectADDRrii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
47 bool selectADDRzri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
48 bool selectADDRzii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
49 bool selectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
50 bool selectADDRzi(SDValue N, SDValue &Base, SDValue &Offset);
51
52 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
53 /// inline asm expressions.
54 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
55 InlineAsm::ConstraintCode ConstraintID,
56 std::vector<SDValue> &OutOps) override;
57
58 // Include the pieces autogenerated from the target description.
59#include "VEGenDAGISel.inc"
60
61private:
62 SDNode *getGlobalBaseReg();
63
64 bool matchADDRrr(SDValue N, SDValue &Base, SDValue &Index);
65 bool matchADDRri(SDValue N, SDValue &Base, SDValue &Offset);
66};
67
68class VEDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
69public:
70 static char ID;
71 explicit VEDAGToDAGISelLegacy(VETargetMachine &tm)
72 : SelectionDAGISelLegacy(ID, std::make_unique<VEDAGToDAGISel>(args&: tm)) {}
73};
74} // end anonymous namespace
75
76char VEDAGToDAGISelLegacy::ID = 0;
77
78INITIALIZE_PASS(VEDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
79
80bool VEDAGToDAGISel::selectADDRrri(SDValue Addr, SDValue &Base, SDValue &Index,
81 SDValue &Offset) {
82 if (Addr.getOpcode() == ISD::FrameIndex)
83 return false;
84 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
85 Addr.getOpcode() == ISD::TargetGlobalAddress ||
86 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
87 return false; // direct calls.
88
89 SDValue LHS, RHS;
90 if (matchADDRri(N: Addr, Base&: LHS, Offset&: RHS)) {
91 if (matchADDRrr(N: LHS, Base, Index)) {
92 Offset = RHS;
93 return true;
94 }
95 // Return false to try selectADDRrii.
96 return false;
97 }
98 if (matchADDRrr(N: Addr, Base&: LHS, Index&: RHS)) {
99 // If the input is a pair of a frame-index and a register, move a
100 // frame-index to LHS. This generates MI with following operands.
101 // %dest, #FI, %reg, offset
102 // In the eliminateFrameIndex, above MI is converted to the following.
103 // %dest, %fp, %reg, fi_offset + offset
104 if (isa<FrameIndexSDNode>(Val: RHS))
105 std::swap(a&: LHS, b&: RHS);
106
107 if (matchADDRri(N: RHS, Base&: Index, Offset)) {
108 Base = LHS;
109 return true;
110 }
111 if (matchADDRri(N: LHS, Base, Offset)) {
112 Index = RHS;
113 return true;
114 }
115 Base = LHS;
116 Index = RHS;
117 Offset = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
118 return true;
119 }
120 return false; // Let the reg+imm(=0) pattern catch this!
121}
122
123bool VEDAGToDAGISel::selectADDRrii(SDValue Addr, SDValue &Base, SDValue &Index,
124 SDValue &Offset) {
125 if (matchADDRri(N: Addr, Base, Offset)) {
126 Index = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
127 return true;
128 }
129
130 Base = Addr;
131 Index = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
132 Offset = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
133 return true;
134}
135
136bool VEDAGToDAGISel::selectADDRzri(SDValue Addr, SDValue &Base, SDValue &Index,
137 SDValue &Offset) {
138 // Prefer ADDRrii.
139 return false;
140}
141
142bool VEDAGToDAGISel::selectADDRzii(SDValue Addr, SDValue &Base, SDValue &Index,
143 SDValue &Offset) {
144 if (isa<FrameIndexSDNode>(Val: Addr))
145 return false;
146 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
147 Addr.getOpcode() == ISD::TargetGlobalAddress ||
148 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
149 return false; // direct calls.
150
151 if (auto *CN = dyn_cast<ConstantSDNode>(Val&: Addr)) {
152 if (isInt<32>(x: CN->getSExtValue())) {
153 Base = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
154 Index = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
155 Offset =
156 CurDAG->getTargetConstant(Val: CN->getZExtValue(), DL: SDLoc(Addr), VT: MVT::i32);
157 return true;
158 }
159 }
160 return false;
161}
162
163bool VEDAGToDAGISel::selectADDRri(SDValue Addr, SDValue &Base,
164 SDValue &Offset) {
165 if (matchADDRri(N: Addr, Base, Offset))
166 return true;
167
168 Base = Addr;
169 Offset = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
170 return true;
171}
172
173bool VEDAGToDAGISel::selectADDRzi(SDValue Addr, SDValue &Base,
174 SDValue &Offset) {
175 if (isa<FrameIndexSDNode>(Val: Addr))
176 return false;
177 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
178 Addr.getOpcode() == ISD::TargetGlobalAddress ||
179 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
180 return false; // direct calls.
181
182 if (auto *CN = dyn_cast<ConstantSDNode>(Val&: Addr)) {
183 if (isInt<32>(x: CN->getSExtValue())) {
184 Base = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
185 Offset =
186 CurDAG->getTargetConstant(Val: CN->getZExtValue(), DL: SDLoc(Addr), VT: MVT::i32);
187 return true;
188 }
189 }
190 return false;
191}
192
193bool VEDAGToDAGISel::matchADDRrr(SDValue Addr, SDValue &Base, SDValue &Index) {
194 if (isa<FrameIndexSDNode>(Val: Addr))
195 return false;
196 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
197 Addr.getOpcode() == ISD::TargetGlobalAddress ||
198 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
199 return false; // direct calls.
200
201 if (Addr.getOpcode() == ISD::ADD) {
202 ; // Nothing to do here.
203 } else if (Addr.getOpcode() == ISD::OR) {
204 // We want to look through a transform in InstCombine and DAGCombiner that
205 // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
206 if (!CurDAG->haveNoCommonBitsSet(A: Addr.getOperand(i: 0), B: Addr.getOperand(i: 1)))
207 return false;
208 } else {
209 return false;
210 }
211
212 if (Addr.getOperand(i: 0).getOpcode() == VEISD::Lo ||
213 Addr.getOperand(i: 1).getOpcode() == VEISD::Lo)
214 return false; // Let the LEASL patterns catch this!
215
216 Base = Addr.getOperand(i: 0);
217 Index = Addr.getOperand(i: 1);
218 return true;
219}
220
221bool VEDAGToDAGISel::matchADDRri(SDValue Addr, SDValue &Base, SDValue &Offset) {
222 auto AddrTy = Addr->getValueType(ResNo: 0);
223 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Val&: Addr)) {
224 Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), VT: AddrTy);
225 Offset = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
226 return true;
227 }
228 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
229 Addr.getOpcode() == ISD::TargetGlobalAddress ||
230 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
231 return false; // direct calls.
232
233 if (CurDAG->isBaseWithConstantOffset(Op: Addr)) {
234 ConstantSDNode *CN = cast<ConstantSDNode>(Val: Addr.getOperand(i: 1));
235 if (isInt<32>(x: CN->getSExtValue())) {
236 if (FrameIndexSDNode *FIN =
237 dyn_cast<FrameIndexSDNode>(Val: Addr.getOperand(i: 0))) {
238 // Constant offset from frame ref.
239 Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), VT: AddrTy);
240 } else {
241 Base = Addr.getOperand(i: 0);
242 }
243 Offset =
244 CurDAG->getTargetConstant(Val: CN->getZExtValue(), DL: SDLoc(Addr), VT: MVT::i32);
245 return true;
246 }
247 }
248 return false;
249}
250
251void VEDAGToDAGISel::Select(SDNode *N) {
252 if (N->isMachineOpcode()) {
253 N->setNodeId(-1);
254 return; // Already selected.
255 }
256
257 switch (N->getOpcode()) {
258
259 // Late eliminate the LEGALAVL wrapper
260 case VEISD::LEGALAVL:
261 ReplaceNode(F: N, T: N->getOperand(Num: 0).getNode());
262 return;
263
264 // Lower (broadcast 1) and (broadcast 0) to VM[P]0
265 case VEISD::VEC_BROADCAST: {
266 MVT SplatResTy = N->getSimpleValueType(ResNo: 0);
267 if (SplatResTy.getVectorElementType() != MVT::i1)
268 break;
269
270 // Constant non-zero broadcast.
271 auto BConst = dyn_cast<ConstantSDNode>(Val: N->getOperand(Num: 0));
272 if (!BConst)
273 break;
274 bool BCTrueMask = (BConst->getSExtValue() != 0);
275 if (!BCTrueMask)
276 break;
277
278 // Packed or non-packed.
279 SDValue New;
280 if (SplatResTy.getVectorNumElements() == StandardVectorWidth) {
281 New = CurDAG->getCopyFromReg(Chain: CurDAG->getEntryNode(), dl: SDLoc(N), Reg: VE::VM0,
282 VT: MVT::v256i1);
283 } else if (SplatResTy.getVectorNumElements() == PackedVectorWidth) {
284 New = CurDAG->getCopyFromReg(Chain: CurDAG->getEntryNode(), dl: SDLoc(N), Reg: VE::VMP0,
285 VT: MVT::v512i1);
286 } else
287 break;
288
289 // Replace.
290 ReplaceNode(F: N, T: New.getNode());
291 return;
292 }
293
294 case VEISD::GLOBAL_BASE_REG:
295 ReplaceNode(F: N, T: getGlobalBaseReg());
296 return;
297 }
298
299 SelectCode(N);
300}
301
302/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
303/// inline asm expressions.
304bool VEDAGToDAGISel::SelectInlineAsmMemoryOperand(
305 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
306 std::vector<SDValue> &OutOps) {
307 SDValue Op0, Op1;
308 switch (ConstraintID) {
309 default:
310 llvm_unreachable("Unexpected asm memory constraint");
311 case InlineAsm::ConstraintCode::o:
312 case InlineAsm::ConstraintCode::m: // memory
313 // Try to match ADDRri since reg+imm style is safe for all VE instructions
314 // with a memory operand.
315 if (selectADDRri(Addr: Op, Base&: Op0, Offset&: Op1)) {
316 OutOps.push_back(x: Op0);
317 OutOps.push_back(x: Op1);
318 return false;
319 }
320 // Otherwise, require the address to be in a register and immediate 0.
321 OutOps.push_back(x: Op);
322 OutOps.push_back(x: CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Op), VT: MVT::i32));
323 return false;
324 }
325 return true;
326}
327
328SDNode *VEDAGToDAGISel::getGlobalBaseReg() {
329 Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
330 return CurDAG
331 ->getRegister(Reg: GlobalBaseReg, VT: TLI->getPointerTy(DL: CurDAG->getDataLayout()))
332 .getNode();
333}
334
335/// createVEISelDag - This pass converts a legalized DAG into a
336/// VE-specific DAG, ready for instruction scheduling.
337///
338FunctionPass *llvm::createVEISelDag(VETargetMachine &TM) {
339 return new VEDAGToDAGISelLegacy(TM);
340}
341