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"
21 using 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 ///
30 namespace {
31 class 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
36 public:
37 VEDAGToDAGISel() = delete;
38
VEDAGToDAGISel(VETargetMachine & tm)39 explicit VEDAGToDAGISel(VETargetMachine &tm) : SelectionDAGISel(tm) {}
40
runOnMachineFunction(MachineFunction & MF)41 bool runOnMachineFunction(MachineFunction &MF) override {
42 Subtarget = &MF.getSubtarget<VESubtarget>();
43 return SelectionDAGISel::runOnMachineFunction(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
65 private:
66 SDNode *getGlobalBaseReg();
67
68 bool matchADDRrr(SDValue N, SDValue &Base, SDValue &Index);
69 bool matchADDRri(SDValue N, SDValue &Base, SDValue &Offset);
70 };
71
72 class VEDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
73 public:
74 static char ID;
VEDAGToDAGISelLegacy(VETargetMachine & tm)75 explicit VEDAGToDAGISelLegacy(VETargetMachine &tm)
76 : SelectionDAGISelLegacy(ID, std::make_unique<VEDAGToDAGISel>(tm)) {}
77 };
78 } // end anonymous namespace
79
80 char VEDAGToDAGISelLegacy::ID = 0;
81
INITIALIZE_PASS(VEDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)82 INITIALIZE_PASS(VEDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
83
84 bool 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(Addr, LHS, RHS)) {
95 if (matchADDRrr(LHS, Base, Index)) {
96 Offset = RHS;
97 return true;
98 }
99 // Return false to try selectADDRrii.
100 return false;
101 }
102 if (matchADDRrr(Addr, LHS, 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>(RHS))
109 std::swap(LHS, RHS);
110
111 if (matchADDRri(RHS, Index, Offset)) {
112 Base = LHS;
113 return true;
114 }
115 if (matchADDRri(LHS, Base, Offset)) {
116 Index = RHS;
117 return true;
118 }
119 Base = LHS;
120 Index = RHS;
121 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
122 return true;
123 }
124 return false; // Let the reg+imm(=0) pattern catch this!
125 }
126
selectADDRrii(SDValue Addr,SDValue & Base,SDValue & Index,SDValue & Offset)127 bool VEDAGToDAGISel::selectADDRrii(SDValue Addr, SDValue &Base, SDValue &Index,
128 SDValue &Offset) {
129 if (matchADDRri(Addr, Base, Offset)) {
130 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
131 return true;
132 }
133
134 Base = Addr;
135 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
136 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
137 return true;
138 }
139
selectADDRzri(SDValue Addr,SDValue & Base,SDValue & Index,SDValue & Offset)140 bool VEDAGToDAGISel::selectADDRzri(SDValue Addr, SDValue &Base, SDValue &Index,
141 SDValue &Offset) {
142 // Prefer ADDRrii.
143 return false;
144 }
145
selectADDRzii(SDValue Addr,SDValue & Base,SDValue & Index,SDValue & Offset)146 bool VEDAGToDAGISel::selectADDRzii(SDValue Addr, SDValue &Base, SDValue &Index,
147 SDValue &Offset) {
148 if (isa<FrameIndexSDNode>(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>(Addr)) {
156 if (isInt<32>(CN->getSExtValue())) {
157 Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
158 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
159 Offset =
160 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
161 return true;
162 }
163 }
164 return false;
165 }
166
selectADDRri(SDValue Addr,SDValue & Base,SDValue & Offset)167 bool VEDAGToDAGISel::selectADDRri(SDValue Addr, SDValue &Base,
168 SDValue &Offset) {
169 if (matchADDRri(Addr, Base, Offset))
170 return true;
171
172 Base = Addr;
173 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
174 return true;
175 }
176
selectADDRzi(SDValue Addr,SDValue & Base,SDValue & Offset)177 bool VEDAGToDAGISel::selectADDRzi(SDValue Addr, SDValue &Base,
178 SDValue &Offset) {
179 if (isa<FrameIndexSDNode>(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>(Addr)) {
187 if (isInt<32>(CN->getSExtValue())) {
188 Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
189 Offset =
190 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
191 return true;
192 }
193 }
194 return false;
195 }
196
matchADDRrr(SDValue Addr,SDValue & Base,SDValue & Index)197 bool VEDAGToDAGISel::matchADDRrr(SDValue Addr, SDValue &Base, SDValue &Index) {
198 if (isa<FrameIndexSDNode>(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(Addr.getOperand(0), Addr.getOperand(1)))
211 return false;
212 } else {
213 return false;
214 }
215
216 if (Addr.getOperand(0).getOpcode() == VEISD::Lo ||
217 Addr.getOperand(1).getOpcode() == VEISD::Lo)
218 return false; // Let the LEASL patterns catch this!
219
220 Base = Addr.getOperand(0);
221 Index = Addr.getOperand(1);
222 return true;
223 }
224
matchADDRri(SDValue Addr,SDValue & Base,SDValue & Offset)225 bool VEDAGToDAGISel::matchADDRri(SDValue Addr, SDValue &Base, SDValue &Offset) {
226 auto AddrTy = Addr->getValueType(0);
227 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
228 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy);
229 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), 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(Addr)) {
238 ConstantSDNode *CN = cast<ConstantSDNode>(Addr.getOperand(1));
239 if (isInt<32>(CN->getSExtValue())) {
240 if (FrameIndexSDNode *FIN =
241 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
242 // Constant offset from frame ref.
243 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy);
244 } else {
245 Base = Addr.getOperand(0);
246 }
247 Offset =
248 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
249 return true;
250 }
251 }
252 return false;
253 }
254
Select(SDNode * N)255 void 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(N, N->getOperand(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(0);
272 if (SplatResTy.getVectorElementType() != MVT::i1)
273 break;
274
275 // Constant non-zero broadcast.
276 auto BConst = dyn_cast<ConstantSDNode>(N->getOperand(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(CurDAG->getEntryNode(), SDLoc(N), VE::VM0,
287 MVT::v256i1);
288 } else if (SplatResTy.getVectorNumElements() == PackedVectorWidth) {
289 New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(N), VE::VMP0,
290 MVT::v512i1);
291 } else
292 break;
293
294 // Replace.
295 ReplaceNode(N, New.getNode());
296 return;
297 }
298
299 case VEISD::GLOBAL_BASE_REG:
300 ReplaceNode(N, getGlobalBaseReg());
301 return;
302 }
303
304 SelectCode(N);
305 }
306
307 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
308 /// inline asm expressions.
SelectInlineAsmMemoryOperand(const SDValue & Op,InlineAsm::ConstraintCode ConstraintID,std::vector<SDValue> & OutOps)309 bool 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(Op, Op0, Op1)) {
321 OutOps.push_back(Op0);
322 OutOps.push_back(Op1);
323 return false;
324 }
325 // Otherwise, require the address to be in a register and immediate 0.
326 OutOps.push_back(Op);
327 OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32));
328 return false;
329 }
330 return true;
331 }
332
getGlobalBaseReg()333 SDNode *VEDAGToDAGISel::getGlobalBaseReg() {
334 Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
335 return CurDAG
336 ->getRegister(GlobalBaseReg, TLI->getPointerTy(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 ///
createVEISelDag(VETargetMachine & TM)343 FunctionPass *llvm::createVEISelDag(VETargetMachine &TM) {
344 return new VEDAGToDAGISelLegacy(TM);
345 }
346