SparcISelDAGToDAG.cpp revision e50ed30282bb5b4a9ed952580523f2dda16215ac
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 "SparcISelLowering.h"
15#include "SparcTargetMachine.h"
16#include "llvm/Intrinsics.h"
17#include "llvm/CodeGen/SelectionDAGISel.h"
18#include "llvm/Support/Compiler.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/ErrorHandling.h"
21#include "llvm/Support/raw_ostream.h"
22using namespace llvm;
23
24//===----------------------------------------------------------------------===//
25// Instruction Selector Implementation
26//===----------------------------------------------------------------------===//
27
28//===--------------------------------------------------------------------===//
29/// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
30/// instructions for SelectionDAG operations.
31///
32namespace {
33class SparcDAGToDAGISel : public SelectionDAGISel {
34  /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
35  /// make the right decision when generating code for different targets.
36  const SparcSubtarget &Subtarget;
37public:
38  explicit SparcDAGToDAGISel(SparcTargetMachine &TM)
39    : SelectionDAGISel(TM),
40      Subtarget(TM.getSubtarget<SparcSubtarget>()) {
41  }
42
43  SDNode *Select(SDValue Op);
44
45  // Complex Pattern Selectors.
46  bool SelectADDRrr(SDValue Op, SDValue N, SDValue &R1, SDValue &R2);
47  bool SelectADDRri(SDValue Op, SDValue N, SDValue &Base,
48                    SDValue &Offset);
49
50  /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
51  /// inline asm expressions.
52  virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
53                                            char ConstraintCode,
54                                            std::vector<SDValue> &OutOps);
55
56  /// InstructionSelect - This callback is invoked by
57  /// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
58  virtual void InstructionSelect();
59
60  virtual const char *getPassName() const {
61    return "SPARC DAG->DAG Pattern Instruction Selection";
62  }
63
64  // Include the pieces autogenerated from the target description.
65#include "SparcGenDAGISel.inc"
66};
67}  // end anonymous namespace
68
69/// InstructionSelect - This callback is invoked by
70/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
71void SparcDAGToDAGISel::InstructionSelect() {
72  DEBUG(BB->dump());
73
74  // Select target instructions for the DAG.
75  SelectRoot(*CurDAG);
76  CurDAG->RemoveDeadNodes();
77}
78
79bool SparcDAGToDAGISel::SelectADDRri(SDValue Op, SDValue Addr,
80                                     SDValue &Base, SDValue &Offset) {
81  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
82    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), EVT::i32);
83    Offset = CurDAG->getTargetConstant(0, EVT::i32);
84    return true;
85  }
86  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
87      Addr.getOpcode() == ISD::TargetGlobalAddress)
88    return false;  // direct calls.
89
90  if (Addr.getOpcode() == ISD::ADD) {
91    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
92      if (Predicate_simm13(CN)) {
93        if (FrameIndexSDNode *FIN =
94                dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
95          // Constant offset from frame ref.
96          Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), EVT::i32);
97        } else {
98          Base = Addr.getOperand(0);
99        }
100        Offset = CurDAG->getTargetConstant(CN->getZExtValue(), EVT::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, EVT::i32);
117  return true;
118}
119
120bool SparcDAGToDAGISel::SelectADDRrr(SDValue Op, SDValue Addr,
121                                     SDValue &R1,  SDValue &R2) {
122  if (Addr.getOpcode() == ISD::FrameIndex) return false;
123  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
124      Addr.getOpcode() == ISD::TargetGlobalAddress)
125    return false;  // direct calls.
126
127  if (Addr.getOpcode() == ISD::ADD) {
128    if (isa<ConstantSDNode>(Addr.getOperand(1)) &&
129        Predicate_simm13(Addr.getOperand(1).getNode()))
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, EVT::i32);
141  return true;
142}
143
144SDNode *SparcDAGToDAGISel::Select(SDValue Op) {
145  SDNode *N = Op.getNode();
146  DebugLoc dl = N->getDebugLoc();
147  if (N->isMachineOpcode())
148    return NULL;   // Already selected.
149
150  switch (N->getOpcode()) {
151  default: break;
152  case ISD::SDIV:
153  case ISD::UDIV: {
154    // FIXME: should use a custom expander to expose the SRA to the dag.
155    SDValue DivLHS = N->getOperand(0);
156    SDValue DivRHS = N->getOperand(1);
157
158    // Set the Y register to the high-part.
159    SDValue TopPart;
160    if (N->getOpcode() == ISD::SDIV) {
161      TopPart = SDValue(CurDAG->getTargetNode(SP::SRAri, dl, EVT::i32, DivLHS,
162                                   CurDAG->getTargetConstant(31, EVT::i32)), 0);
163    } else {
164      TopPart = CurDAG->getRegister(SP::G0, EVT::i32);
165    }
166    TopPart = SDValue(CurDAG->getTargetNode(SP::WRYrr, dl, EVT::Flag, TopPart,
167                                     CurDAG->getRegister(SP::G0, EVT::i32)), 0);
168
169    // FIXME: Handle div by immediate.
170    unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
171    return CurDAG->SelectNodeTo(N, Opcode, EVT::i32, DivLHS, DivRHS,
172                                TopPart);
173  }
174  case ISD::MULHU:
175  case ISD::MULHS: {
176    // FIXME: Handle mul by immediate.
177    SDValue MulLHS = N->getOperand(0);
178    SDValue MulRHS = N->getOperand(1);
179    unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr;
180    SDNode *Mul = CurDAG->getTargetNode(Opcode, dl, EVT::i32, EVT::Flag,
181                                        MulLHS, MulRHS);
182    // The high part is in the Y register.
183    return CurDAG->SelectNodeTo(N, SP::RDY, EVT::i32, SDValue(Mul, 1));
184    return NULL;
185  }
186  }
187
188  return SelectCode(Op);
189}
190
191
192/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
193/// inline asm expressions.
194bool
195SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
196                                                char ConstraintCode,
197                                                std::vector<SDValue> &OutOps) {
198  SDValue Op0, Op1;
199  switch (ConstraintCode) {
200  default: return true;
201  case 'm':   // memory
202   if (!SelectADDRrr(Op, Op, Op0, Op1))
203     SelectADDRri(Op, Op, Op0, Op1);
204   break;
205  }
206
207  OutOps.push_back(Op0);
208  OutOps.push_back(Op1);
209  return false;
210}
211
212/// createSparcISelDag - This pass converts a legalized DAG into a
213/// SPARC-specific DAG, ready for instruction scheduling.
214///
215FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
216  return new SparcDAGToDAGISel(TM);
217}
218