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