xref: /freebsd/contrib/llvm-project/llvm/lib/Target/VE/VEISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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