xref: /llvm-project/llvm/lib/Target/VE/VEISelDAGToDAG.cpp (revision ed8019d9fbed2e6a6b08f8f73e9fa54a24f3ed52)
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/SelectionDAGISel.h"
16 #include "llvm/Support/ErrorHandling.h"
17 using namespace llvm;
18 
19 #define DEBUG_TYPE "ve-isel"
20 #define PASS_NAME "VE DAG->DAG Pattern Instruction Selection"
21 
22 //===--------------------------------------------------------------------===//
23 /// VEDAGToDAGISel - VE specific code to select VE machine
24 /// instructions for SelectionDAG operations.
25 ///
26 namespace {
27 class VEDAGToDAGISel : public SelectionDAGISel {
28   /// Subtarget - Keep a pointer to the VE Subtarget around so that we can
29   /// make the right decision when generating code for different targets.
30   const VESubtarget *Subtarget;
31 
32 public:
33   VEDAGToDAGISel() = delete;
34 
35   explicit VEDAGToDAGISel(VETargetMachine &tm) : SelectionDAGISel(tm) {}
36 
37   bool runOnMachineFunction(MachineFunction &MF) override {
38     Subtarget = &MF.getSubtarget<VESubtarget>();
39     return SelectionDAGISel::runOnMachineFunction(MF);
40   }
41 
42   void Select(SDNode *N) override;
43 
44   // Complex Pattern Selectors.
45   bool selectADDRrri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
46   bool selectADDRrii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
47   bool selectADDRzri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
48   bool selectADDRzii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
49   bool selectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
50   bool selectADDRzi(SDValue N, SDValue &Base, SDValue &Offset);
51 
52   /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
53   /// inline asm expressions.
54   bool SelectInlineAsmMemoryOperand(const SDValue &Op,
55                                     InlineAsm::ConstraintCode ConstraintID,
56                                     std::vector<SDValue> &OutOps) override;
57 
58   // Include the pieces autogenerated from the target description.
59 #include "VEGenDAGISel.inc"
60 
61 private:
62   SDNode *getGlobalBaseReg();
63 
64   bool matchADDRrr(SDValue N, SDValue &Base, SDValue &Index);
65   bool matchADDRri(SDValue N, SDValue &Base, SDValue &Offset);
66 };
67 
68 class VEDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
69 public:
70   static char ID;
71   explicit VEDAGToDAGISelLegacy(VETargetMachine &tm)
72       : SelectionDAGISelLegacy(ID, std::make_unique<VEDAGToDAGISel>(tm)) {}
73 };
74 } // end anonymous namespace
75 
76 char VEDAGToDAGISelLegacy::ID = 0;
77 
78 INITIALIZE_PASS(VEDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
79 
80 bool VEDAGToDAGISel::selectADDRrri(SDValue Addr, SDValue &Base, SDValue &Index,
81                                    SDValue &Offset) {
82   if (Addr.getOpcode() == ISD::FrameIndex)
83     return false;
84   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
85       Addr.getOpcode() == ISD::TargetGlobalAddress ||
86       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
87     return false; // direct calls.
88 
89   SDValue LHS, RHS;
90   if (matchADDRri(Addr, LHS, RHS)) {
91     if (matchADDRrr(LHS, Base, Index)) {
92       Offset = RHS;
93       return true;
94     }
95     // Return false to try selectADDRrii.
96     return false;
97   }
98   if (matchADDRrr(Addr, LHS, RHS)) {
99     // If the input is a pair of a frame-index and a register, move a
100     // frame-index to LHS.  This generates MI with following operands.
101     //    %dest, #FI, %reg, offset
102     // In the eliminateFrameIndex, above MI is converted to the following.
103     //    %dest, %fp, %reg, fi_offset + offset
104     if (isa<FrameIndexSDNode>(RHS))
105       std::swap(LHS, RHS);
106 
107     if (matchADDRri(RHS, Index, Offset)) {
108       Base = LHS;
109       return true;
110     }
111     if (matchADDRri(LHS, Base, Offset)) {
112       Index = RHS;
113       return true;
114     }
115     Base = LHS;
116     Index = RHS;
117     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
118     return true;
119   }
120   return false; // Let the reg+imm(=0) pattern catch this!
121 }
122 
123 bool VEDAGToDAGISel::selectADDRrii(SDValue Addr, SDValue &Base, SDValue &Index,
124                                    SDValue &Offset) {
125   if (matchADDRri(Addr, Base, Offset)) {
126     Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
127     return true;
128   }
129 
130   Base = Addr;
131   Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
132   Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
133   return true;
134 }
135 
136 bool VEDAGToDAGISel::selectADDRzri(SDValue Addr, SDValue &Base, SDValue &Index,
137                                    SDValue &Offset) {
138   // Prefer ADDRrii.
139   return false;
140 }
141 
142 bool VEDAGToDAGISel::selectADDRzii(SDValue Addr, SDValue &Base, SDValue &Index,
143                                    SDValue &Offset) {
144   if (isa<FrameIndexSDNode>(Addr))
145     return false;
146   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
147       Addr.getOpcode() == ISD::TargetGlobalAddress ||
148       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
149     return false; // direct calls.
150 
151   if (auto *CN = dyn_cast<ConstantSDNode>(Addr)) {
152     if (isInt<32>(CN->getSExtValue())) {
153       Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
154       Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
155       Offset =
156           CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
157       return true;
158     }
159   }
160   return false;
161 }
162 
163 bool VEDAGToDAGISel::selectADDRri(SDValue Addr, SDValue &Base,
164                                   SDValue &Offset) {
165   if (matchADDRri(Addr, Base, Offset))
166     return true;
167 
168   Base = Addr;
169   Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
170   return true;
171 }
172 
173 bool VEDAGToDAGISel::selectADDRzi(SDValue Addr, SDValue &Base,
174                                   SDValue &Offset) {
175   if (isa<FrameIndexSDNode>(Addr))
176     return false;
177   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
178       Addr.getOpcode() == ISD::TargetGlobalAddress ||
179       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
180     return false; // direct calls.
181 
182   if (auto *CN = dyn_cast<ConstantSDNode>(Addr)) {
183     if (isInt<32>(CN->getSExtValue())) {
184       Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
185       Offset =
186           CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
187       return true;
188     }
189   }
190   return false;
191 }
192 
193 bool VEDAGToDAGISel::matchADDRrr(SDValue Addr, SDValue &Base, SDValue &Index) {
194   if (isa<FrameIndexSDNode>(Addr))
195     return false;
196   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
197       Addr.getOpcode() == ISD::TargetGlobalAddress ||
198       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
199     return false; // direct calls.
200 
201   if (Addr.getOpcode() == ISD::ADD) {
202     ; // Nothing to do here.
203   } else if (Addr.getOpcode() == ISD::OR) {
204     // We want to look through a transform in InstCombine and DAGCombiner that
205     // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
206     if (!CurDAG->haveNoCommonBitsSet(Addr.getOperand(0), Addr.getOperand(1)))
207       return false;
208   } else {
209     return false;
210   }
211 
212   if (Addr.getOperand(0).getOpcode() == VEISD::Lo ||
213       Addr.getOperand(1).getOpcode() == VEISD::Lo)
214     return false; // Let the LEASL patterns catch this!
215 
216   Base = Addr.getOperand(0);
217   Index = Addr.getOperand(1);
218   return true;
219 }
220 
221 bool VEDAGToDAGISel::matchADDRri(SDValue Addr, SDValue &Base, SDValue &Offset) {
222   auto AddrTy = Addr->getValueType(0);
223   if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
224     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy);
225     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
226     return true;
227   }
228   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
229       Addr.getOpcode() == ISD::TargetGlobalAddress ||
230       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
231     return false; // direct calls.
232 
233   if (CurDAG->isBaseWithConstantOffset(Addr)) {
234     ConstantSDNode *CN = cast<ConstantSDNode>(Addr.getOperand(1));
235     if (isInt<32>(CN->getSExtValue())) {
236       if (FrameIndexSDNode *FIN =
237               dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
238         // Constant offset from frame ref.
239         Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy);
240       } else {
241         Base = Addr.getOperand(0);
242       }
243       Offset =
244           CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
245       return true;
246     }
247   }
248   return false;
249 }
250 
251 void VEDAGToDAGISel::Select(SDNode *N) {
252   SDLoc dl(N);
253   if (N->isMachineOpcode()) {
254     N->setNodeId(-1);
255     return; // Already selected.
256   }
257 
258   switch (N->getOpcode()) {
259 
260   // Late eliminate the LEGALAVL wrapper
261   case VEISD::LEGALAVL:
262     ReplaceNode(N, N->getOperand(0).getNode());
263     return;
264 
265   // Lower (broadcast 1) and (broadcast 0) to VM[P]0
266   case VEISD::VEC_BROADCAST: {
267     MVT SplatResTy = N->getSimpleValueType(0);
268     if (SplatResTy.getVectorElementType() != MVT::i1)
269       break;
270 
271     // Constant non-zero broadcast.
272     auto BConst = dyn_cast<ConstantSDNode>(N->getOperand(0));
273     if (!BConst)
274       break;
275     bool BCTrueMask = (BConst->getSExtValue() != 0);
276     if (!BCTrueMask)
277       break;
278 
279     // Packed or non-packed.
280     SDValue New;
281     if (SplatResTy.getVectorNumElements() == StandardVectorWidth) {
282       New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(N), VE::VM0,
283                                    MVT::v256i1);
284     } else if (SplatResTy.getVectorNumElements() == PackedVectorWidth) {
285       New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(N), VE::VMP0,
286                                    MVT::v512i1);
287     } else
288       break;
289 
290     // Replace.
291     ReplaceNode(N, New.getNode());
292     return;
293   }
294 
295   case VEISD::GLOBAL_BASE_REG:
296     ReplaceNode(N, getGlobalBaseReg());
297     return;
298   }
299 
300   SelectCode(N);
301 }
302 
303 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
304 /// inline asm expressions.
305 bool VEDAGToDAGISel::SelectInlineAsmMemoryOperand(
306     const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
307     std::vector<SDValue> &OutOps) {
308   SDValue Op0, Op1;
309   switch (ConstraintID) {
310   default:
311     llvm_unreachable("Unexpected asm memory constraint");
312   case InlineAsm::ConstraintCode::o:
313   case InlineAsm::ConstraintCode::m: // memory
314     // Try to match ADDRri since reg+imm style is safe for all VE instructions
315     // with a memory operand.
316     if (selectADDRri(Op, Op0, Op1)) {
317       OutOps.push_back(Op0);
318       OutOps.push_back(Op1);
319       return false;
320     }
321     // Otherwise, require the address to be in a register and immediate 0.
322     OutOps.push_back(Op);
323     OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32));
324     return false;
325   }
326   return true;
327 }
328 
329 SDNode *VEDAGToDAGISel::getGlobalBaseReg() {
330   Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
331   return CurDAG
332       ->getRegister(GlobalBaseReg, TLI->getPointerTy(CurDAG->getDataLayout()))
333       .getNode();
334 }
335 
336 /// createVEISelDag - This pass converts a legalized DAG into a
337 /// VE-specific DAG, ready for instruction scheduling.
338 ///
339 FunctionPass *llvm::createVEISelDag(VETargetMachine &TM) {
340   return new VEDAGToDAGISelLegacy(TM);
341 }
342