1 //===- SPIRVInstructionSelector.cpp ------------------------------*- C++ -*-==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the targeting of the InstructionSelector class for 10 // SPIRV. 11 // TODO: This should be generated by TableGen. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "SPIRV.h" 16 #include "SPIRVGlobalRegistry.h" 17 #include "SPIRVInstrInfo.h" 18 #include "SPIRVRegisterBankInfo.h" 19 #include "SPIRVRegisterInfo.h" 20 #include "SPIRVTargetMachine.h" 21 #include "SPIRVUtils.h" 22 #include "llvm/ADT/APFloat.h" 23 #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" 24 #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" 25 #include "llvm/CodeGen/MachineInstrBuilder.h" 26 #include "llvm/CodeGen/MachineRegisterInfo.h" 27 #include "llvm/Support/Debug.h" 28 29 #define DEBUG_TYPE "spirv-isel" 30 31 using namespace llvm; 32 33 namespace { 34 35 #define GET_GLOBALISEL_PREDICATE_BITSET 36 #include "SPIRVGenGlobalISel.inc" 37 #undef GET_GLOBALISEL_PREDICATE_BITSET 38 39 class SPIRVInstructionSelector : public InstructionSelector { 40 const SPIRVSubtarget &STI; 41 const SPIRVInstrInfo &TII; 42 const SPIRVRegisterInfo &TRI; 43 const RegisterBankInfo &RBI; 44 SPIRVGlobalRegistry &GR; 45 MachineRegisterInfo *MRI; 46 47 public: 48 SPIRVInstructionSelector(const SPIRVTargetMachine &TM, 49 const SPIRVSubtarget &ST, 50 const RegisterBankInfo &RBI); 51 void setupMF(MachineFunction &MF, GISelKnownBits *KB, 52 CodeGenCoverage &CoverageInfo, ProfileSummaryInfo *PSI, 53 BlockFrequencyInfo *BFI) override; 54 // Common selection code. Instruction-specific selection occurs in spvSelect. 55 bool select(MachineInstr &I) override; 56 static const char *getName() { return DEBUG_TYPE; } 57 58 #define GET_GLOBALISEL_PREDICATES_DECL 59 #include "SPIRVGenGlobalISel.inc" 60 #undef GET_GLOBALISEL_PREDICATES_DECL 61 62 #define GET_GLOBALISEL_TEMPORARIES_DECL 63 #include "SPIRVGenGlobalISel.inc" 64 #undef GET_GLOBALISEL_TEMPORARIES_DECL 65 66 private: 67 // tblgen-erated 'select' implementation, used as the initial selector for 68 // the patterns that don't require complex C++. 69 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; 70 71 // All instruction-specific selection that didn't happen in "select()". 72 // Is basically a large Switch/Case delegating to all other select method. 73 bool spvSelect(Register ResVReg, const SPIRVType *ResType, 74 MachineInstr &I) const; 75 76 bool selectGlobalValue(Register ResVReg, MachineInstr &I, 77 const MachineInstr *Init = nullptr) const; 78 79 bool selectUnOpWithSrc(Register ResVReg, const SPIRVType *ResType, 80 MachineInstr &I, Register SrcReg, 81 unsigned Opcode) const; 82 bool selectUnOp(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 83 unsigned Opcode) const; 84 85 bool selectLoad(Register ResVReg, const SPIRVType *ResType, 86 MachineInstr &I) const; 87 bool selectStore(MachineInstr &I) const; 88 89 bool selectMemOperation(Register ResVReg, MachineInstr &I) const; 90 91 bool selectAtomicRMW(Register ResVReg, const SPIRVType *ResType, 92 MachineInstr &I, unsigned NewOpcode) const; 93 94 bool selectAtomicCmpXchg(Register ResVReg, const SPIRVType *ResType, 95 MachineInstr &I) const; 96 97 bool selectFence(MachineInstr &I) const; 98 99 bool selectAddrSpaceCast(Register ResVReg, const SPIRVType *ResType, 100 MachineInstr &I) const; 101 102 bool selectBitreverse(Register ResVReg, const SPIRVType *ResType, 103 MachineInstr &I) const; 104 105 bool selectConstVector(Register ResVReg, const SPIRVType *ResType, 106 MachineInstr &I) const; 107 108 bool selectCmp(Register ResVReg, const SPIRVType *ResType, 109 unsigned comparisonOpcode, MachineInstr &I) const; 110 111 bool selectICmp(Register ResVReg, const SPIRVType *ResType, 112 MachineInstr &I) const; 113 bool selectFCmp(Register ResVReg, const SPIRVType *ResType, 114 MachineInstr &I) const; 115 116 void renderImm32(MachineInstrBuilder &MIB, const MachineInstr &I, 117 int OpIdx) const; 118 void renderFImm32(MachineInstrBuilder &MIB, const MachineInstr &I, 119 int OpIdx) const; 120 121 bool selectConst(Register ResVReg, const SPIRVType *ResType, const APInt &Imm, 122 MachineInstr &I) const; 123 124 bool selectSelect(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 125 bool IsSigned) const; 126 bool selectIToF(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 127 bool IsSigned, unsigned Opcode) const; 128 bool selectExt(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 129 bool IsSigned) const; 130 131 bool selectTrunc(Register ResVReg, const SPIRVType *ResType, 132 MachineInstr &I) const; 133 134 bool selectIntToBool(Register IntReg, Register ResVReg, 135 const SPIRVType *intTy, const SPIRVType *boolTy, 136 MachineInstr &I) const; 137 138 bool selectOpUndef(Register ResVReg, const SPIRVType *ResType, 139 MachineInstr &I) const; 140 bool selectIntrinsic(Register ResVReg, const SPIRVType *ResType, 141 MachineInstr &I) const; 142 143 bool selectFrameIndex(Register ResVReg, const SPIRVType *ResType, 144 MachineInstr &I) const; 145 146 bool selectBranch(MachineInstr &I) const; 147 bool selectBranchCond(MachineInstr &I) const; 148 149 bool selectPhi(Register ResVReg, const SPIRVType *ResType, 150 MachineInstr &I) const; 151 152 Register buildI32Constant(uint32_t Val, MachineInstr &I, 153 const SPIRVType *ResType = nullptr) const; 154 155 Register buildZerosVal(const SPIRVType *ResType, MachineInstr &I) const; 156 Register buildOnesVal(bool AllOnes, const SPIRVType *ResType, 157 MachineInstr &I) const; 158 }; 159 160 } // end anonymous namespace 161 162 #define GET_GLOBALISEL_IMPL 163 #include "SPIRVGenGlobalISel.inc" 164 #undef GET_GLOBALISEL_IMPL 165 166 SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM, 167 const SPIRVSubtarget &ST, 168 const RegisterBankInfo &RBI) 169 : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()), 170 TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()), 171 #define GET_GLOBALISEL_PREDICATES_INIT 172 #include "SPIRVGenGlobalISel.inc" 173 #undef GET_GLOBALISEL_PREDICATES_INIT 174 #define GET_GLOBALISEL_TEMPORARIES_INIT 175 #include "SPIRVGenGlobalISel.inc" 176 #undef GET_GLOBALISEL_TEMPORARIES_INIT 177 { 178 } 179 180 void SPIRVInstructionSelector::setupMF(MachineFunction &MF, GISelKnownBits *KB, 181 CodeGenCoverage &CoverageInfo, 182 ProfileSummaryInfo *PSI, 183 BlockFrequencyInfo *BFI) { 184 MRI = &MF.getRegInfo(); 185 GR.setCurrentFunc(MF); 186 InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI); 187 } 188 189 // Defined in SPIRVLegalizerInfo.cpp. 190 extern bool isTypeFoldingSupported(unsigned Opcode); 191 192 bool SPIRVInstructionSelector::select(MachineInstr &I) { 193 assert(I.getParent() && "Instruction should be in a basic block!"); 194 assert(I.getParent()->getParent() && "Instruction should be in a function!"); 195 196 Register Opcode = I.getOpcode(); 197 // If it's not a GMIR instruction, we've selected it already. 198 if (!isPreISelGenericOpcode(Opcode)) { 199 if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more. 200 auto *Def = MRI->getVRegDef(I.getOperand(1).getReg()); 201 if (isTypeFoldingSupported(Def->getOpcode())) { 202 auto Res = selectImpl(I, *CoverageInfo); 203 assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT); 204 if (Res) 205 return Res; 206 } 207 MRI->replaceRegWith(I.getOperand(1).getReg(), I.getOperand(0).getReg()); 208 I.removeFromParent(); 209 } else if (I.getNumDefs() == 1) { 210 // Make all vregs 32 bits (for SPIR-V IDs). 211 MRI->setType(I.getOperand(0).getReg(), LLT::scalar(32)); 212 } 213 return true; 214 } 215 216 if (I.getNumOperands() != I.getNumExplicitOperands()) { 217 LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n"); 218 return false; 219 } 220 221 // Common code for getting return reg+type, and removing selected instr 222 // from parent occurs here. Instr-specific selection happens in spvSelect(). 223 bool HasDefs = I.getNumDefs() > 0; 224 Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0); 225 SPIRVType *ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr; 226 assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE); 227 if (spvSelect(ResVReg, ResType, I)) { 228 if (HasDefs) // Make all vregs 32 bits (for SPIR-V IDs). 229 MRI->setType(ResVReg, LLT::scalar(32)); 230 I.removeFromParent(); 231 return true; 232 } 233 return false; 234 } 235 236 bool SPIRVInstructionSelector::spvSelect(Register ResVReg, 237 const SPIRVType *ResType, 238 MachineInstr &I) const { 239 assert(!isTypeFoldingSupported(I.getOpcode()) || 240 I.getOpcode() == TargetOpcode::G_CONSTANT); 241 const unsigned Opcode = I.getOpcode(); 242 switch (Opcode) { 243 case TargetOpcode::G_CONSTANT: 244 return selectConst(ResVReg, ResType, I.getOperand(1).getCImm()->getValue(), 245 I); 246 case TargetOpcode::G_GLOBAL_VALUE: 247 return selectGlobalValue(ResVReg, I); 248 case TargetOpcode::G_IMPLICIT_DEF: 249 return selectOpUndef(ResVReg, ResType, I); 250 251 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 252 return selectIntrinsic(ResVReg, ResType, I); 253 case TargetOpcode::G_BITREVERSE: 254 return selectBitreverse(ResVReg, ResType, I); 255 256 case TargetOpcode::G_BUILD_VECTOR: 257 return selectConstVector(ResVReg, ResType, I); 258 259 case TargetOpcode::G_SHUFFLE_VECTOR: { 260 MachineBasicBlock &BB = *I.getParent(); 261 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle)) 262 .addDef(ResVReg) 263 .addUse(GR.getSPIRVTypeID(ResType)) 264 .addUse(I.getOperand(1).getReg()) 265 .addUse(I.getOperand(2).getReg()); 266 for (auto V : I.getOperand(3).getShuffleMask()) 267 MIB.addImm(V); 268 return MIB.constrainAllUses(TII, TRI, RBI); 269 } 270 case TargetOpcode::G_MEMMOVE: 271 case TargetOpcode::G_MEMCPY: 272 return selectMemOperation(ResVReg, I); 273 274 case TargetOpcode::G_ICMP: 275 return selectICmp(ResVReg, ResType, I); 276 case TargetOpcode::G_FCMP: 277 return selectFCmp(ResVReg, ResType, I); 278 279 case TargetOpcode::G_FRAME_INDEX: 280 return selectFrameIndex(ResVReg, ResType, I); 281 282 case TargetOpcode::G_LOAD: 283 return selectLoad(ResVReg, ResType, I); 284 case TargetOpcode::G_STORE: 285 return selectStore(I); 286 287 case TargetOpcode::G_BR: 288 return selectBranch(I); 289 case TargetOpcode::G_BRCOND: 290 return selectBranchCond(I); 291 292 case TargetOpcode::G_PHI: 293 return selectPhi(ResVReg, ResType, I); 294 295 case TargetOpcode::G_FPTOSI: 296 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS); 297 case TargetOpcode::G_FPTOUI: 298 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU); 299 300 case TargetOpcode::G_SITOFP: 301 return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF); 302 case TargetOpcode::G_UITOFP: 303 return selectIToF(ResVReg, ResType, I, false, SPIRV::OpConvertUToF); 304 305 case TargetOpcode::G_CTPOP: 306 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitCount); 307 308 case TargetOpcode::G_SEXT: 309 return selectExt(ResVReg, ResType, I, true); 310 case TargetOpcode::G_ANYEXT: 311 case TargetOpcode::G_ZEXT: 312 return selectExt(ResVReg, ResType, I, false); 313 case TargetOpcode::G_TRUNC: 314 return selectTrunc(ResVReg, ResType, I); 315 case TargetOpcode::G_FPTRUNC: 316 case TargetOpcode::G_FPEXT: 317 return selectUnOp(ResVReg, ResType, I, SPIRV::OpFConvert); 318 319 case TargetOpcode::G_PTRTOINT: 320 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertPtrToU); 321 case TargetOpcode::G_INTTOPTR: 322 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertUToPtr); 323 case TargetOpcode::G_BITCAST: 324 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast); 325 case TargetOpcode::G_ADDRSPACE_CAST: 326 return selectAddrSpaceCast(ResVReg, ResType, I); 327 328 case TargetOpcode::G_ATOMICRMW_OR: 329 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicOr); 330 case TargetOpcode::G_ATOMICRMW_ADD: 331 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicIAdd); 332 case TargetOpcode::G_ATOMICRMW_AND: 333 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicAnd); 334 case TargetOpcode::G_ATOMICRMW_MAX: 335 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMax); 336 case TargetOpcode::G_ATOMICRMW_MIN: 337 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMin); 338 case TargetOpcode::G_ATOMICRMW_SUB: 339 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicISub); 340 case TargetOpcode::G_ATOMICRMW_XOR: 341 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicXor); 342 case TargetOpcode::G_ATOMICRMW_UMAX: 343 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMax); 344 case TargetOpcode::G_ATOMICRMW_UMIN: 345 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMin); 346 case TargetOpcode::G_ATOMICRMW_XCHG: 347 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicExchange); 348 case TargetOpcode::G_ATOMIC_CMPXCHG: 349 return selectAtomicCmpXchg(ResVReg, ResType, I); 350 351 case TargetOpcode::G_FENCE: 352 return selectFence(I); 353 354 default: 355 return false; 356 } 357 } 358 359 bool SPIRVInstructionSelector::selectUnOpWithSrc(Register ResVReg, 360 const SPIRVType *ResType, 361 MachineInstr &I, 362 Register SrcReg, 363 unsigned Opcode) const { 364 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) 365 .addDef(ResVReg) 366 .addUse(GR.getSPIRVTypeID(ResType)) 367 .addUse(SrcReg) 368 .constrainAllUses(TII, TRI, RBI); 369 } 370 371 bool SPIRVInstructionSelector::selectUnOp(Register ResVReg, 372 const SPIRVType *ResType, 373 MachineInstr &I, 374 unsigned Opcode) const { 375 return selectUnOpWithSrc(ResVReg, ResType, I, I.getOperand(1).getReg(), 376 Opcode); 377 } 378 379 static SPIRV::MemorySemantics getMemSemantics(AtomicOrdering Ord) { 380 switch (Ord) { 381 case AtomicOrdering::Acquire: 382 return SPIRV::MemorySemantics::Acquire; 383 case AtomicOrdering::Release: 384 return SPIRV::MemorySemantics::Release; 385 case AtomicOrdering::AcquireRelease: 386 return SPIRV::MemorySemantics::AcquireRelease; 387 case AtomicOrdering::SequentiallyConsistent: 388 return SPIRV::MemorySemantics::SequentiallyConsistent; 389 case AtomicOrdering::Unordered: 390 case AtomicOrdering::Monotonic: 391 case AtomicOrdering::NotAtomic: 392 return SPIRV::MemorySemantics::None; 393 } 394 } 395 396 static SPIRV::Scope getScope(SyncScope::ID Ord) { 397 switch (Ord) { 398 case SyncScope::SingleThread: 399 return SPIRV::Scope::Invocation; 400 case SyncScope::System: 401 return SPIRV::Scope::Device; 402 default: 403 llvm_unreachable("Unsupported synchronization Scope ID."); 404 } 405 } 406 407 static void addMemoryOperands(MachineMemOperand *MemOp, 408 MachineInstrBuilder &MIB) { 409 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None); 410 if (MemOp->isVolatile()) 411 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile); 412 if (MemOp->isNonTemporal()) 413 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal); 414 if (MemOp->getAlign().value()) 415 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned); 416 417 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) { 418 MIB.addImm(SpvMemOp); 419 if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned)) 420 MIB.addImm(MemOp->getAlign().value()); 421 } 422 } 423 424 static void addMemoryOperands(uint64_t Flags, MachineInstrBuilder &MIB) { 425 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None); 426 if (Flags & MachineMemOperand::Flags::MOVolatile) 427 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile); 428 if (Flags & MachineMemOperand::Flags::MONonTemporal) 429 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal); 430 431 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) 432 MIB.addImm(SpvMemOp); 433 } 434 435 bool SPIRVInstructionSelector::selectLoad(Register ResVReg, 436 const SPIRVType *ResType, 437 MachineInstr &I) const { 438 unsigned OpOffset = 439 I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ? 1 : 0; 440 Register Ptr = I.getOperand(1 + OpOffset).getReg(); 441 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad)) 442 .addDef(ResVReg) 443 .addUse(GR.getSPIRVTypeID(ResType)) 444 .addUse(Ptr); 445 if (!I.getNumMemOperands()) { 446 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS); 447 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB); 448 } else { 449 addMemoryOperands(*I.memoperands_begin(), MIB); 450 } 451 return MIB.constrainAllUses(TII, TRI, RBI); 452 } 453 454 bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const { 455 unsigned OpOffset = 456 I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ? 1 : 0; 457 Register StoreVal = I.getOperand(0 + OpOffset).getReg(); 458 Register Ptr = I.getOperand(1 + OpOffset).getReg(); 459 MachineBasicBlock &BB = *I.getParent(); 460 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore)) 461 .addUse(Ptr) 462 .addUse(StoreVal); 463 if (!I.getNumMemOperands()) { 464 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS); 465 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB); 466 } else { 467 addMemoryOperands(*I.memoperands_begin(), MIB); 468 } 469 return MIB.constrainAllUses(TII, TRI, RBI); 470 } 471 472 bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg, 473 MachineInstr &I) const { 474 MachineBasicBlock &BB = *I.getParent(); 475 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized)) 476 .addDef(I.getOperand(0).getReg()) 477 .addUse(I.getOperand(1).getReg()) 478 .addUse(I.getOperand(2).getReg()); 479 if (I.getNumMemOperands()) 480 addMemoryOperands(*I.memoperands_begin(), MIB); 481 bool Result = MIB.constrainAllUses(TII, TRI, RBI); 482 if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg()) { 483 BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), ResVReg) 484 .addUse(MIB->getOperand(0).getReg()); 485 } 486 return Result; 487 } 488 489 bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg, 490 const SPIRVType *ResType, 491 MachineInstr &I, 492 unsigned NewOpcode) const { 493 assert(I.hasOneMemOperand()); 494 const MachineMemOperand *MemOp = *I.memoperands_begin(); 495 uint32_t Scope = static_cast<uint32_t>(getScope(MemOp->getSyncScopeID())); 496 Register ScopeReg = buildI32Constant(Scope, I); 497 498 Register Ptr = I.getOperand(1).getReg(); 499 // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll 500 // auto ScSem = 501 // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr)); 502 AtomicOrdering AO = MemOp->getSuccessOrdering(); 503 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)); 504 Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I); 505 506 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode)) 507 .addDef(ResVReg) 508 .addUse(GR.getSPIRVTypeID(ResType)) 509 .addUse(Ptr) 510 .addUse(ScopeReg) 511 .addUse(MemSemReg) 512 .addUse(I.getOperand(2).getReg()) 513 .constrainAllUses(TII, TRI, RBI); 514 } 515 516 bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const { 517 AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm()); 518 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)); 519 Register MemSemReg = buildI32Constant(MemSem, I); 520 SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm()); 521 uint32_t Scope = static_cast<uint32_t>(getScope(Ord)); 522 Register ScopeReg = buildI32Constant(Scope, I); 523 MachineBasicBlock &BB = *I.getParent(); 524 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier)) 525 .addUse(ScopeReg) 526 .addUse(MemSemReg) 527 .constrainAllUses(TII, TRI, RBI); 528 } 529 530 bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg, 531 const SPIRVType *ResType, 532 MachineInstr &I) const { 533 assert(I.hasOneMemOperand()); 534 const MachineMemOperand *MemOp = *I.memoperands_begin(); 535 uint32_t Scope = static_cast<uint32_t>(getScope(MemOp->getSyncScopeID())); 536 Register ScopeReg = buildI32Constant(Scope, I); 537 538 Register Ptr = I.getOperand(2).getReg(); 539 Register Cmp = I.getOperand(3).getReg(); 540 Register Val = I.getOperand(4).getReg(); 541 542 SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val); 543 SPIRV::StorageClass SC = GR.getPointerStorageClass(Ptr); 544 uint32_t ScSem = static_cast<uint32_t>(getMemSemanticsForStorageClass(SC)); 545 AtomicOrdering AO = MemOp->getSuccessOrdering(); 546 uint32_t MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem; 547 Register MemSemEqReg = buildI32Constant(MemSemEq, I); 548 AtomicOrdering FO = MemOp->getFailureOrdering(); 549 uint32_t MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem; 550 Register MemSemNeqReg = 551 MemSemEq == MemSemNeq ? MemSemEqReg : buildI32Constant(MemSemNeq, I); 552 const DebugLoc &DL = I.getDebugLoc(); 553 return BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange)) 554 .addDef(ResVReg) 555 .addUse(GR.getSPIRVTypeID(SpvValTy)) 556 .addUse(Ptr) 557 .addUse(ScopeReg) 558 .addUse(MemSemEqReg) 559 .addUse(MemSemNeqReg) 560 .addUse(Val) 561 .addUse(Cmp) 562 .constrainAllUses(TII, TRI, RBI); 563 } 564 565 static bool isGenericCastablePtr(SPIRV::StorageClass SC) { 566 switch (SC) { 567 case SPIRV::StorageClass::Workgroup: 568 case SPIRV::StorageClass::CrossWorkgroup: 569 case SPIRV::StorageClass::Function: 570 return true; 571 default: 572 return false; 573 } 574 } 575 576 // In SPIR-V address space casting can only happen to and from the Generic 577 // storage class. We can also only case Workgroup, CrossWorkgroup, or Function 578 // pointers to and from Generic pointers. As such, we can convert e.g. from 579 // Workgroup to Function by going via a Generic pointer as an intermediary. All 580 // other combinations can only be done by a bitcast, and are probably not safe. 581 bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg, 582 const SPIRVType *ResType, 583 MachineInstr &I) const { 584 Register SrcPtr = I.getOperand(1).getReg(); 585 SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr); 586 SPIRV::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtr); 587 SPIRV::StorageClass DstSC = GR.getPointerStorageClass(ResVReg); 588 589 // Casting from an eligable pointer to Generic. 590 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC)) 591 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric); 592 // Casting from Generic to an eligable pointer. 593 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC)) 594 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr); 595 // Casting between 2 eligable pointers using Generic as an intermediary. 596 if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) { 597 Register Tmp = MRI->createVirtualRegister(&SPIRV::IDRegClass); 598 SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType( 599 SrcPtrTy, I, TII, SPIRV::StorageClass::Generic); 600 MachineBasicBlock &BB = *I.getParent(); 601 const DebugLoc &DL = I.getDebugLoc(); 602 bool Success = BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric)) 603 .addDef(Tmp) 604 .addUse(GR.getSPIRVTypeID(GenericPtrTy)) 605 .addUse(SrcPtr) 606 .constrainAllUses(TII, TRI, RBI); 607 return Success && BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr)) 608 .addDef(ResVReg) 609 .addUse(GR.getSPIRVTypeID(ResType)) 610 .addUse(Tmp) 611 .constrainAllUses(TII, TRI, RBI); 612 } 613 // TODO Should this case just be disallowed completely? 614 // We're casting 2 other arbitrary address spaces, so have to bitcast. 615 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast); 616 } 617 618 static unsigned getFCmpOpcode(unsigned PredNum) { 619 auto Pred = static_cast<CmpInst::Predicate>(PredNum); 620 switch (Pred) { 621 case CmpInst::FCMP_OEQ: 622 return SPIRV::OpFOrdEqual; 623 case CmpInst::FCMP_OGE: 624 return SPIRV::OpFOrdGreaterThanEqual; 625 case CmpInst::FCMP_OGT: 626 return SPIRV::OpFOrdGreaterThan; 627 case CmpInst::FCMP_OLE: 628 return SPIRV::OpFOrdLessThanEqual; 629 case CmpInst::FCMP_OLT: 630 return SPIRV::OpFOrdLessThan; 631 case CmpInst::FCMP_ONE: 632 return SPIRV::OpFOrdNotEqual; 633 case CmpInst::FCMP_ORD: 634 return SPIRV::OpOrdered; 635 case CmpInst::FCMP_UEQ: 636 return SPIRV::OpFUnordEqual; 637 case CmpInst::FCMP_UGE: 638 return SPIRV::OpFUnordGreaterThanEqual; 639 case CmpInst::FCMP_UGT: 640 return SPIRV::OpFUnordGreaterThan; 641 case CmpInst::FCMP_ULE: 642 return SPIRV::OpFUnordLessThanEqual; 643 case CmpInst::FCMP_ULT: 644 return SPIRV::OpFUnordLessThan; 645 case CmpInst::FCMP_UNE: 646 return SPIRV::OpFUnordNotEqual; 647 case CmpInst::FCMP_UNO: 648 return SPIRV::OpUnordered; 649 default: 650 llvm_unreachable("Unknown predicate type for FCmp"); 651 } 652 } 653 654 static unsigned getICmpOpcode(unsigned PredNum) { 655 auto Pred = static_cast<CmpInst::Predicate>(PredNum); 656 switch (Pred) { 657 case CmpInst::ICMP_EQ: 658 return SPIRV::OpIEqual; 659 case CmpInst::ICMP_NE: 660 return SPIRV::OpINotEqual; 661 case CmpInst::ICMP_SGE: 662 return SPIRV::OpSGreaterThanEqual; 663 case CmpInst::ICMP_SGT: 664 return SPIRV::OpSGreaterThan; 665 case CmpInst::ICMP_SLE: 666 return SPIRV::OpSLessThanEqual; 667 case CmpInst::ICMP_SLT: 668 return SPIRV::OpSLessThan; 669 case CmpInst::ICMP_UGE: 670 return SPIRV::OpUGreaterThanEqual; 671 case CmpInst::ICMP_UGT: 672 return SPIRV::OpUGreaterThan; 673 case CmpInst::ICMP_ULE: 674 return SPIRV::OpULessThanEqual; 675 case CmpInst::ICMP_ULT: 676 return SPIRV::OpULessThan; 677 default: 678 llvm_unreachable("Unknown predicate type for ICmp"); 679 } 680 } 681 682 static unsigned getPtrCmpOpcode(unsigned Pred) { 683 switch (static_cast<CmpInst::Predicate>(Pred)) { 684 case CmpInst::ICMP_EQ: 685 return SPIRV::OpPtrEqual; 686 case CmpInst::ICMP_NE: 687 return SPIRV::OpPtrNotEqual; 688 default: 689 llvm_unreachable("Unknown predicate type for pointer comparison"); 690 } 691 } 692 693 // Return the logical operation, or abort if none exists. 694 static unsigned getBoolCmpOpcode(unsigned PredNum) { 695 auto Pred = static_cast<CmpInst::Predicate>(PredNum); 696 switch (Pred) { 697 case CmpInst::ICMP_EQ: 698 return SPIRV::OpLogicalEqual; 699 case CmpInst::ICMP_NE: 700 return SPIRV::OpLogicalNotEqual; 701 default: 702 llvm_unreachable("Unknown predicate type for Bool comparison"); 703 } 704 } 705 706 bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg, 707 const SPIRVType *ResType, 708 MachineInstr &I) const { 709 MachineBasicBlock &BB = *I.getParent(); 710 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse)) 711 .addDef(ResVReg) 712 .addUse(GR.getSPIRVTypeID(ResType)) 713 .addUse(I.getOperand(1).getReg()) 714 .constrainAllUses(TII, TRI, RBI); 715 } 716 717 bool SPIRVInstructionSelector::selectConstVector(Register ResVReg, 718 const SPIRVType *ResType, 719 MachineInstr &I) const { 720 // TODO: only const case is supported for now. 721 assert(std::all_of( 722 I.operands_begin(), I.operands_end(), [this](const MachineOperand &MO) { 723 if (MO.isDef()) 724 return true; 725 if (!MO.isReg()) 726 return false; 727 SPIRVType *ConstTy = this->MRI->getVRegDef(MO.getReg()); 728 assert(ConstTy && ConstTy->getOpcode() == SPIRV::ASSIGN_TYPE && 729 ConstTy->getOperand(1).isReg()); 730 Register ConstReg = ConstTy->getOperand(1).getReg(); 731 const MachineInstr *Const = this->MRI->getVRegDef(ConstReg); 732 assert(Const); 733 return (Const->getOpcode() == TargetOpcode::G_CONSTANT || 734 Const->getOpcode() == TargetOpcode::G_FCONSTANT); 735 })); 736 737 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), 738 TII.get(SPIRV::OpConstantComposite)) 739 .addDef(ResVReg) 740 .addUse(GR.getSPIRVTypeID(ResType)); 741 for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i) 742 MIB.addUse(I.getOperand(i).getReg()); 743 return MIB.constrainAllUses(TII, TRI, RBI); 744 } 745 746 bool SPIRVInstructionSelector::selectCmp(Register ResVReg, 747 const SPIRVType *ResType, 748 unsigned CmpOpc, 749 MachineInstr &I) const { 750 Register Cmp0 = I.getOperand(2).getReg(); 751 Register Cmp1 = I.getOperand(3).getReg(); 752 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() == 753 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() && 754 "CMP operands should have the same type"); 755 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc)) 756 .addDef(ResVReg) 757 .addUse(GR.getSPIRVTypeID(ResType)) 758 .addUse(Cmp0) 759 .addUse(Cmp1) 760 .constrainAllUses(TII, TRI, RBI); 761 } 762 763 bool SPIRVInstructionSelector::selectICmp(Register ResVReg, 764 const SPIRVType *ResType, 765 MachineInstr &I) const { 766 auto Pred = I.getOperand(1).getPredicate(); 767 unsigned CmpOpc; 768 769 Register CmpOperand = I.getOperand(2).getReg(); 770 if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer)) 771 CmpOpc = getPtrCmpOpcode(Pred); 772 else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool)) 773 CmpOpc = getBoolCmpOpcode(Pred); 774 else 775 CmpOpc = getICmpOpcode(Pred); 776 return selectCmp(ResVReg, ResType, CmpOpc, I); 777 } 778 779 void SPIRVInstructionSelector::renderFImm32(MachineInstrBuilder &MIB, 780 const MachineInstr &I, 781 int OpIdx) const { 782 assert(I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 && 783 "Expected G_FCONSTANT"); 784 const ConstantFP *FPImm = I.getOperand(1).getFPImm(); 785 addNumImm(FPImm->getValueAPF().bitcastToAPInt(), MIB); 786 } 787 788 void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder &MIB, 789 const MachineInstr &I, 790 int OpIdx) const { 791 assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 792 "Expected G_CONSTANT"); 793 addNumImm(I.getOperand(1).getCImm()->getValue(), MIB); 794 } 795 796 Register 797 SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I, 798 const SPIRVType *ResType) const { 799 const SPIRVType *SpvI32Ty = 800 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII); 801 Register NewReg; 802 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(32)); 803 MachineInstr *MI; 804 MachineBasicBlock &BB = *I.getParent(); 805 if (Val == 0) { 806 MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) 807 .addDef(NewReg) 808 .addUse(GR.getSPIRVTypeID(SpvI32Ty)); 809 } else { 810 MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI)) 811 .addDef(NewReg) 812 .addUse(GR.getSPIRVTypeID(SpvI32Ty)) 813 .addImm(APInt(32, Val).getZExtValue()); 814 } 815 constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 816 return NewReg; 817 } 818 819 bool SPIRVInstructionSelector::selectFCmp(Register ResVReg, 820 const SPIRVType *ResType, 821 MachineInstr &I) const { 822 unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate()); 823 return selectCmp(ResVReg, ResType, CmpOp, I); 824 } 825 826 Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType, 827 MachineInstr &I) const { 828 return buildI32Constant(0, I, ResType); 829 } 830 831 Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes, 832 const SPIRVType *ResType, 833 MachineInstr &I) const { 834 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType); 835 APInt One = AllOnes ? APInt::getAllOnesValue(BitWidth) 836 : APInt::getOneBitSet(BitWidth, 0); 837 Register OneReg = buildI32Constant(One.getZExtValue(), I, ResType); 838 if (ResType->getOpcode() == SPIRV::OpTypeVector) { 839 const unsigned NumEles = ResType->getOperand(2).getImm(); 840 Register OneVec = MRI->createVirtualRegister(&SPIRV::IDRegClass); 841 unsigned Opcode = SPIRV::OpConstantComposite; 842 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) 843 .addDef(OneVec) 844 .addUse(GR.getSPIRVTypeID(ResType)); 845 for (unsigned i = 0; i < NumEles; ++i) 846 MIB.addUse(OneReg); 847 constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); 848 return OneVec; 849 } 850 return OneReg; 851 } 852 853 bool SPIRVInstructionSelector::selectSelect(Register ResVReg, 854 const SPIRVType *ResType, 855 MachineInstr &I, 856 bool IsSigned) const { 857 // To extend a bool, we need to use OpSelect between constants. 858 Register ZeroReg = buildZerosVal(ResType, I); 859 Register OneReg = buildOnesVal(IsSigned, ResType, I); 860 bool IsScalarBool = 861 GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool); 862 unsigned Opcode = 863 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectSIVCond; 864 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) 865 .addDef(ResVReg) 866 .addUse(GR.getSPIRVTypeID(ResType)) 867 .addUse(I.getOperand(1).getReg()) 868 .addUse(OneReg) 869 .addUse(ZeroReg) 870 .constrainAllUses(TII, TRI, RBI); 871 } 872 873 bool SPIRVInstructionSelector::selectIToF(Register ResVReg, 874 const SPIRVType *ResType, 875 MachineInstr &I, bool IsSigned, 876 unsigned Opcode) const { 877 Register SrcReg = I.getOperand(1).getReg(); 878 // We can convert bool value directly to float type without OpConvert*ToF, 879 // however the translator generates OpSelect+OpConvert*ToF, so we do the same. 880 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) { 881 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType); 882 SPIRVType *TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII); 883 if (ResType->getOpcode() == SPIRV::OpTypeVector) { 884 const unsigned NumElts = ResType->getOperand(2).getImm(); 885 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII); 886 } 887 SrcReg = MRI->createVirtualRegister(&SPIRV::IDRegClass); 888 selectSelect(SrcReg, TmpType, I, false); 889 } 890 return selectUnOpWithSrc(ResVReg, ResType, I, SrcReg, Opcode); 891 } 892 893 bool SPIRVInstructionSelector::selectExt(Register ResVReg, 894 const SPIRVType *ResType, 895 MachineInstr &I, bool IsSigned) const { 896 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) 897 return selectSelect(ResVReg, ResType, I, IsSigned); 898 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; 899 return selectUnOp(ResVReg, ResType, I, Opcode); 900 } 901 902 bool SPIRVInstructionSelector::selectIntToBool(Register IntReg, 903 Register ResVReg, 904 const SPIRVType *IntTy, 905 const SPIRVType *BoolTy, 906 MachineInstr &I) const { 907 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero. 908 Register BitIntReg = MRI->createVirtualRegister(&SPIRV::IDRegClass); 909 bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector; 910 unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS; 911 Register Zero = buildZerosVal(IntTy, I); 912 Register One = buildOnesVal(false, IntTy, I); 913 MachineBasicBlock &BB = *I.getParent(); 914 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 915 .addDef(BitIntReg) 916 .addUse(GR.getSPIRVTypeID(IntTy)) 917 .addUse(IntReg) 918 .addUse(One) 919 .constrainAllUses(TII, TRI, RBI); 920 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual)) 921 .addDef(ResVReg) 922 .addUse(GR.getSPIRVTypeID(BoolTy)) 923 .addUse(BitIntReg) 924 .addUse(Zero) 925 .constrainAllUses(TII, TRI, RBI); 926 } 927 928 bool SPIRVInstructionSelector::selectTrunc(Register ResVReg, 929 const SPIRVType *ResType, 930 MachineInstr &I) const { 931 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool)) { 932 Register IntReg = I.getOperand(1).getReg(); 933 const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg); 934 return selectIntToBool(IntReg, ResVReg, ArgType, ResType, I); 935 } 936 bool IsSigned = GR.isScalarOrVectorSigned(ResType); 937 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; 938 return selectUnOp(ResVReg, ResType, I, Opcode); 939 } 940 941 bool SPIRVInstructionSelector::selectConst(Register ResVReg, 942 const SPIRVType *ResType, 943 const APInt &Imm, 944 MachineInstr &I) const { 945 assert(ResType->getOpcode() != SPIRV::OpTypePointer || Imm.isNullValue()); 946 MachineBasicBlock &BB = *I.getParent(); 947 if (ResType->getOpcode() == SPIRV::OpTypePointer && Imm.isNullValue()) { 948 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) 949 .addDef(ResVReg) 950 .addUse(GR.getSPIRVTypeID(ResType)) 951 .constrainAllUses(TII, TRI, RBI); 952 } 953 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI)) 954 .addDef(ResVReg) 955 .addUse(GR.getSPIRVTypeID(ResType)); 956 // <=32-bit integers should be caught by the sdag pattern. 957 assert(Imm.getBitWidth() > 32); 958 addNumImm(Imm, MIB); 959 return MIB.constrainAllUses(TII, TRI, RBI); 960 } 961 962 bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg, 963 const SPIRVType *ResType, 964 MachineInstr &I) const { 965 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef)) 966 .addDef(ResVReg) 967 .addUse(GR.getSPIRVTypeID(ResType)) 968 .constrainAllUses(TII, TRI, RBI); 969 } 970 971 bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, 972 const SPIRVType *ResType, 973 MachineInstr &I) const { 974 llvm_unreachable("Intrinsic selection not implemented"); 975 } 976 977 bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg, 978 const SPIRVType *ResType, 979 MachineInstr &I) const { 980 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable)) 981 .addDef(ResVReg) 982 .addUse(GR.getSPIRVTypeID(ResType)) 983 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function)) 984 .constrainAllUses(TII, TRI, RBI); 985 } 986 987 bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const { 988 // InstructionSelector walks backwards through the instructions. We can use 989 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR 990 // first, so can generate an OpBranchConditional here. If there is no 991 // G_BRCOND, we just use OpBranch for a regular unconditional branch. 992 const MachineInstr *PrevI = I.getPrevNode(); 993 MachineBasicBlock &MBB = *I.getParent(); 994 if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) { 995 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional)) 996 .addUse(PrevI->getOperand(0).getReg()) 997 .addMBB(PrevI->getOperand(1).getMBB()) 998 .addMBB(I.getOperand(0).getMBB()) 999 .constrainAllUses(TII, TRI, RBI); 1000 } 1001 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch)) 1002 .addMBB(I.getOperand(0).getMBB()) 1003 .constrainAllUses(TII, TRI, RBI); 1004 } 1005 1006 bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const { 1007 // InstructionSelector walks backwards through the instructions. For an 1008 // explicit conditional branch with no fallthrough, we use both a G_BR and a 1009 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and 1010 // generate the OpBranchConditional in selectBranch above. 1011 // 1012 // If an OpBranchConditional has been generated, we simply return, as the work 1013 // is alread done. If there is no OpBranchConditional, LLVM must be relying on 1014 // implicit fallthrough to the next basic block, so we need to create an 1015 // OpBranchConditional with an explicit "false" argument pointing to the next 1016 // basic block that LLVM would fall through to. 1017 const MachineInstr *NextI = I.getNextNode(); 1018 // Check if this has already been successfully selected. 1019 if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional) 1020 return true; 1021 // Must be relying on implicit block fallthrough, so generate an 1022 // OpBranchConditional with the "next" basic block as the "false" target. 1023 MachineBasicBlock &MBB = *I.getParent(); 1024 unsigned NextMBBNum = MBB.getNextNode()->getNumber(); 1025 MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum); 1026 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional)) 1027 .addUse(I.getOperand(0).getReg()) 1028 .addMBB(I.getOperand(1).getMBB()) 1029 .addMBB(NextMBB) 1030 .constrainAllUses(TII, TRI, RBI); 1031 } 1032 1033 bool SPIRVInstructionSelector::selectPhi(Register ResVReg, 1034 const SPIRVType *ResType, 1035 MachineInstr &I) const { 1036 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpPhi)) 1037 .addDef(ResVReg) 1038 .addUse(GR.getSPIRVTypeID(ResType)); 1039 const unsigned NumOps = I.getNumOperands(); 1040 for (unsigned i = 1; i < NumOps; i += 2) { 1041 MIB.addUse(I.getOperand(i + 0).getReg()); 1042 MIB.addMBB(I.getOperand(i + 1).getMBB()); 1043 } 1044 return MIB.constrainAllUses(TII, TRI, RBI); 1045 } 1046 1047 bool SPIRVInstructionSelector::selectGlobalValue( 1048 Register ResVReg, MachineInstr &I, const MachineInstr *Init) const { 1049 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI. 1050 MachineIRBuilder MIRBuilder(I); 1051 const GlobalValue *GV = I.getOperand(1).getGlobal(); 1052 SPIRVType *ResType = GR.getOrCreateSPIRVType( 1053 GV->getType(), MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false); 1054 1055 std::string GlobalIdent = GV->getGlobalIdentifier(); 1056 // TODO: suport @llvm.global.annotations. 1057 auto GlobalVar = cast<GlobalVariable>(GV); 1058 1059 bool HasInit = GlobalVar->hasInitializer() && 1060 !isa<UndefValue>(GlobalVar->getInitializer()); 1061 // Skip empty declaration for GVs with initilaizers till we get the decl with 1062 // passed initializer. 1063 if (HasInit && !Init) 1064 return true; 1065 1066 unsigned AddrSpace = GV->getAddressSpace(); 1067 SPIRV::StorageClass Storage = addressSpaceToStorageClass(AddrSpace); 1068 bool HasLnkTy = GV->getLinkage() != GlobalValue::InternalLinkage && 1069 Storage != SPIRV::StorageClass::Function; 1070 SPIRV::LinkageType LnkType = 1071 (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) 1072 ? SPIRV::LinkageType::Import 1073 : SPIRV::LinkageType::Export; 1074 1075 Register Reg = GR.buildGlobalVariable(ResVReg, ResType, GlobalIdent, GV, 1076 Storage, Init, GlobalVar->isConstant(), 1077 HasLnkTy, LnkType, MIRBuilder, true); 1078 return Reg.isValid(); 1079 } 1080 1081 namespace llvm { 1082 InstructionSelector * 1083 createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, 1084 const SPIRVSubtarget &Subtarget, 1085 const RegisterBankInfo &RBI) { 1086 return new SPIRVInstructionSelector(TM, Subtarget, RBI); 1087 } 1088 } // namespace llvm 1089