LLVM  4.0.0
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,
77  SDValue &Base, SDValue &Offset) {
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  SDValue New = CurDAG->getNode(ISD::INLINEASM, SDLoc(N),
315  CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
316  New->setNodeId(-1);
317  ReplaceNode(N, New.getNode());
318  return true;
319 }
320 
322  SDLoc dl(N);
323  if (N->isMachineOpcode()) {
324  N->setNodeId(-1);
325  return; // Already selected.
326  }
327 
328  switch (N->getOpcode()) {
329  default: break;
330  case ISD::INLINEASM: {
331  if (tryInlineAsm(N))
332  return;
333  break;
334  }
336  ReplaceNode(N, getGlobalBaseReg());
337  return;
338 
339  case ISD::SDIV:
340  case ISD::UDIV: {
341  // sdivx / udivx handle 64-bit divides.
342  if (N->getValueType(0) == MVT::i64)
343  break;
344  // FIXME: should use a custom expander to expose the SRA to the dag.
345  SDValue DivLHS = N->getOperand(0);
346  SDValue DivRHS = N->getOperand(1);
347 
348  // Set the Y register to the high-part.
349  SDValue TopPart;
350  if (N->getOpcode() == ISD::SDIV) {
351  TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
352  CurDAG->getTargetConstant(31, dl, MVT::i32)),
353  0);
354  } else {
355  TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
356  }
357  TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
358  SDValue())
359  .getValue(1);
360 
361  // FIXME: Handle div by immediate.
362  unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
363  // SDIV is a hardware erratum on some LEON2 processors. Replace it with SDIVcc here.
364  if (((SparcTargetMachine&)TM).getSubtargetImpl()->performSDIVReplace()
365  &&
366  Opcode == SP::SDIVrr) {
367  Opcode = SP::SDIVCCrr;
368  }
369  CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);
370  return;
371  }
372  }
373 
374  SelectCode(N);
375 }
376 
377 
378 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
379 /// inline asm expressions.
380 bool
381 SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
382  unsigned ConstraintID,
383  std::vector<SDValue> &OutOps) {
384  SDValue Op0, Op1;
385  switch (ConstraintID) {
386  default: return true;
387  case InlineAsm::Constraint_i:
388  case InlineAsm::Constraint_o:
389  case InlineAsm::Constraint_m: // memory
390  if (!SelectADDRrr(Op, Op0, Op1))
391  SelectADDRri(Op, Op0, Op1);
392  break;
393  }
394 
395  OutOps.push_back(Op0);
396  OutOps.push_back(Op1);
397  return false;
398 }
399 
400 /// createSparcISelDag - This pass converts a legalized DAG into a
401 /// SPARC-specific DAG, ready for instruction scheduling.
402 ///
404  return new SparcDAGToDAGISel(TM);
405 }
SDValue getValue(unsigned R) const
size_t i
unsigned createVirtualRegister(const TargetRegisterClass *RegClass)
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
static unsigned getFlagWord(unsigned Kind, unsigned NumOps)
Definition: InlineAsm.h:268
SDNode * getGluedNode() const
If this node has a glue operand, return the node to which the glue operand points.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
Definition: ISDOpcodes.h:131
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
void setNodeId(int Id)
Set unique node id.
#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:341
GlobalBaseReg - On Darwin, this node represents the result of the mflr at function entry...
static unsigned getFlagWordForRegClass(unsigned InputFlag, unsigned RC)
getFlagWordForRegClass - Augment an existing flag word returned by getFlagWord with the required regi...
Definition: InlineAsm.h:299
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
INLINEASM - Represents an inline asm block.
Definition: ISDOpcodes.h:589
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
Flag
These should be considered private to the implementation of the MCInstrDesc class.
Definition: MCInstrDesc.h:121
SDNode * getNode() const
get the SDNode which holds the desired result
unsigned const MachineRegisterInfo * MRI
const SDValue & getOperand(unsigned i) const
static unsigned getNumOperandRegisters(unsigned Flag)
getNumOperandRegisters - Extract the number of registers field from the inline asm operand flag...
Definition: InlineAsm.h:335
uint32_t Offset
unsigned getOpcode() const
static unsigned getKind(unsigned Flags)
Definition: InlineAsm.h:324
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:298
FunctionPass * createSparcISelDag(SparcTargetMachine &TM)
createSparcISelDag - This pass converts a legalized DAG into a SPARC-specific DAG, ready for instruction scheduling.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:843
SDNode * getGluedUser() const
If this node has a glue value with a user, return the user (there is at most one).
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 GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
static unsigned getReg(const void *D, unsigned RC, unsigned RegNo)
op_iterator op_begin() const
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:350
#define N
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
Definition: SmallVector.h:135
op_iterator op_end() const
const unsigned Kind
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml","ocaml 3.10-compatible collector")
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation...
#define T1
static unsigned getFlagWordForMatchingOp(unsigned InputFlag, unsigned MatchedOperandNo)
getFlagWordForMatchingOp - Augment an existing flag word returned by getFlagWord with information ind...
Definition: InlineAsm.h:287
bool isMachineOpcode() const
Test if this node has a post-isel opcode, directly corresponding to a MachineInstr opcode...