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 static char ID;
38
39 VEDAGToDAGISel() = delete;
40
41 explicit VEDAGToDAGISel(VETargetMachine &tm) : SelectionDAGISel(ID, tm) {}
42
43 bool runOnMachineFunction(MachineFunction &MF) override {
44 Subtarget = &MF.getSubtarget<VESubtarget>();
45 return SelectionDAGISel::runOnMachineFunction(MF);
46 }
47
48 void Select(SDNode *N) override;
49
50 // Complex Pattern Selectors.
51 bool selectADDRrri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
52 bool selectADDRrii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
53 bool selectADDRzri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
54 bool selectADDRzii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
55 bool selectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
56 bool selectADDRzi(SDValue N, SDValue &Base, SDValue &Offset);
57
58 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
59 /// inline asm expressions.
60 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
61 InlineAsm::ConstraintCode ConstraintID,
62 std::vector<SDValue> &OutOps) override;
63
64 // Include the pieces autogenerated from the target description.
65#include "VEGenDAGISel.inc"
66
67private:
68 SDNode *getGlobalBaseReg();
69
70 bool matchADDRrr(SDValue N, SDValue &Base, SDValue &Index);
71 bool matchADDRri(SDValue N, SDValue &Base, SDValue &Offset);
72};
73} // end anonymous namespace
74
75char VEDAGToDAGISel::ID = 0;
76
77INITIALIZE_PASS(VEDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
78
79bool VEDAGToDAGISel::selectADDRrri(SDValue Addr, SDValue &Base, SDValue &Index,
80 SDValue &Offset) {
81 if (Addr.getOpcode() == ISD::FrameIndex)
82 return false;
83 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
84 Addr.getOpcode() == ISD::TargetGlobalAddress ||
85 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
86 return false; // direct calls.
87
88 SDValue LHS, RHS;
89 if (matchADDRri(N: Addr, Base&: LHS, Offset&: RHS)) {
90 if (matchADDRrr(N: LHS, Base, Index)) {
91 Offset = RHS;
92 return true;
93 }
94 // Return false to try selectADDRrii.
95 return false;
96 }
97 if (matchADDRrr(N: Addr, Base&: LHS, Index&: RHS)) {
98 // If the input is a pair of a frame-index and a register, move a
99 // frame-index to LHS. This generates MI with following operands.
100 // %dest, #FI, %reg, offset
101 // In the eliminateFrameIndex, above MI is converted to the following.
102 // %dest, %fp, %reg, fi_offset + offset
103 if (isa<FrameIndexSDNode>(Val: RHS))
104 std::swap(a&: LHS, b&: RHS);
105
106 if (matchADDRri(N: RHS, Base&: Index, Offset)) {
107 Base = LHS;
108 return true;
109 }
110 if (matchADDRri(N: LHS, Base, Offset)) {
111 Index = RHS;
112 return true;
113 }
114 Base = LHS;
115 Index = RHS;
116 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
117 return true;
118 }
119 return false; // Let the reg+imm(=0) pattern catch this!
120}
121
122bool VEDAGToDAGISel::selectADDRrii(SDValue Addr, SDValue &Base, SDValue &Index,
123 SDValue &Offset) {
124 if (matchADDRri(N: Addr, Base, Offset)) {
125 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
126 return true;
127 }
128
129 Base = Addr;
130 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
131 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
132 return true;
133}
134
135bool VEDAGToDAGISel::selectADDRzri(SDValue Addr, SDValue &Base, SDValue &Index,
136 SDValue &Offset) {
137 // Prefer ADDRrii.
138 return false;
139}
140
141bool VEDAGToDAGISel::selectADDRzii(SDValue Addr, SDValue &Base, SDValue &Index,
142 SDValue &Offset) {
143 if (isa<FrameIndexSDNode>(Val: Addr))
144 return false;
145 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
146 Addr.getOpcode() == ISD::TargetGlobalAddress ||
147 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
148 return false; // direct calls.
149
150 if (auto *CN = dyn_cast<ConstantSDNode>(Val&: Addr)) {
151 if (isInt<32>(x: CN->getSExtValue())) {
152 Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
153 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
154 Offset =
155 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
156 return true;
157 }
158 }
159 return false;
160}
161
162bool VEDAGToDAGISel::selectADDRri(SDValue Addr, SDValue &Base,
163 SDValue &Offset) {
164 if (matchADDRri(N: Addr, Base, Offset))
165 return true;
166
167 Base = Addr;
168 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
169 return true;
170}
171
172bool VEDAGToDAGISel::selectADDRzi(SDValue Addr, SDValue &Base,
173 SDValue &Offset) {
174 if (isa<FrameIndexSDNode>(Val: Addr))
175 return false;
176 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
177 Addr.getOpcode() == ISD::TargetGlobalAddress ||
178 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
179 return false; // direct calls.
180
181 if (auto *CN = dyn_cast<ConstantSDNode>(Val&: Addr)) {
182 if (isInt<32>(x: CN->getSExtValue())) {
183 Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
184 Offset =
185 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
186 return true;
187 }
188 }
189 return false;
190}
191
192bool VEDAGToDAGISel::matchADDRrr(SDValue Addr, SDValue &Base, SDValue &Index) {
193 if (isa<FrameIndexSDNode>(Val: Addr))
194 return false;
195 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
196 Addr.getOpcode() == ISD::TargetGlobalAddress ||
197 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
198 return false; // direct calls.
199
200 if (Addr.getOpcode() == ISD::ADD) {
201 ; // Nothing to do here.
202 } else if (Addr.getOpcode() == ISD::OR) {
203 // We want to look through a transform in InstCombine and DAGCombiner that
204 // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
205 if (!CurDAG->haveNoCommonBitsSet(A: Addr.getOperand(i: 0), B: Addr.getOperand(i: 1)))
206 return false;
207 } else {
208 return false;
209 }
210
211 if (Addr.getOperand(i: 0).getOpcode() == VEISD::Lo ||
212 Addr.getOperand(i: 1).getOpcode() == VEISD::Lo)
213 return false; // Let the LEASL patterns catch this!
214
215 Base = Addr.getOperand(i: 0);
216 Index = Addr.getOperand(i: 1);
217 return true;
218}
219
220bool VEDAGToDAGISel::matchADDRri(SDValue Addr, SDValue &Base, SDValue &Offset) {
221 auto AddrTy = Addr->getValueType(ResNo: 0);
222 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Val&: Addr)) {
223 Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), VT: AddrTy);
224 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
225 return true;
226 }
227 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
228 Addr.getOpcode() == ISD::TargetGlobalAddress ||
229 Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
230 return false; // direct calls.
231
232 if (CurDAG->isBaseWithConstantOffset(Op: Addr)) {
233 ConstantSDNode *CN = cast<ConstantSDNode>(Val: Addr.getOperand(i: 1));
234 if (isInt<32>(x: CN->getSExtValue())) {
235 if (FrameIndexSDNode *FIN =
236 dyn_cast<FrameIndexSDNode>(Val: Addr.getOperand(i: 0))) {
237 // Constant offset from frame ref.
238 Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), VT: AddrTy);
239 } else {
240 Base = Addr.getOperand(i: 0);
241 }
242 Offset =
243 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
244 return true;
245 }
246 }
247 return false;
248}
249
250void VEDAGToDAGISel::Select(SDNode *N) {
251 SDLoc dl(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(CurDAG->getEntryNode(), SDLoc(N), VE::VM0,
282 MVT::v256i1);
283 } else if (SplatResTy.getVectorNumElements() == PackedVectorWidth) {
284 New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(N), VE::VMP0,
285 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(CurDAG->getTargetConstant(0, SDLoc(Op), 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 VEDAGToDAGISel(TM);
340}
341

source code of llvm/lib/Target/VE/VEISelDAGToDAG.cpp