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