LLVM  10.0.0svn
SparcISelDAGToDAG.cpp
Go to the documentation of this file.
1 //===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
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 SPARC target.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "SparcTargetMachine.h"
16 #include "llvm/IR/Intrinsics.h"
17 #include "llvm/Support/Debug.h"
20 using namespace llvm;
21 
22 //===----------------------------------------------------------------------===//
23 // Instruction Selector Implementation
24 //===----------------------------------------------------------------------===//
25 
26 //===--------------------------------------------------------------------===//
27 /// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
28 /// instructions for SelectionDAG operations.
29 ///
30 namespace {
31 class SparcDAGToDAGISel : public SelectionDAGISel {
32  /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
33  /// make the right decision when generating code for different targets.
34  const SparcSubtarget *Subtarget;
35 public:
36  explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}
37 
38  bool runOnMachineFunction(MachineFunction &MF) override {
39  Subtarget = &MF.getSubtarget<SparcSubtarget>();
41  }
42 
43  void Select(SDNode *N) override;
44 
45  // Complex Pattern Selectors.
46  bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
47  bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
48 
49  /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
50  /// inline asm expressions.
51  bool SelectInlineAsmMemoryOperand(const SDValue &Op,
52  unsigned ConstraintID,
53  std::vector<SDValue> &OutOps) override;
54 
55  StringRef getPassName() const override {
56  return "SPARC DAG->DAG Pattern Instruction Selection";
57  }
58 
59  // Include the pieces autogenerated from the target description.
60 #include "SparcGenDAGISel.inc"
61 
62 private:
63  SDNode* getGlobalBaseReg();
64  bool tryInlineAsm(SDNode *N);
65 };
66 } // end anonymous namespace
67 
68 SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
69  unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
70  return CurDAG->getRegister(GlobalBaseReg,
71  TLI->getPointerTy(CurDAG->getDataLayout()))
72  .getNode();
73 }
74 
75 bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
77  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
78  Base = CurDAG->getTargetFrameIndex(
79  FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
80  Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
81  return true;
82  }
83  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
86  return false; // direct calls.
87 
88  if (Addr.getOpcode() == ISD::ADD) {
89  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
90  if (isInt<13>(CN->getSExtValue())) {
91  if (FrameIndexSDNode *FIN =
92  dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
93  // Constant offset from frame ref.
94  Base = CurDAG->getTargetFrameIndex(
95  FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
96  } else {
97  Base = Addr.getOperand(0);
98  }
99  Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
100  MVT::i32);
101  return true;
102  }
103  }
104  if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
105  Base = Addr.getOperand(1);
106  Offset = Addr.getOperand(0).getOperand(0);
107  return true;
108  }
109  if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
110  Base = Addr.getOperand(0);
111  Offset = Addr.getOperand(1).getOperand(0);
112  return true;
113  }
114  }
115  Base = Addr;
116  Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
117  return true;
118 }
119 
120 bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
121  if (Addr.getOpcode() == ISD::FrameIndex) return false;
122  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
125  return false; // direct calls.
126 
127  if (Addr.getOpcode() == ISD::ADD) {
128  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
129  if (isInt<13>(CN->getSExtValue()))
130  return false; // Let the reg+imm pattern catch this!
131  if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
132  Addr.getOperand(1).getOpcode() == SPISD::Lo)
133  return false; // Let the reg+imm pattern catch this!
134  R1 = Addr.getOperand(0);
135  R2 = Addr.getOperand(1);
136  return true;
137  }
138 
139  R1 = Addr;
140  R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
141  return true;
142 }
143 
144 
145 // Re-assemble i64 arguments split up in SelectionDAGBuilder's
146 // visitInlineAsm / GetRegistersForValue functions.
147 //
148 // Note: This function was copied from, and is essentially identical
149 // to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that
150 // such hacking-up is necessary; a rethink of how inline asm operands
151 // are handled may be in order to make doing this more sane.
152 //
153 // TODO: fix inline asm support so I can simply tell it that 'i64'
154 // inputs to asm need to be allocated to the IntPair register type,
155 // and have that work. Then, delete this function.
156 bool SparcDAGToDAGISel::tryInlineAsm(SDNode *N){
157  std::vector<SDValue> AsmNodeOperands;
158  unsigned Flag, Kind;
159  bool Changed = false;
160  unsigned NumOps = N->getNumOperands();
161 
162  // Normally, i64 data is bounded to two arbitrary GPRs for "%r"
163  // constraint. However, some instructions (e.g. ldd/std) require
164  // (even/even+1) GPRs.
165 
166  // So, here, we check for this case, and mutate the inlineasm to use
167  // a single IntPair register instead, which guarantees such even/odd
168  // placement.
169 
170  SDLoc dl(N);
171  SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps-1)
172  : SDValue(nullptr,0);
173 
174  SmallVector<bool, 8> OpChanged;
175  // Glue node will be appended late.
176  for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
177  SDValue op = N->getOperand(i);
178  AsmNodeOperands.push_back(op);
179 
181  continue;
182 
183  if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
184  Flag = C->getZExtValue();
185  Kind = InlineAsm::getKind(Flag);
186  }
187  else
188  continue;
189 
190  // Immediate operands to inline asm in the SelectionDAG are modeled with
191  // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
192  // the second is a constant with the value of the immediate. If we get here
193  // and we have a Kind_Imm, skip the next operand, and continue.
194  if (Kind == InlineAsm::Kind_Imm) {
195  SDValue op = N->getOperand(++i);
196  AsmNodeOperands.push_back(op);
197  continue;
198  }
199 
200  unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
201  if (NumRegs)
202  OpChanged.push_back(false);
203 
204  unsigned DefIdx = 0;
205  bool IsTiedToChangedOp = false;
206  // If it's a use that is tied with a previous def, it has no
207  // reg class constraint.
208  if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx))
209  IsTiedToChangedOp = OpChanged[DefIdx];
210 
211  if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef
213  continue;
214 
215  unsigned RC;
216  bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
217  if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))
218  || NumRegs != 2)
219  continue;
220 
221  assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
222  SDValue V0 = N->getOperand(i+1);
223  SDValue V1 = N->getOperand(i+2);
224  unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
225  unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
226  SDValue PairedReg;
227  MachineRegisterInfo &MRI = MF->getRegInfo();
228 
229  if (Kind == InlineAsm::Kind_RegDef ||
231  // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
232  // the original GPRs.
233 
234  Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
235  PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
236  SDValue Chain = SDValue(N,0);
237 
238  SDNode *GU = N->getGluedUser();
239  SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
240  Chain.getValue(1));
241 
242  // Extract values from a GPRPair reg and copy to the original GPR reg.
243  SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,
244  RegCopy);
245  SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
246  RegCopy);
247  SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
248  RegCopy.getValue(1));
249  SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
250 
251  // Update the original glue user.
252  std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
253  Ops.push_back(T1.getValue(1));
254  CurDAG->UpdateNodeOperands(GU, Ops);
255  }
256  else {
257  // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a
258  // GPRPair and then pass the GPRPair to the inline asm.
259  SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
260 
261  // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
262  SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
263  Chain.getValue(1));
264  SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
265  T0.getValue(1));
266  SDValue Pair = SDValue(
267  CurDAG->getMachineNode(
268  TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
269  {
270  CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
271  MVT::i32),
272  T0,
273  CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
274  T1,
275  CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
276  }),
277  0);
278 
279  // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
280  // i32 VRs of inline asm with it.
281  Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
282  PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
283  Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
284 
285  AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
286  Glue = Chain.getValue(1);
287  }
288 
289  Changed = true;
290 
291  if(PairedReg.getNode()) {
292  OpChanged[OpChanged.size() -1 ] = true;
293  Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
294  if (IsTiedToChangedOp)
295  Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
296  else
297  Flag = InlineAsm::getFlagWordForRegClass(Flag, SP::IntPairRegClassID);
298  // Replace the current flag.
299  AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
300  Flag, dl, MVT::i32);
301  // Add the new register node and skip the original two GPRs.
302  AsmNodeOperands.push_back(PairedReg);
303  // Skip the next two GPRs.
304  i += 2;
305  }
306  }
307 
308  if (Glue.getNode())
309  AsmNodeOperands.push_back(Glue);
310  if (!Changed)
311  return false;
312 
313  SelectInlineAsmMemoryOperands(AsmNodeOperands, SDLoc(N));
314 
315  SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
316  CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
317  New->setNodeId(-1);
318  ReplaceNode(N, New.getNode());
319  return true;
320 }
321 
323  SDLoc dl(N);
324  if (N->isMachineOpcode()) {
325  N->setNodeId(-1);
326  return; // Already selected.
327  }
328 
329  switch (N->getOpcode()) {
330  default: break;
331  case ISD::INLINEASM:
332  case ISD::INLINEASM_BR: {
333  if (tryInlineAsm(N))
334  return;
335  break;
336  }
338  ReplaceNode(N, getGlobalBaseReg());
339  return;
340 
341  case ISD::SDIV:
342  case ISD::UDIV: {
343  // sdivx / udivx handle 64-bit divides.
344  if (N->getValueType(0) == MVT::i64)
345  break;
346  // FIXME: should use a custom expander to expose the SRA to the dag.
347  SDValue DivLHS = N->getOperand(0);
348  SDValue DivRHS = N->getOperand(1);
349 
350  // Set the Y register to the high-part.
351  SDValue TopPart;
352  if (N->getOpcode() == ISD::SDIV) {
353  TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
354  CurDAG->getTargetConstant(31, dl, MVT::i32)),
355  0);
356  } else {
357  TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
358  }
359  TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
360  SDValue())
361  .getValue(1);
362 
363  // FIXME: Handle div by immediate.
364  unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
365  CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);
366  return;
367  }
368  }
369 
370  SelectCode(N);
371 }
372 
373 
374 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
375 /// inline asm expressions.
376 bool
377 SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
378  unsigned ConstraintID,
379  std::vector<SDValue> &OutOps) {
380  SDValue Op0, Op1;
381  switch (ConstraintID) {
382  default: return true;
385  case InlineAsm::Constraint_m: // memory
386  if (!SelectADDRrr(Op, Op0, Op1))
387  SelectADDRri(Op, Op0, Op1);
388  break;
389  }
390 
391  OutOps.push_back(Op0);
392  OutOps.push_back(Op1);
393  return false;
394 }
395 
396 /// createSparcISelDag - This pass converts a legalized DAG into a
397 /// SPARC-specific DAG, ready for instruction scheduling.
398 ///
400  return new SparcDAGToDAGISel(TM);
401 }
uint64_t CallInst * C
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
static unsigned getFlagWord(unsigned Kind, unsigned NumOps)
Definition: InlineAsm.h:269
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
Definition: ISDOpcodes.h:130
void setNodeId(int Id)
Set unique node id.
SDNode * getNode() const
get the SDNode which holds the desired result
#define R2(n)
#define op(i)
static bool isUseOperandTiedToDef(unsigned Flag, unsigned &Idx)
isUseOperandTiedToDef - Return true if the flag of the inline asm operand indicates it is an use oper...
Definition: InlineAsm.h:342
GlobalBaseReg - On Darwin, this node represents the result of the mflr at function entry...
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
static unsigned getFlagWordForRegClass(unsigned InputFlag, unsigned RC)
getFlagWordForRegClass - Augment an existing flag word returned by getFlagWord with the required regi...
Definition: InlineAsm.h:300
op_iterator op_end() const
INLINEASM - Represents an inline asm block.
Definition: ISDOpcodes.h:703
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:200
op_iterator op_begin() const
Flag
These should be considered private to the implementation of the MCInstrDesc class.
Definition: MCInstrDesc.h:131
unsigned const MachineRegisterInfo * MRI
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
SDNode * getGluedUser() const
If this node has a glue value with a user, return the user (there is at most one).
const SDValue & getOperand(unsigned Num) const
static unsigned getNumOperandRegisters(unsigned Flag)
getNumOperandRegisters - Extract the number of registers field from the inline asm operand flag...
Definition: InlineAsm.h:336
constexpr double e
Definition: MathExtras.h:57
static unsigned getKind(unsigned Flags)
Definition: InlineAsm.h:325
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:284
SDNode * getGluedNode() const
If this node has a glue operand, return the node to which the glue operand points.
FunctionPass * createSparcISelDag(SparcTargetMachine &TM)
createSparcISelDag - This pass converts a legalized DAG into a SPARC-specific DAG, ready for instruction scheduling.
size_t size() const
Definition: SmallVector.h:52
bool isMachineOpcode() const
Test if this node has a post-isel opcode, directly corresponding to a MachineInstr opcode...
unsigned getNumOperands() const
Return the number of values used by this operation.
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:837
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
static unsigned getReg(const void *D, unsigned RC, unsigned RegNo)
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
static bool hasRegClassConstraint(unsigned Flag, unsigned &RC)
hasRegClassConstraint - Returns true if the flag contains a register class constraint.
Definition: InlineAsm.h:351
#define N
unsigned getOpcode() const
SDValue getValue(unsigned R) const
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
INLINEASM_BR - Terminator version of inline asm. Used by asm-goto.
Definition: ISDOpcodes.h:706
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
const SDValue & getOperand(unsigned i) const
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation...
#define T1
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
static unsigned getFlagWordForMatchingOp(unsigned InputFlag, unsigned MatchedOperandNo)
getFlagWordForMatchingOp - Augment an existing flag word returned by getFlagWord with information ind...
Definition: InlineAsm.h:288