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