LLVM  8.0.1
SparcISelDAGToDAG.cpp
Go to the documentation of this file.
1 //===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines an instruction selector for the SPARC target.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "SparcTargetMachine.h"
17 #include "llvm/IR/Intrinsics.h"
18 #include "llvm/Support/Debug.h"
21 using namespace llvm;
22 
23 //===----------------------------------------------------------------------===//
24 // Instruction Selector Implementation
25 //===----------------------------------------------------------------------===//
26 
27 //===--------------------------------------------------------------------===//
28 /// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
29 /// instructions for SelectionDAG operations.
30 ///
31 namespace {
32 class SparcDAGToDAGISel : public SelectionDAGISel {
33  /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
34  /// make the right decision when generating code for different targets.
35  const SparcSubtarget *Subtarget;
36 public:
37  explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}
38 
39  bool runOnMachineFunction(MachineFunction &MF) override {
40  Subtarget = &MF.getSubtarget<SparcSubtarget>();
42  }
43 
44  void Select(SDNode *N) override;
45 
46  // Complex Pattern Selectors.
47  bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
48  bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
49 
50  /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
51  /// inline asm expressions.
52  bool SelectInlineAsmMemoryOperand(const SDValue &Op,
53  unsigned ConstraintID,
54  std::vector<SDValue> &OutOps) override;
55 
56  StringRef getPassName() const override {
57  return "SPARC DAG->DAG Pattern Instruction Selection";
58  }
59 
60  // Include the pieces autogenerated from the target description.
61 #include "SparcGenDAGISel.inc"
62 
63 private:
64  SDNode* getGlobalBaseReg();
65  bool tryInlineAsm(SDNode *N);
66 };
67 } // end anonymous namespace
68 
69 SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
70  unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
71  return CurDAG->getRegister(GlobalBaseReg,
72  TLI->getPointerTy(CurDAG->getDataLayout()))
73  .getNode();
74 }
75 
76 bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
78  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
79  Base = CurDAG->getTargetFrameIndex(
80  FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
81  Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
82  return true;
83  }
84  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
87  return false; // direct calls.
88 
89  if (Addr.getOpcode() == ISD::ADD) {
90  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
91  if (isInt<13>(CN->getSExtValue())) {
92  if (FrameIndexSDNode *FIN =
93  dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
94  // Constant offset from frame ref.
95  Base = CurDAG->getTargetFrameIndex(
96  FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
97  } else {
98  Base = Addr.getOperand(0);
99  }
100  Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
101  MVT::i32);
102  return true;
103  }
104  }
105  if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
106  Base = Addr.getOperand(1);
107  Offset = Addr.getOperand(0).getOperand(0);
108  return true;
109  }
110  if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
111  Base = Addr.getOperand(0);
112  Offset = Addr.getOperand(1).getOperand(0);
113  return true;
114  }
115  }
116  Base = Addr;
117  Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
118  return true;
119 }
120 
121 bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
122  if (Addr.getOpcode() == ISD::FrameIndex) return false;
123  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
126  return false; // direct calls.
127 
128  if (Addr.getOpcode() == ISD::ADD) {
129  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
130  if (isInt<13>(CN->getSExtValue()))
131  return false; // Let the reg+imm pattern catch this!
132  if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
133  Addr.getOperand(1).getOpcode() == SPISD::Lo)
134  return false; // Let the reg+imm pattern catch this!
135  R1 = Addr.getOperand(0);
136  R2 = Addr.getOperand(1);
137  return true;
138  }
139 
140  R1 = Addr;
141  R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
142  return true;
143 }
144 
145 
146 // Re-assemble i64 arguments split up in SelectionDAGBuilder's
147 // visitInlineAsm / GetRegistersForValue functions.
148 //
149 // Note: This function was copied from, and is essentially identical
150 // to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that
151 // such hacking-up is necessary; a rethink of how inline asm operands
152 // are handled may be in order to make doing this more sane.
153 //
154 // TODO: fix inline asm support so I can simply tell it that 'i64'
155 // inputs to asm need to be allocated to the IntPair register type,
156 // and have that work. Then, delete this function.
157 bool SparcDAGToDAGISel::tryInlineAsm(SDNode *N){
158  std::vector<SDValue> AsmNodeOperands;
159  unsigned Flag, Kind;
160  bool Changed = false;
161  unsigned NumOps = N->getNumOperands();
162 
163  // Normally, i64 data is bounded to two arbitrary GPRs for "%r"
164  // constraint. However, some instructions (e.g. ldd/std) require
165  // (even/even+1) GPRs.
166 
167  // So, here, we check for this case, and mutate the inlineasm to use
168  // a single IntPair register instead, which guarantees such even/odd
169  // placement.
170 
171  SDLoc dl(N);
172  SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps-1)
173  : SDValue(nullptr,0);
174 
175  SmallVector<bool, 8> OpChanged;
176  // Glue node will be appended late.
177  for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
178  SDValue op = N->getOperand(i);
179  AsmNodeOperands.push_back(op);
180 
182  continue;
183 
184  if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
185  Flag = C->getZExtValue();
186  Kind = InlineAsm::getKind(Flag);
187  }
188  else
189  continue;
190 
191  // Immediate operands to inline asm in the SelectionDAG are modeled with
192  // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
193  // the second is a constant with the value of the immediate. If we get here
194  // and we have a Kind_Imm, skip the next operand, and continue.
195  if (Kind == InlineAsm::Kind_Imm) {
196  SDValue op = N->getOperand(++i);
197  AsmNodeOperands.push_back(op);
198  continue;
199  }
200 
201  unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
202  if (NumRegs)
203  OpChanged.push_back(false);
204 
205  unsigned DefIdx = 0;
206  bool IsTiedToChangedOp = false;
207  // If it's a use that is tied with a previous def, it has no
208  // reg class constraint.
209  if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx))
210  IsTiedToChangedOp = OpChanged[DefIdx];
211 
212  if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef
214  continue;
215 
216  unsigned RC;
217  bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
218  if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))
219  || NumRegs != 2)
220  continue;
221 
222  assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
223  SDValue V0 = N->getOperand(i+1);
224  SDValue V1 = N->getOperand(i+2);
225  unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
226  unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
227  SDValue PairedReg;
228  MachineRegisterInfo &MRI = MF->getRegInfo();
229 
230  if (Kind == InlineAsm::Kind_RegDef ||
232  // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
233  // the original GPRs.
234 
235  unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
236  PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
237  SDValue Chain = SDValue(N,0);
238 
239  SDNode *GU = N->getGluedUser();
240  SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
241  Chain.getValue(1));
242 
243  // Extract values from a GPRPair reg and copy to the original GPR reg.
244  SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,
245  RegCopy);
246  SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
247  RegCopy);
248  SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
249  RegCopy.getValue(1));
250  SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
251 
252  // Update the original glue user.
253  std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
254  Ops.push_back(T1.getValue(1));
255  CurDAG->UpdateNodeOperands(GU, Ops);
256  }
257  else {
258  // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a
259  // GPRPair and then pass the GPRPair to the inline asm.
260  SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
261 
262  // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
263  SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
264  Chain.getValue(1));
265  SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
266  T0.getValue(1));
267  SDValue Pair = SDValue(
268  CurDAG->getMachineNode(
269  TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
270  {
271  CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
272  MVT::i32),
273  T0,
274  CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
275  T1,
276  CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
277  }),
278  0);
279 
280  // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
281  // i32 VRs of inline asm with it.
282  unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
283  PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
284  Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
285 
286  AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
287  Glue = Chain.getValue(1);
288  }
289 
290  Changed = true;
291 
292  if(PairedReg.getNode()) {
293  OpChanged[OpChanged.size() -1 ] = true;
294  Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
295  if (IsTiedToChangedOp)
296  Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
297  else
298  Flag = InlineAsm::getFlagWordForRegClass(Flag, SP::IntPairRegClassID);
299  // Replace the current flag.
300  AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
301  Flag, dl, MVT::i32);
302  // Add the new register node and skip the original two GPRs.
303  AsmNodeOperands.push_back(PairedReg);
304  // Skip the next two GPRs.
305  i += 2;
306  }
307  }
308 
309  if (Glue.getNode())
310  AsmNodeOperands.push_back(Glue);
311  if (!Changed)
312  return false;
313 
314  SelectInlineAsmMemoryOperands(AsmNodeOperands, SDLoc(N));
315 
316  SDValue New = CurDAG->getNode(ISD::INLINEASM, SDLoc(N),
317  CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
318  New->setNodeId(-1);
319  ReplaceNode(N, New.getNode());
320  return true;
321 }
322 
324  SDLoc dl(N);
325  if (N->isMachineOpcode()) {
326  N->setNodeId(-1);
327  return; // Already selected.
328  }
329 
330  switch (N->getOpcode()) {
331  default: break;
332  case ISD::INLINEASM: {
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:24
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:131
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:667
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:201
op_iterator op_begin() const
Flag
These should be considered private to the implementation of the MCInstrDesc class.
Definition: MCInstrDesc.h:118
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
static unsigned getKind(unsigned Flags)
Definition: InlineAsm.h:325
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:285
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:53
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:847
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
const unsigned Kind
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
const SDValue & getOperand(unsigned i) const
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation...
#define T1
unsigned createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
static unsigned getFlagWordForMatchingOp(unsigned InputFlag, unsigned MatchedOperandNo)
getFlagWordForMatchingOp - Augment an existing flag word returned by getFlagWord with information ind...
Definition: InlineAsm.h:288