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 | |
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 | |
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; |
75 | explicit VEDAGToDAGISelLegacy(VETargetMachine &tm) |
76 | : SelectionDAGISelLegacy(ID, std::make_unique<VEDAGToDAGISel>(args&: tm)) {} |
77 | }; |
78 | } // end anonymous namespace |
79 | |
80 | char VEDAGToDAGISelLegacy::ID = 0; |
81 | |
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(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 | |
127 | bool 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 | |
140 | bool VEDAGToDAGISel::selectADDRzri(SDValue Addr, SDValue &Base, SDValue &Index, |
141 | SDValue &Offset) { |
142 | // Prefer ADDRrii. |
143 | return false; |
144 | } |
145 | |
146 | bool 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 | |
167 | bool 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 | |
177 | bool 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 | |
197 | bool 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 | |
225 | bool 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 | |
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(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. |
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(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 | |
333 | SDNode *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 | /// |
343 | FunctionPass *llvm::createVEISelDag(VETargetMachine &TM) { |
344 | return new VEDAGToDAGISelLegacy(TM); |
345 | } |
346 | |