1 //===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines an instruction selector for the SPARC target.
12 //===----------------------------------------------------------------------===//
14 #include "SparcTargetMachine.h"
15 #include "llvm/Intrinsics.h"
16 #include "llvm/CodeGen/SelectionDAGISel.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include "llvm/Support/raw_ostream.h"
23 //===----------------------------------------------------------------------===//
24 // Instruction Selector Implementation
25 //===----------------------------------------------------------------------===//
27 //===--------------------------------------------------------------------===//
28 /// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
29 /// instructions for SelectionDAG operations.
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 SparcTargetMachine
& TM
;
38 explicit SparcDAGToDAGISel(SparcTargetMachine
&tm
)
39 : SelectionDAGISel(tm
),
40 Subtarget(tm
.getSubtarget
<SparcSubtarget
>()),
44 SDNode
*Select(SDNode
*N
);
46 // Complex Pattern Selectors.
47 bool SelectADDRrr(SDValue N
, SDValue
&R1
, SDValue
&R2
);
48 bool SelectADDRri(SDValue N
, SDValue
&Base
, SDValue
&Offset
);
50 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
51 /// inline asm expressions.
52 virtual bool SelectInlineAsmMemoryOperand(const SDValue
&Op
,
54 std::vector
<SDValue
> &OutOps
);
56 virtual const char *getPassName() const {
57 return "SPARC DAG->DAG Pattern Instruction Selection";
60 // Include the pieces autogenerated from the target description.
61 #include "SparcGenDAGISel.inc"
64 SDNode
* getGlobalBaseReg();
66 } // end anonymous namespace
68 SDNode
* SparcDAGToDAGISel::getGlobalBaseReg() {
69 unsigned GlobalBaseReg
= TM
.getInstrInfo()->getGlobalBaseReg(MF
);
70 return CurDAG
->getRegister(GlobalBaseReg
, TLI
.getPointerTy()).getNode();
73 bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr
,
74 SDValue
&Base
, SDValue
&Offset
) {
75 if (FrameIndexSDNode
*FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
)) {
76 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), MVT::i32
);
77 Offset
= CurDAG
->getTargetConstant(0, MVT::i32
);
80 if (Addr
.getOpcode() == ISD::TargetExternalSymbol
||
81 Addr
.getOpcode() == ISD::TargetGlobalAddress
)
82 return false; // direct calls.
84 if (Addr
.getOpcode() == ISD::ADD
) {
85 if (ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Addr
.getOperand(1))) {
86 if (isInt
<13>(CN
->getSExtValue())) {
87 if (FrameIndexSDNode
*FIN
=
88 dyn_cast
<FrameIndexSDNode
>(Addr
.getOperand(0))) {
89 // Constant offset from frame ref.
90 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), MVT::i32
);
92 Base
= Addr
.getOperand(0);
94 Offset
= CurDAG
->getTargetConstant(CN
->getZExtValue(), MVT::i32
);
98 if (Addr
.getOperand(0).getOpcode() == SPISD::Lo
) {
99 Base
= Addr
.getOperand(1);
100 Offset
= Addr
.getOperand(0).getOperand(0);
103 if (Addr
.getOperand(1).getOpcode() == SPISD::Lo
) {
104 Base
= Addr
.getOperand(0);
105 Offset
= Addr
.getOperand(1).getOperand(0);
110 Offset
= CurDAG
->getTargetConstant(0, MVT::i32
);
114 bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr
, SDValue
&R1
, SDValue
&R2
) {
115 if (Addr
.getOpcode() == ISD::FrameIndex
) return false;
116 if (Addr
.getOpcode() == ISD::TargetExternalSymbol
||
117 Addr
.getOpcode() == ISD::TargetGlobalAddress
)
118 return false; // direct calls.
120 if (Addr
.getOpcode() == ISD::ADD
) {
121 if (ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Addr
.getOperand(1)))
122 if (isInt
<13>(CN
->getSExtValue()))
123 return false; // Let the reg+imm pattern catch this!
124 if (Addr
.getOperand(0).getOpcode() == SPISD::Lo
||
125 Addr
.getOperand(1).getOpcode() == SPISD::Lo
)
126 return false; // Let the reg+imm pattern catch this!
127 R1
= Addr
.getOperand(0);
128 R2
= Addr
.getOperand(1);
133 R2
= CurDAG
->getRegister(SP::G0
, MVT::i32
);
137 SDNode
*SparcDAGToDAGISel::Select(SDNode
*N
) {
138 DebugLoc dl
= N
->getDebugLoc();
139 if (N
->isMachineOpcode())
140 return NULL
; // Already selected.
142 switch (N
->getOpcode()) {
144 case SPISD::GLOBAL_BASE_REG
:
145 return getGlobalBaseReg();
149 // FIXME: should use a custom expander to expose the SRA to the dag.
150 SDValue DivLHS
= N
->getOperand(0);
151 SDValue DivRHS
= N
->getOperand(1);
153 // Set the Y register to the high-part.
155 if (N
->getOpcode() == ISD::SDIV
) {
156 TopPart
= SDValue(CurDAG
->getMachineNode(SP::SRAri
, dl
, MVT::i32
, DivLHS
,
157 CurDAG
->getTargetConstant(31, MVT::i32
)), 0);
159 TopPart
= CurDAG
->getRegister(SP::G0
, MVT::i32
);
161 TopPart
= SDValue(CurDAG
->getMachineNode(SP::WRYrr
, dl
, MVT::Flag
, TopPart
,
162 CurDAG
->getRegister(SP::G0
, MVT::i32
)), 0);
164 // FIXME: Handle div by immediate.
165 unsigned Opcode
= N
->getOpcode() == ISD::SDIV
? SP::SDIVrr
: SP::UDIVrr
;
166 return CurDAG
->SelectNodeTo(N
, Opcode
, MVT::i32
, DivLHS
, DivRHS
,
171 // FIXME: Handle mul by immediate.
172 SDValue MulLHS
= N
->getOperand(0);
173 SDValue MulRHS
= N
->getOperand(1);
174 unsigned Opcode
= N
->getOpcode() == ISD::MULHU
? SP::UMULrr
: SP::SMULrr
;
175 SDNode
*Mul
= CurDAG
->getMachineNode(Opcode
, dl
, MVT::i32
, MVT::Flag
,
177 // The high part is in the Y register.
178 return CurDAG
->SelectNodeTo(N
, SP::RDY
, MVT::i32
, SDValue(Mul
, 1));
183 return SelectCode(N
);
187 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
188 /// inline asm expressions.
190 SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue
&Op
,
192 std::vector
<SDValue
> &OutOps
) {
194 switch (ConstraintCode
) {
195 default: return true;
197 if (!SelectADDRrr(Op
, Op0
, Op1
))
198 SelectADDRri(Op
, Op0
, Op1
);
202 OutOps
.push_back(Op0
);
203 OutOps
.push_back(Op1
);
207 /// createSparcISelDag - This pass converts a legalized DAG into a
208 /// SPARC-specific DAG, ready for instruction scheduling.
210 FunctionPass
*llvm::createSparcISelDag(SparcTargetMachine
&TM
) {
211 return new SparcDAGToDAGISel(TM
);