SparcISelDAGToDAG.cpp revision f5f5dce897269885754fc79adeb809194da52942
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 DebugLoc dl = N->getDebugLoc(); 145 if (N->isMachineOpcode()) 146 return NULL; // Already selected. 147 148 switch (N->getOpcode()) { 149 default: break; 150 case ISD::SDIV: 151 case ISD::UDIV: { 152 // FIXME: should use a custom expander to expose the SRA to the dag. 153 SDValue DivLHS = N->getOperand(0); 154 SDValue DivRHS = N->getOperand(1); 155 156 // Set the Y register to the high-part. 157 SDValue TopPart; 158 if (N->getOpcode() == ISD::SDIV) { 159 TopPart = SDValue(CurDAG->getTargetNode(SP::SRAri, dl, MVT::i32, DivLHS, 160 CurDAG->getTargetConstant(31, MVT::i32)), 0); 161 } else { 162 TopPart = CurDAG->getRegister(SP::G0, MVT::i32); 163 } 164 TopPart = SDValue(CurDAG->getTargetNode(SP::WRYrr, dl, MVT::Flag, TopPart, 165 CurDAG->getRegister(SP::G0, MVT::i32)), 0); 166 167 // FIXME: Handle div by immediate. 168 unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr; 169 return CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, 170 TopPart); 171 } 172 case ISD::MULHU: 173 case ISD::MULHS: { 174 // FIXME: Handle mul by immediate. 175 SDValue MulLHS = N->getOperand(0); 176 SDValue MulRHS = N->getOperand(1); 177 unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr; 178 SDNode *Mul = CurDAG->getTargetNode(Opcode, dl, MVT::i32, MVT::Flag, 179 MulLHS, MulRHS); 180 // The high part is in the Y register. 181 return CurDAG->SelectNodeTo(N, SP::RDY, MVT::i32, SDValue(Mul, 1)); 182 return NULL; 183 } 184 } 185 186 return SelectCode(Op); 187} 188 189 190/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 191/// inline asm expressions. 192bool 193SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op, 194 char ConstraintCode, 195 std::vector<SDValue> &OutOps) { 196 SDValue Op0, Op1; 197 switch (ConstraintCode) { 198 default: return true; 199 case 'm': // memory 200 if (!SelectADDRrr(Op, Op, Op0, Op1)) 201 SelectADDRri(Op, Op, Op0, Op1); 202 break; 203 } 204 205 OutOps.push_back(Op0); 206 OutOps.push_back(Op1); 207 return false; 208} 209 210/// createSparcISelDag - This pass converts a legalized DAG into a 211/// SPARC-specific DAG, ready for instruction scheduling. 212/// 213FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) { 214 return new SparcDAGToDAGISel(TM); 215} 216