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 //===----------------------------------------------------------------------===//
24 // Instruction Selector Implementation
25 //===----------------------------------------------------------------------===//
26 
27 /// Convert a DAG integer condition code to a VE ICC condition.
28 inline static VECC::CondCode intCondCode2Icc(ISD::CondCode CC) {
29   switch (CC) {
30   default:
31     llvm_unreachable("Unknown integer condition code!");
32   case ISD::SETEQ:
33     return VECC::CC_IEQ;
34   case ISD::SETNE:
35     return VECC::CC_INE;
36   case ISD::SETLT:
37     return VECC::CC_IL;
38   case ISD::SETGT:
39     return VECC::CC_IG;
40   case ISD::SETLE:
41     return VECC::CC_ILE;
42   case ISD::SETGE:
43     return VECC::CC_IGE;
44   case ISD::SETULT:
45     return VECC::CC_IL;
46   case ISD::SETULE:
47     return VECC::CC_ILE;
48   case ISD::SETUGT:
49     return VECC::CC_IG;
50   case ISD::SETUGE:
51     return VECC::CC_IGE;
52   }
53 }
54 
55 /// Convert a DAG floating point condition code to a VE FCC condition.
56 inline static VECC::CondCode fpCondCode2Fcc(ISD::CondCode CC) {
57   switch (CC) {
58   default:
59     llvm_unreachable("Unknown fp condition code!");
60   case ISD::SETFALSE:
61     return VECC::CC_AF;
62   case ISD::SETEQ:
63   case ISD::SETOEQ:
64     return VECC::CC_EQ;
65   case ISD::SETNE:
66   case ISD::SETONE:
67     return VECC::CC_NE;
68   case ISD::SETLT:
69   case ISD::SETOLT:
70     return VECC::CC_L;
71   case ISD::SETGT:
72   case ISD::SETOGT:
73     return VECC::CC_G;
74   case ISD::SETLE:
75   case ISD::SETOLE:
76     return VECC::CC_LE;
77   case ISD::SETGE:
78   case ISD::SETOGE:
79     return VECC::CC_GE;
80   case ISD::SETO:
81     return VECC::CC_NUM;
82   case ISD::SETUO:
83     return VECC::CC_NAN;
84   case ISD::SETUEQ:
85     return VECC::CC_EQNAN;
86   case ISD::SETUNE:
87     return VECC::CC_NENAN;
88   case ISD::SETULT:
89     return VECC::CC_LNAN;
90   case ISD::SETUGT:
91     return VECC::CC_GNAN;
92   case ISD::SETULE:
93     return VECC::CC_LENAN;
94   case ISD::SETUGE:
95     return VECC::CC_GENAN;
96   case ISD::SETTRUE:
97     return VECC::CC_AT;
98   }
99 }
100 
101 /// getImmVal - get immediate representation of integer value
102 inline static uint64_t getImmVal(const ConstantSDNode *N) {
103   return N->getSExtValue();
104 }
105 
106 /// getFpImmVal - get immediate representation of floating point value
107 inline static uint64_t getFpImmVal(const ConstantFPSDNode *N) {
108   const APInt &Imm = N->getValueAPF().bitcastToAPInt();
109   uint64_t Val = Imm.getZExtValue();
110   if (Imm.getBitWidth() == 32) {
111     // Immediate value of float place places at higher bits on VE.
112     Val <<= 32;
113   }
114   return Val;
115 }
116 
117 //===--------------------------------------------------------------------===//
118 /// VEDAGToDAGISel - VE specific code to select VE machine
119 /// instructions for SelectionDAG operations.
120 ///
121 namespace {
122 class VEDAGToDAGISel : public SelectionDAGISel {
123   /// Subtarget - Keep a pointer to the VE Subtarget around so that we can
124   /// make the right decision when generating code for different targets.
125   const VESubtarget *Subtarget;
126 
127 public:
128   explicit VEDAGToDAGISel(VETargetMachine &tm) : SelectionDAGISel(tm) {}
129 
130   bool runOnMachineFunction(MachineFunction &MF) override {
131     Subtarget = &MF.getSubtarget<VESubtarget>();
132     return SelectionDAGISel::runOnMachineFunction(MF);
133   }
134 
135   void Select(SDNode *N) override;
136 
137   // Complex Pattern Selectors.
138   bool selectADDRrri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
139   bool selectADDRrii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
140   bool selectADDRzri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
141   bool selectADDRzii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
142   bool selectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
143   bool selectADDRzi(SDValue N, SDValue &Base, SDValue &Offset);
144 
145   StringRef getPassName() const override {
146     return "VE DAG->DAG Pattern Instruction Selection";
147   }
148 
149   // Include the pieces autogenerated from the target description.
150 #include "VEGenDAGISel.inc"
151 
152 private:
153   SDNode *getGlobalBaseReg();
154 
155   bool matchADDRrr(SDValue N, SDValue &Base, SDValue &Index);
156   bool matchADDRri(SDValue N, SDValue &Base, SDValue &Offset);
157 };
158 } // end anonymous namespace
159 
160 bool VEDAGToDAGISel::selectADDRrri(SDValue Addr, SDValue &Base, SDValue &Index,
161                                    SDValue &Offset) {
162   if (Addr.getOpcode() == ISD::FrameIndex)
163     return false;
164   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
165       Addr.getOpcode() == ISD::TargetGlobalAddress ||
166       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
167     return false; // direct calls.
168 
169   SDValue LHS, RHS;
170   if (matchADDRri(Addr, LHS, RHS)) {
171     if (matchADDRrr(LHS, Base, Index)) {
172       Offset = RHS;
173       return true;
174     }
175     // Return false to try selectADDRrii.
176     return false;
177   }
178   if (matchADDRrr(Addr, LHS, RHS)) {
179     // If the input is a pair of a frame-index and a register, move a
180     // frame-index to LHS.  This generates MI with following operands.
181     //    %dest, #FI, %reg, offset
182     // In the eliminateFrameIndex, above MI is converted to the following.
183     //    %dest, %fp, %reg, fi_offset + offset
184     if (isa<FrameIndexSDNode>(RHS))
185       std::swap(LHS, RHS);
186 
187     if (matchADDRri(RHS, Index, Offset)) {
188       Base = LHS;
189       return true;
190     }
191     if (matchADDRri(LHS, Base, Offset)) {
192       Index = RHS;
193       return true;
194     }
195     Base = LHS;
196     Index = RHS;
197     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
198     return true;
199   }
200   return false; // Let the reg+imm(=0) pattern catch this!
201 }
202 
203 bool VEDAGToDAGISel::selectADDRrii(SDValue Addr, SDValue &Base, SDValue &Index,
204                                    SDValue &Offset) {
205   if (matchADDRri(Addr, Base, Offset)) {
206     Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
207     return true;
208   }
209 
210   Base = Addr;
211   Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
212   Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
213   return true;
214 }
215 
216 bool VEDAGToDAGISel::selectADDRzri(SDValue Addr, SDValue &Base, SDValue &Index,
217                                    SDValue &Offset) {
218   // Prefer ADDRrii.
219   return false;
220 }
221 
222 bool VEDAGToDAGISel::selectADDRzii(SDValue Addr, SDValue &Base, SDValue &Index,
223                                    SDValue &Offset) {
224   if (isa<FrameIndexSDNode>(Addr))
225     return false;
226   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
227       Addr.getOpcode() == ISD::TargetGlobalAddress ||
228       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
229     return false; // direct calls.
230 
231   if (auto *CN = dyn_cast<ConstantSDNode>(Addr)) {
232     if (isInt<32>(CN->getSExtValue())) {
233       Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
234       Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
235       Offset =
236           CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
237       return true;
238     }
239   }
240   return false;
241 }
242 
243 bool VEDAGToDAGISel::selectADDRri(SDValue Addr, SDValue &Base,
244                                   SDValue &Offset) {
245   if (matchADDRri(Addr, Base, Offset))
246     return true;
247 
248   Base = Addr;
249   Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
250   return true;
251 }
252 
253 bool VEDAGToDAGISel::selectADDRzi(SDValue Addr, SDValue &Base,
254                                   SDValue &Offset) {
255   if (isa<FrameIndexSDNode>(Addr))
256     return false;
257   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
258       Addr.getOpcode() == ISD::TargetGlobalAddress ||
259       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
260     return false; // direct calls.
261 
262   if (auto *CN = dyn_cast<ConstantSDNode>(Addr)) {
263     if (isInt<32>(CN->getSExtValue())) {
264       Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
265       Offset =
266           CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
267       return true;
268     }
269   }
270   return false;
271 }
272 
273 bool VEDAGToDAGISel::matchADDRrr(SDValue Addr, SDValue &Base, SDValue &Index) {
274   if (isa<FrameIndexSDNode>(Addr))
275     return false;
276   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
277       Addr.getOpcode() == ISD::TargetGlobalAddress ||
278       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
279     return false; // direct calls.
280 
281   if (Addr.getOpcode() == ISD::ADD) {
282     ; // Nothing to do here.
283   } else if (Addr.getOpcode() == ISD::OR) {
284     // We want to look through a transform in InstCombine and DAGCombiner that
285     // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
286     if (!CurDAG->haveNoCommonBitsSet(Addr.getOperand(0), Addr.getOperand(1)))
287       return false;
288   } else {
289     return false;
290   }
291 
292   if (Addr.getOperand(0).getOpcode() == VEISD::Lo ||
293       Addr.getOperand(1).getOpcode() == VEISD::Lo)
294     return false; // Let the LEASL patterns catch this!
295 
296   Base = Addr.getOperand(0);
297   Index = Addr.getOperand(1);
298   return true;
299 }
300 
301 bool VEDAGToDAGISel::matchADDRri(SDValue Addr, SDValue &Base, SDValue &Offset) {
302   auto AddrTy = Addr->getValueType(0);
303   if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
304     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy);
305     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
306     return true;
307   }
308   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
309       Addr.getOpcode() == ISD::TargetGlobalAddress ||
310       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
311     return false; // direct calls.
312 
313   if (CurDAG->isBaseWithConstantOffset(Addr)) {
314     ConstantSDNode *CN = cast<ConstantSDNode>(Addr.getOperand(1));
315     if (isInt<32>(CN->getSExtValue())) {
316       if (FrameIndexSDNode *FIN =
317               dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
318         // Constant offset from frame ref.
319         Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy);
320       } else {
321         Base = Addr.getOperand(0);
322       }
323       Offset =
324           CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
325       return true;
326     }
327   }
328   return false;
329 }
330 
331 void VEDAGToDAGISel::Select(SDNode *N) {
332   SDLoc dl(N);
333   if (N->isMachineOpcode()) {
334     N->setNodeId(-1);
335     return; // Already selected.
336   }
337 
338   switch (N->getOpcode()) {
339 
340   // Late eliminate the LEGALAVL wrapper
341   case VEISD::LEGALAVL:
342     ReplaceNode(N, N->getOperand(0).getNode());
343     return;
344 
345   // Lower (broadcast 1) and (broadcast 0) to VM[P]0
346   case VEISD::VEC_BROADCAST: {
347     MVT SplatResTy = N->getSimpleValueType(0);
348     if (SplatResTy.getVectorElementType() != MVT::i1)
349       break;
350 
351     // Constant non-zero broadcast.
352     auto BConst = dyn_cast<ConstantSDNode>(N->getOperand(0));
353     if (!BConst)
354       break;
355     bool BCTrueMask = (BConst->getSExtValue() != 0);
356     if (!BCTrueMask)
357       break;
358 
359     // Packed or non-packed.
360     SDValue New;
361     if (SplatResTy.getVectorNumElements() == StandardVectorWidth) {
362       New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(N), VE::VM0,
363                                    MVT::v256i1);
364     } else if (SplatResTy.getVectorNumElements() == PackedVectorWidth) {
365       New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(N), VE::VMP0,
366                                    MVT::v512i1);
367     } else
368       break;
369 
370     // Replace.
371     ReplaceNode(N, New.getNode());
372     return;
373   }
374 
375   case VEISD::GLOBAL_BASE_REG:
376     ReplaceNode(N, getGlobalBaseReg());
377     return;
378   }
379 
380   SelectCode(N);
381 }
382 
383 SDNode *VEDAGToDAGISel::getGlobalBaseReg() {
384   Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
385   return CurDAG
386       ->getRegister(GlobalBaseReg, TLI->getPointerTy(CurDAG->getDataLayout()))
387       .getNode();
388 }
389 
390 /// createVEISelDag - This pass converts a legalized DAG into a
391 /// VE-specific DAG, ready for instruction scheduling.
392 ///
393 FunctionPass *llvm::createVEISelDag(VETargetMachine &TM) {
394   return new VEDAGToDAGISel(TM);
395 }
396