1193323Sed//===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
2193323Sed//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6193323Sed//
7193323Sed//===----------------------------------------------------------------------===//
8193323Sed//
9193323Sed// This file defines an instruction selector for the SPARC target.
10193323Sed//
11193323Sed//===----------------------------------------------------------------------===//
12193323Sed
13193323Sed#include "SparcTargetMachine.h"
14296417Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
15193323Sed#include "llvm/CodeGen/SelectionDAGISel.h"
16249423Sdim#include "llvm/IR/Intrinsics.h"
17193323Sed#include "llvm/Support/Debug.h"
18198090Srdivacky#include "llvm/Support/ErrorHandling.h"
19198090Srdivacky#include "llvm/Support/raw_ostream.h"
20193323Sedusing namespace llvm;
21193323Sed
22193323Sed//===----------------------------------------------------------------------===//
23193323Sed// Instruction Selector Implementation
24193323Sed//===----------------------------------------------------------------------===//
25193323Sed
26193323Sed//===--------------------------------------------------------------------===//
27193323Sed/// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
28193323Sed/// instructions for SelectionDAG operations.
29193323Sed///
30193323Sednamespace {
31193323Sedclass SparcDAGToDAGISel : public SelectionDAGISel {
32193323Sed  /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
33193323Sed  /// make the right decision when generating code for different targets.
34360784Sdim  const SparcSubtarget *Subtarget = nullptr;
35193323Sedpublic:
36288943Sdim  explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}
37288943Sdim
38288943Sdim  bool runOnMachineFunction(MachineFunction &MF) override {
39288943Sdim    Subtarget = &MF.getSubtarget<SparcSubtarget>();
40288943Sdim    return SelectionDAGISel::runOnMachineFunction(MF);
41193323Sed  }
42193323Sed
43309124Sdim  void Select(SDNode *N) override;
44193323Sed
45193323Sed  // Complex Pattern Selectors.
46218893Sdim  bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
47218893Sdim  bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
48193323Sed
49193323Sed  /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
50193323Sed  /// inline asm expressions.
51276479Sdim  bool SelectInlineAsmMemoryOperand(const SDValue &Op,
52288943Sdim                                    unsigned ConstraintID,
53276479Sdim                                    std::vector<SDValue> &OutOps) override;
54193323Sed
55314564Sdim  StringRef getPassName() const override {
56193323Sed    return "SPARC DAG->DAG Pattern Instruction Selection";
57193323Sed  }
58193323Sed
59193323Sed  // Include the pieces autogenerated from the target description.
60193323Sed#include "SparcGenDAGISel.inc"
61198090Srdivacky
62198090Srdivackyprivate:
63198090Srdivacky  SDNode* getGlobalBaseReg();
64309124Sdim  bool tryInlineAsm(SDNode *N);
65193323Sed};
66193323Sed}  // end anonymous namespace
67193323Sed
68198090SrdivackySDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
69288943Sdim  unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
70288943Sdim  return CurDAG->getRegister(GlobalBaseReg,
71288943Sdim                             TLI->getPointerTy(CurDAG->getDataLayout()))
72288943Sdim      .getNode();
73198090Srdivacky}
74198090Srdivacky
75218893Sdimbool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
76193323Sed                                     SDValue &Base, SDValue &Offset) {
77193323Sed  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
78288943Sdim    Base = CurDAG->getTargetFrameIndex(
79288943Sdim        FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
80288943Sdim    Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
81193323Sed    return true;
82193323Sed  }
83193323Sed  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
84261991Sdim      Addr.getOpcode() == ISD::TargetGlobalAddress ||
85261991Sdim      Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
86193323Sed    return false;  // direct calls.
87193323Sed
88193323Sed  if (Addr.getOpcode() == ISD::ADD) {
89193323Sed    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
90212904Sdim      if (isInt<13>(CN->getSExtValue())) {
91193323Sed        if (FrameIndexSDNode *FIN =
92193323Sed                dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
93193323Sed          // Constant offset from frame ref.
94288943Sdim          Base = CurDAG->getTargetFrameIndex(
95288943Sdim              FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
96193323Sed        } else {
97193323Sed          Base = Addr.getOperand(0);
98193323Sed        }
99288943Sdim        Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
100288943Sdim                                           MVT::i32);
101193323Sed        return true;
102193323Sed      }
103193323Sed    }
104193323Sed    if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
105193323Sed      Base = Addr.getOperand(1);
106193323Sed      Offset = Addr.getOperand(0).getOperand(0);
107193323Sed      return true;
108193323Sed    }
109193323Sed    if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
110193323Sed      Base = Addr.getOperand(0);
111193323Sed      Offset = Addr.getOperand(1).getOperand(0);
112193323Sed      return true;
113193323Sed    }
114193323Sed  }
115193323Sed  Base = Addr;
116288943Sdim  Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
117193323Sed  return true;
118193323Sed}
119193323Sed
120218893Sdimbool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
121193323Sed  if (Addr.getOpcode() == ISD::FrameIndex) return false;
122193323Sed  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
123261991Sdim      Addr.getOpcode() == ISD::TargetGlobalAddress ||
124261991Sdim      Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
125193323Sed    return false;  // direct calls.
126193323Sed
127193323Sed  if (Addr.getOpcode() == ISD::ADD) {
128212904Sdim    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
129212904Sdim      if (isInt<13>(CN->getSExtValue()))
130212904Sdim        return false;  // Let the reg+imm pattern catch this!
131193323Sed    if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
132193323Sed        Addr.getOperand(1).getOpcode() == SPISD::Lo)
133193323Sed      return false;  // Let the reg+imm pattern catch this!
134193323Sed    R1 = Addr.getOperand(0);
135193323Sed    R2 = Addr.getOperand(1);
136193323Sed    return true;
137193323Sed  }
138193323Sed
139193323Sed  R1 = Addr;
140288943Sdim  R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
141193323Sed  return true;
142193323Sed}
143193323Sed
144296417Sdim
145296417Sdim// Re-assemble i64 arguments split up in SelectionDAGBuilder's
146296417Sdim// visitInlineAsm / GetRegistersForValue functions.
147296417Sdim//
148296417Sdim// Note: This function was copied from, and is essentially identical
149296417Sdim// to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that
150296417Sdim// such hacking-up is necessary; a rethink of how inline asm operands
151296417Sdim// are handled may be in order to make doing this more sane.
152296417Sdim//
153296417Sdim// TODO: fix inline asm support so I can simply tell it that 'i64'
154296417Sdim// inputs to asm need to be allocated to the IntPair register type,
155296417Sdim// and have that work. Then, delete this function.
156309124Sdimbool SparcDAGToDAGISel::tryInlineAsm(SDNode *N){
157296417Sdim  std::vector<SDValue> AsmNodeOperands;
158296417Sdim  unsigned Flag, Kind;
159296417Sdim  bool Changed = false;
160296417Sdim  unsigned NumOps = N->getNumOperands();
161296417Sdim
162296417Sdim  // Normally, i64 data is bounded to two arbitrary GPRs for "%r"
163296417Sdim  // constraint.  However, some instructions (e.g. ldd/std) require
164296417Sdim  // (even/even+1) GPRs.
165296417Sdim
166296417Sdim  // So, here, we check for this case, and mutate the inlineasm to use
167296417Sdim  // a single IntPair register instead, which guarantees such even/odd
168296417Sdim  // placement.
169296417Sdim
170296417Sdim  SDLoc dl(N);
171296417Sdim  SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps-1)
172296417Sdim                                   : SDValue(nullptr,0);
173296417Sdim
174296417Sdim  SmallVector<bool, 8> OpChanged;
175296417Sdim  // Glue node will be appended late.
176296417Sdim  for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
177296417Sdim    SDValue op = N->getOperand(i);
178296417Sdim    AsmNodeOperands.push_back(op);
179296417Sdim
180296417Sdim    if (i < InlineAsm::Op_FirstOperand)
181296417Sdim      continue;
182296417Sdim
183296417Sdim    if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
184296417Sdim      Flag = C->getZExtValue();
185296417Sdim      Kind = InlineAsm::getKind(Flag);
186296417Sdim    }
187296417Sdim    else
188296417Sdim      continue;
189296417Sdim
190296417Sdim    // Immediate operands to inline asm in the SelectionDAG are modeled with
191296417Sdim    // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
192296417Sdim    // the second is a constant with the value of the immediate. If we get here
193296417Sdim    // and we have a Kind_Imm, skip the next operand, and continue.
194296417Sdim    if (Kind == InlineAsm::Kind_Imm) {
195296417Sdim      SDValue op = N->getOperand(++i);
196296417Sdim      AsmNodeOperands.push_back(op);
197296417Sdim      continue;
198296417Sdim    }
199296417Sdim
200296417Sdim    unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
201296417Sdim    if (NumRegs)
202296417Sdim      OpChanged.push_back(false);
203296417Sdim
204296417Sdim    unsigned DefIdx = 0;
205296417Sdim    bool IsTiedToChangedOp = false;
206296417Sdim    // If it's a use that is tied with a previous def, it has no
207296417Sdim    // reg class constraint.
208296417Sdim    if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx))
209296417Sdim      IsTiedToChangedOp = OpChanged[DefIdx];
210296417Sdim
211296417Sdim    if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef
212296417Sdim        && Kind != InlineAsm::Kind_RegDefEarlyClobber)
213296417Sdim      continue;
214296417Sdim
215296417Sdim    unsigned RC;
216296417Sdim    bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
217296417Sdim    if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))
218296417Sdim        || NumRegs != 2)
219296417Sdim      continue;
220296417Sdim
221296417Sdim    assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
222296417Sdim    SDValue V0 = N->getOperand(i+1);
223296417Sdim    SDValue V1 = N->getOperand(i+2);
224296417Sdim    unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
225296417Sdim    unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
226296417Sdim    SDValue PairedReg;
227296417Sdim    MachineRegisterInfo &MRI = MF->getRegInfo();
228296417Sdim
229296417Sdim    if (Kind == InlineAsm::Kind_RegDef ||
230296417Sdim        Kind == InlineAsm::Kind_RegDefEarlyClobber) {
231296417Sdim      // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
232296417Sdim      // the original GPRs.
233296417Sdim
234360784Sdim      Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
235296417Sdim      PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
236296417Sdim      SDValue Chain = SDValue(N,0);
237296417Sdim
238296417Sdim      SDNode *GU = N->getGluedUser();
239296417Sdim      SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
240296417Sdim                                               Chain.getValue(1));
241296417Sdim
242296417Sdim      // Extract values from a GPRPair reg and copy to the original GPR reg.
243296417Sdim      SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,
244296417Sdim                                                    RegCopy);
245296417Sdim      SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
246296417Sdim                                                    RegCopy);
247296417Sdim      SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
248296417Sdim                                        RegCopy.getValue(1));
249296417Sdim      SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
250296417Sdim
251296417Sdim      // Update the original glue user.
252296417Sdim      std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
253296417Sdim      Ops.push_back(T1.getValue(1));
254296417Sdim      CurDAG->UpdateNodeOperands(GU, Ops);
255296417Sdim    }
256296417Sdim    else {
257296417Sdim      // For Kind  == InlineAsm::Kind_RegUse, we first copy two GPRs into a
258296417Sdim      // GPRPair and then pass the GPRPair to the inline asm.
259296417Sdim      SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
260296417Sdim
261296417Sdim      // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
262296417Sdim      SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
263296417Sdim                                          Chain.getValue(1));
264296417Sdim      SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
265296417Sdim                                          T0.getValue(1));
266296417Sdim      SDValue Pair = SDValue(
267296417Sdim          CurDAG->getMachineNode(
268296417Sdim              TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
269296417Sdim              {
270296417Sdim                  CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
271296417Sdim                                            MVT::i32),
272296417Sdim                  T0,
273296417Sdim                  CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
274296417Sdim                  T1,
275296417Sdim                  CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
276296417Sdim              }),
277296417Sdim          0);
278296417Sdim
279296417Sdim      // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
280296417Sdim      // i32 VRs of inline asm with it.
281360784Sdim      Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
282296417Sdim      PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
283296417Sdim      Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
284296417Sdim
285296417Sdim      AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
286296417Sdim      Glue = Chain.getValue(1);
287296417Sdim    }
288296417Sdim
289296417Sdim    Changed = true;
290296417Sdim
291296417Sdim    if(PairedReg.getNode()) {
292296417Sdim      OpChanged[OpChanged.size() -1 ] = true;
293296417Sdim      Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
294296417Sdim      if (IsTiedToChangedOp)
295296417Sdim        Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
296296417Sdim      else
297296417Sdim        Flag = InlineAsm::getFlagWordForRegClass(Flag, SP::IntPairRegClassID);
298296417Sdim      // Replace the current flag.
299296417Sdim      AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
300296417Sdim          Flag, dl, MVT::i32);
301296417Sdim      // Add the new register node and skip the original two GPRs.
302296417Sdim      AsmNodeOperands.push_back(PairedReg);
303296417Sdim      // Skip the next two GPRs.
304296417Sdim      i += 2;
305296417Sdim    }
306296417Sdim  }
307296417Sdim
308296417Sdim  if (Glue.getNode())
309296417Sdim    AsmNodeOperands.push_back(Glue);
310296417Sdim  if (!Changed)
311309124Sdim    return false;
312296417Sdim
313341825Sdim  SelectInlineAsmMemoryOperands(AsmNodeOperands, SDLoc(N));
314341825Sdim
315353358Sdim  SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
316296417Sdim      CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
317296417Sdim  New->setNodeId(-1);
318309124Sdim  ReplaceNode(N, New.getNode());
319309124Sdim  return true;
320296417Sdim}
321296417Sdim
322309124Sdimvoid SparcDAGToDAGISel::Select(SDNode *N) {
323261991Sdim  SDLoc dl(N);
324255804Sdim  if (N->isMachineOpcode()) {
325255804Sdim    N->setNodeId(-1);
326309124Sdim    return;   // Already selected.
327255804Sdim  }
328193323Sed
329193323Sed  switch (N->getOpcode()) {
330193323Sed  default: break;
331353358Sdim  case ISD::INLINEASM:
332353358Sdim  case ISD::INLINEASM_BR: {
333309124Sdim    if (tryInlineAsm(N))
334309124Sdim      return;
335296417Sdim    break;
336296417Sdim  }
337198090Srdivacky  case SPISD::GLOBAL_BASE_REG:
338309124Sdim    ReplaceNode(N, getGlobalBaseReg());
339309124Sdim    return;
340198090Srdivacky
341193323Sed  case ISD::SDIV:
342193323Sed  case ISD::UDIV: {
343251662Sdim    // sdivx / udivx handle 64-bit divides.
344251662Sdim    if (N->getValueType(0) == MVT::i64)
345251662Sdim      break;
346193323Sed    // FIXME: should use a custom expander to expose the SRA to the dag.
347193323Sed    SDValue DivLHS = N->getOperand(0);
348193323Sed    SDValue DivRHS = N->getOperand(1);
349193323Sed
350193323Sed    // Set the Y register to the high-part.
351193323Sed    SDValue TopPart;
352193323Sed    if (N->getOpcode() == ISD::SDIV) {
353198090Srdivacky      TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
354288943Sdim                                   CurDAG->getTargetConstant(31, dl, MVT::i32)),
355288943Sdim                        0);
356193323Sed    } else {
357193323Sed      TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
358193323Sed    }
359288943Sdim    TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
360288943Sdim                                   SDValue())
361288943Sdim                  .getValue(1);
362193323Sed
363193323Sed    // FIXME: Handle div by immediate.
364193323Sed    unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
365309124Sdim    CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);
366309124Sdim    return;
367193323Sed  }
368193323Sed  }
369193323Sed
370309124Sdim  SelectCode(N);
371193323Sed}
372193323Sed
373193323Sed
374193323Sed/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
375193323Sed/// inline asm expressions.
376193323Sedbool
377193323SedSparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
378288943Sdim                                                unsigned ConstraintID,
379193323Sed                                                std::vector<SDValue> &OutOps) {
380193323Sed  SDValue Op0, Op1;
381288943Sdim  switch (ConstraintID) {
382193323Sed  default: return true;
383309124Sdim  case InlineAsm::Constraint_o:
384288943Sdim  case InlineAsm::Constraint_m: // memory
385218893Sdim   if (!SelectADDRrr(Op, Op0, Op1))
386218893Sdim     SelectADDRri(Op, Op0, Op1);
387193323Sed   break;
388193323Sed  }
389193323Sed
390193323Sed  OutOps.push_back(Op0);
391193323Sed  OutOps.push_back(Op1);
392193323Sed  return false;
393193323Sed}
394193323Sed
395193323Sed/// createSparcISelDag - This pass converts a legalized DAG into a
396193323Sed/// SPARC-specific DAG, ready for instruction scheduling.
397193323Sed///
398193323SedFunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
399193323Sed  return new SparcDAGToDAGISel(TM);
400193323Sed}
401