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