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