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