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 "SparcTargetMachine.h" 15 #include "llvm/CodeGen/MachineRegisterInfo.h" 16 #include "llvm/CodeGen/SelectionDAGISel.h" 17 #include "llvm/IR/Intrinsics.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" 22 using 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 /// 32 namespace { 33 class 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 public: 38 explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {} 39 40 bool runOnMachineFunction(MachineFunction &MF) override { 41 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 42 return SelectionDAGISel::runOnMachineFunction(MF); 43 } 44 45 SDNode *Select(SDNode *N) override; 46 47 // Complex Pattern Selectors. 48 bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2); 49 bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset); 50 51 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 52 /// inline asm expressions. 53 bool SelectInlineAsmMemoryOperand(const SDValue &Op, 54 unsigned ConstraintID, 55 std::vector<SDValue> &OutOps) override; 56 57 const char *getPassName() const override { 58 return "SPARC DAG->DAG Pattern Instruction Selection"; 59 } 60 61 // Include the pieces autogenerated from the target description. 62 #include "SparcGenDAGISel.inc" 63 64 private: 65 SDNode* getGlobalBaseReg(); 66 SDNode *SelectInlineAsm(SDNode *N); 67 }; 68 } // end anonymous namespace 69 70 SDNode* SparcDAGToDAGISel::getGlobalBaseReg() { 71 unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF); 72 return CurDAG->getRegister(GlobalBaseReg, 73 TLI->getPointerTy(CurDAG->getDataLayout())) 74 .getNode(); 75 } 76 77 bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr, 78 SDValue &Base, SDValue &Offset) { 79 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 80 Base = CurDAG->getTargetFrameIndex( 81 FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout())); 82 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 83 return true; 84 } 85 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 86 Addr.getOpcode() == ISD::TargetGlobalAddress || 87 Addr.getOpcode() == ISD::TargetGlobalTLSAddress) 88 return false; // direct calls. 89 90 if (Addr.getOpcode() == ISD::ADD) { 91 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 92 if (isInt<13>(CN->getSExtValue())) { 93 if (FrameIndexSDNode *FIN = 94 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 95 // Constant offset from frame ref. 96 Base = CurDAG->getTargetFrameIndex( 97 FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout())); 98 } else { 99 Base = Addr.getOperand(0); 100 } 101 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), 102 MVT::i32); 103 return true; 104 } 105 } 106 if (Addr.getOperand(0).getOpcode() == SPISD::Lo) { 107 Base = Addr.getOperand(1); 108 Offset = Addr.getOperand(0).getOperand(0); 109 return true; 110 } 111 if (Addr.getOperand(1).getOpcode() == SPISD::Lo) { 112 Base = Addr.getOperand(0); 113 Offset = Addr.getOperand(1).getOperand(0); 114 return true; 115 } 116 } 117 Base = Addr; 118 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 119 return true; 120 } 121 122 bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) { 123 if (Addr.getOpcode() == ISD::FrameIndex) return false; 124 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 125 Addr.getOpcode() == ISD::TargetGlobalAddress || 126 Addr.getOpcode() == ISD::TargetGlobalTLSAddress) 127 return false; // direct calls. 128 129 if (Addr.getOpcode() == ISD::ADD) { 130 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) 131 if (isInt<13>(CN->getSExtValue())) 132 return false; // Let the reg+imm pattern catch this! 133 if (Addr.getOperand(0).getOpcode() == SPISD::Lo || 134 Addr.getOperand(1).getOpcode() == SPISD::Lo) 135 return false; // Let the reg+imm pattern catch this! 136 R1 = Addr.getOperand(0); 137 R2 = Addr.getOperand(1); 138 return true; 139 } 140 141 R1 = Addr; 142 R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout())); 143 return true; 144 } 145 146 147 // Re-assemble i64 arguments split up in SelectionDAGBuilder's 148 // visitInlineAsm / GetRegistersForValue functions. 149 // 150 // Note: This function was copied from, and is essentially identical 151 // to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that 152 // such hacking-up is necessary; a rethink of how inline asm operands 153 // are handled may be in order to make doing this more sane. 154 // 155 // TODO: fix inline asm support so I can simply tell it that 'i64' 156 // inputs to asm need to be allocated to the IntPair register type, 157 // and have that work. Then, delete this function. 158 SDNode *SparcDAGToDAGISel::SelectInlineAsm(SDNode *N){ 159 std::vector<SDValue> AsmNodeOperands; 160 unsigned Flag, Kind; 161 bool Changed = false; 162 unsigned NumOps = N->getNumOperands(); 163 164 // Normally, i64 data is bounded to two arbitrary GPRs for "%r" 165 // constraint. However, some instructions (e.g. ldd/std) require 166 // (even/even+1) GPRs. 167 168 // So, here, we check for this case, and mutate the inlineasm to use 169 // a single IntPair register instead, which guarantees such even/odd 170 // placement. 171 172 SDLoc dl(N); 173 SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps-1) 174 : SDValue(nullptr,0); 175 176 SmallVector<bool, 8> OpChanged; 177 // Glue node will be appended late. 178 for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) { 179 SDValue op = N->getOperand(i); 180 AsmNodeOperands.push_back(op); 181 182 if (i < InlineAsm::Op_FirstOperand) 183 continue; 184 185 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) { 186 Flag = C->getZExtValue(); 187 Kind = InlineAsm::getKind(Flag); 188 } 189 else 190 continue; 191 192 // Immediate operands to inline asm in the SelectionDAG are modeled with 193 // two operands. The first is a constant of value InlineAsm::Kind_Imm, and 194 // the second is a constant with the value of the immediate. If we get here 195 // and we have a Kind_Imm, skip the next operand, and continue. 196 if (Kind == InlineAsm::Kind_Imm) { 197 SDValue op = N->getOperand(++i); 198 AsmNodeOperands.push_back(op); 199 continue; 200 } 201 202 unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag); 203 if (NumRegs) 204 OpChanged.push_back(false); 205 206 unsigned DefIdx = 0; 207 bool IsTiedToChangedOp = false; 208 // If it's a use that is tied with a previous def, it has no 209 // reg class constraint. 210 if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx)) 211 IsTiedToChangedOp = OpChanged[DefIdx]; 212 213 if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef 214 && Kind != InlineAsm::Kind_RegDefEarlyClobber) 215 continue; 216 217 unsigned RC; 218 bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC); 219 if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID)) 220 || NumRegs != 2) 221 continue; 222 223 assert((i+2 < NumOps) && "Invalid number of operands in inline asm"); 224 SDValue V0 = N->getOperand(i+1); 225 SDValue V1 = N->getOperand(i+2); 226 unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg(); 227 unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg(); 228 SDValue PairedReg; 229 MachineRegisterInfo &MRI = MF->getRegInfo(); 230 231 if (Kind == InlineAsm::Kind_RegDef || 232 Kind == InlineAsm::Kind_RegDefEarlyClobber) { 233 // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to 234 // the original GPRs. 235 236 unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass); 237 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32); 238 SDValue Chain = SDValue(N,0); 239 240 SDNode *GU = N->getGluedUser(); 241 SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32, 242 Chain.getValue(1)); 243 244 // Extract values from a GPRPair reg and copy to the original GPR reg. 245 SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32, 246 RegCopy); 247 SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32, 248 RegCopy); 249 SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, 250 RegCopy.getValue(1)); 251 SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1)); 252 253 // Update the original glue user. 254 std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1); 255 Ops.push_back(T1.getValue(1)); 256 CurDAG->UpdateNodeOperands(GU, Ops); 257 } 258 else { 259 // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a 260 // GPRPair and then pass the GPRPair to the inline asm. 261 SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain]; 262 263 // As REG_SEQ doesn't take RegisterSDNode, we copy them first. 264 SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, 265 Chain.getValue(1)); 266 SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, 267 T0.getValue(1)); 268 SDValue Pair = SDValue( 269 CurDAG->getMachineNode( 270 TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32, 271 { 272 CurDAG->getTargetConstant(SP::IntPairRegClassID, dl, 273 MVT::i32), 274 T0, 275 CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32), 276 T1, 277 CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32), 278 }), 279 0); 280 281 // Copy REG_SEQ into a GPRPair-typed VR and replace the original two 282 // i32 VRs of inline asm with it. 283 unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass); 284 PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32); 285 Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1)); 286 287 AsmNodeOperands[InlineAsm::Op_InputChain] = Chain; 288 Glue = Chain.getValue(1); 289 } 290 291 Changed = true; 292 293 if(PairedReg.getNode()) { 294 OpChanged[OpChanged.size() -1 ] = true; 295 Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/); 296 if (IsTiedToChangedOp) 297 Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx); 298 else 299 Flag = InlineAsm::getFlagWordForRegClass(Flag, SP::IntPairRegClassID); 300 // Replace the current flag. 301 AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant( 302 Flag, dl, MVT::i32); 303 // Add the new register node and skip the original two GPRs. 304 AsmNodeOperands.push_back(PairedReg); 305 // Skip the next two GPRs. 306 i += 2; 307 } 308 } 309 310 if (Glue.getNode()) 311 AsmNodeOperands.push_back(Glue); 312 if (!Changed) 313 return nullptr; 314 315 SDValue New = CurDAG->getNode(ISD::INLINEASM, SDLoc(N), 316 CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands); 317 New->setNodeId(-1); 318 return New.getNode(); 319 } 320 321 SDNode *SparcDAGToDAGISel::Select(SDNode *N) { 322 SDLoc dl(N); 323 if (N->isMachineOpcode()) { 324 N->setNodeId(-1); 325 return nullptr; // Already selected. 326 } 327 328 switch (N->getOpcode()) { 329 default: break; 330 case ISD::INLINEASM: { 331 SDNode *ResNode = SelectInlineAsm(N); 332 if (ResNode) 333 return ResNode; 334 break; 335 } 336 case SPISD::GLOBAL_BASE_REG: 337 return getGlobalBaseReg(); 338 339 case ISD::SDIV: 340 case ISD::UDIV: { 341 // sdivx / udivx handle 64-bit divides. 342 if (N->getValueType(0) == MVT::i64) 343 break; 344 // FIXME: should use a custom expander to expose the SRA to the dag. 345 SDValue DivLHS = N->getOperand(0); 346 SDValue DivRHS = N->getOperand(1); 347 348 // Set the Y register to the high-part. 349 SDValue TopPart; 350 if (N->getOpcode() == ISD::SDIV) { 351 TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS, 352 CurDAG->getTargetConstant(31, dl, MVT::i32)), 353 0); 354 } else { 355 TopPart = CurDAG->getRegister(SP::G0, MVT::i32); 356 } 357 TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart, 358 SDValue()) 359 .getValue(1); 360 361 // FIXME: Handle div by immediate. 362 unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr; 363 return CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, 364 TopPart); 365 } 366 case ISD::MULHU: 367 case ISD::MULHS: { 368 // FIXME: Handle mul by immediate. 369 SDValue MulLHS = N->getOperand(0); 370 SDValue MulRHS = N->getOperand(1); 371 unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr; 372 SDNode *Mul = 373 CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32, MulLHS, MulRHS); 374 SDValue ResultHigh = SDValue(Mul, 1); 375 ReplaceUses(SDValue(N, 0), ResultHigh); 376 return nullptr; 377 } 378 } 379 380 return SelectCode(N); 381 } 382 383 384 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 385 /// inline asm expressions. 386 bool 387 SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op, 388 unsigned ConstraintID, 389 std::vector<SDValue> &OutOps) { 390 SDValue Op0, Op1; 391 switch (ConstraintID) { 392 default: return true; 393 case InlineAsm::Constraint_i: 394 case InlineAsm::Constraint_m: // memory 395 if (!SelectADDRrr(Op, Op0, Op1)) 396 SelectADDRri(Op, Op0, Op1); 397 break; 398 } 399 400 OutOps.push_back(Op0); 401 OutOps.push_back(Op1); 402 return false; 403 } 404 405 /// createSparcISelDag - This pass converts a legalized DAG into a 406 /// SPARC-specific DAG, ready for instruction scheduling. 407 /// 408 FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) { 409 return new SparcDAGToDAGISel(TM); 410 } 411