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"
20using namespace llvm;
21
22//===----------------------------------------------------------------------===//
23// Instruction Selector Implementation
24//===----------------------------------------------------------------------===//
25
26/// Convert a DAG integer condition code to a VE ICC condition.
27inline 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.
55inline 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
101inline static uint64_t getImmVal(const ConstantSDNode *N) {
102  return N->getSExtValue();
103}
104
105/// getFpImmVal - get immediate representation of floating point value
106inline 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/// convMImmVal - Convert a mimm integer immediate value to target immediate.
117inline static uint64_t convMImmVal(uint64_t Val) {
118  if (Val == 0)
119    return 0; // (0)1
120  if (Val & (1UL << 63))
121    return countLeadingOnes(Val);       // (m)1
122  return countLeadingZeros(Val) | 0x40; // (m)0
123}
124
125//===--------------------------------------------------------------------===//
126/// VEDAGToDAGISel - VE specific code to select VE machine
127/// instructions for SelectionDAG operations.
128///
129namespace {
130class VEDAGToDAGISel : public SelectionDAGISel {
131  /// Subtarget - Keep a pointer to the VE Subtarget around so that we can
132  /// make the right decision when generating code for different targets.
133  const VESubtarget *Subtarget;
134
135public:
136  explicit VEDAGToDAGISel(VETargetMachine &tm) : SelectionDAGISel(tm) {}
137
138  bool runOnMachineFunction(MachineFunction &MF) override {
139    Subtarget = &MF.getSubtarget<VESubtarget>();
140    return SelectionDAGISel::runOnMachineFunction(MF);
141  }
142
143  void Select(SDNode *N) override;
144
145  // Complex Pattern Selectors.
146  bool selectADDRrri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
147  bool selectADDRrii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
148  bool selectADDRzri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
149  bool selectADDRzii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset);
150  bool selectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
151
152  StringRef getPassName() const override {
153    return "VE DAG->DAG Pattern Instruction Selection";
154  }
155
156  // Include the pieces autogenerated from the target description.
157#include "VEGenDAGISel.inc"
158
159private:
160  SDNode *getGlobalBaseReg();
161
162  bool matchADDRrr(SDValue N, SDValue &Base, SDValue &Index);
163  bool matchADDRri(SDValue N, SDValue &Base, SDValue &Offset);
164};
165} // end anonymous namespace
166
167bool VEDAGToDAGISel::selectADDRrri(SDValue Addr, SDValue &Base, SDValue &Index,
168                                   SDValue &Offset) {
169  if (Addr.getOpcode() == ISD::FrameIndex)
170    return false;
171  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
172      Addr.getOpcode() == ISD::TargetGlobalAddress ||
173      Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
174    return false; // direct calls.
175
176  SDValue LHS, RHS;
177  if (matchADDRri(Addr, LHS, RHS)) {
178    if (matchADDRrr(LHS, Base, Index)) {
179      Offset = RHS;
180      return true;
181    }
182    // Return false to try selectADDRrii.
183    return false;
184  }
185  if (matchADDRrr(Addr, LHS, RHS)) {
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
202bool 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
215bool VEDAGToDAGISel::selectADDRzri(SDValue Addr, SDValue &Base, SDValue &Index,
216                                   SDValue &Offset) {
217  // Prefer ADDRrii.
218  return false;
219}
220
221bool VEDAGToDAGISel::selectADDRzii(SDValue Addr, SDValue &Base, SDValue &Index,
222                                   SDValue &Offset) {
223  if (dyn_cast<FrameIndexSDNode>(Addr)) {
224    return false;
225  }
226  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
227      Addr.getOpcode() == ISD::TargetGlobalAddress ||
228      Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
229    return false; // direct calls.
230
231  if (ConstantSDNode *CN = 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
243bool 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
253bool VEDAGToDAGISel::matchADDRrr(SDValue Addr, SDValue &Base, SDValue &Index) {
254  if (dyn_cast<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 (Addr.getOpcode() == ISD::ADD) {
262    ; // Nothing to do here.
263  } else if (Addr.getOpcode() == ISD::OR) {
264    // We want to look through a transform in InstCombine and DAGCombiner that
265    // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
266    if (!CurDAG->haveNoCommonBitsSet(Addr.getOperand(0), Addr.getOperand(1)))
267      return false;
268  } else {
269    return false;
270  }
271
272  if (Addr.getOperand(0).getOpcode() == VEISD::Lo ||
273      Addr.getOperand(1).getOpcode() == VEISD::Lo)
274    return false; // Let the LEASL patterns catch this!
275
276  Base = Addr.getOperand(0);
277  Index = Addr.getOperand(1);
278  return true;
279}
280
281bool VEDAGToDAGISel::matchADDRri(SDValue Addr, SDValue &Base, SDValue &Offset) {
282  auto AddrTy = Addr->getValueType(0);
283  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
284    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy);
285    Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
286    return true;
287  }
288  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
289      Addr.getOpcode() == ISD::TargetGlobalAddress ||
290      Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
291    return false; // direct calls.
292
293  if (CurDAG->isBaseWithConstantOffset(Addr)) {
294    ConstantSDNode *CN = cast<ConstantSDNode>(Addr.getOperand(1));
295    if (isInt<32>(CN->getSExtValue())) {
296      if (FrameIndexSDNode *FIN =
297              dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
298        // Constant offset from frame ref.
299        Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy);
300      } else {
301        Base = Addr.getOperand(0);
302      }
303      Offset =
304          CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32);
305      return true;
306    }
307  }
308  return false;
309}
310
311void VEDAGToDAGISel::Select(SDNode *N) {
312  SDLoc dl(N);
313  if (N->isMachineOpcode()) {
314    N->setNodeId(-1);
315    return; // Already selected.
316  }
317
318  switch (N->getOpcode()) {
319  case VEISD::GLOBAL_BASE_REG:
320    ReplaceNode(N, getGlobalBaseReg());
321    return;
322  }
323
324  SelectCode(N);
325}
326
327SDNode *VEDAGToDAGISel::getGlobalBaseReg() {
328  Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
329  return CurDAG
330      ->getRegister(GlobalBaseReg, TLI->getPointerTy(CurDAG->getDataLayout()))
331      .getNode();
332}
333
334/// createVEISelDag - This pass converts a legalized DAG into a
335/// VE-specific DAG, ready for instruction scheduling.
336///
337FunctionPass *llvm::createVEISelDag(VETargetMachine &TM) {
338  return new VEDAGToDAGISel(TM);
339}
340