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 default: 393 return SPIRV::MemorySemantics::None; 394 } 395 } 396 397 static SPIRV::Scope getScope(SyncScope::ID Ord) { 398 switch (Ord) { 399 case SyncScope::SingleThread: 400 return SPIRV::Scope::Invocation; 401 case SyncScope::System: 402 return SPIRV::Scope::Device; 403 default: 404 llvm_unreachable("Unsupported synchronization Scope ID."); 405 } 406 } 407 408 static void addMemoryOperands(MachineMemOperand *MemOp, 409 MachineInstrBuilder &MIB) { 410 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None); 411 if (MemOp->isVolatile()) 412 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile); 413 if (MemOp->isNonTemporal()) 414 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal); 415 if (MemOp->getAlign().value()) 416 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned); 417 418 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) { 419 MIB.addImm(SpvMemOp); 420 if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned)) 421 MIB.addImm(MemOp->getAlign().value()); 422 } 423 } 424 425 static void addMemoryOperands(uint64_t Flags, MachineInstrBuilder &MIB) { 426 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None); 427 if (Flags & MachineMemOperand::Flags::MOVolatile) 428 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile); 429 if (Flags & MachineMemOperand::Flags::MONonTemporal) 430 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal); 431 432 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) 433 MIB.addImm(SpvMemOp); 434 } 435 436 bool SPIRVInstructionSelector::selectLoad(Register ResVReg, 437 const SPIRVType *ResType, 438 MachineInstr &I) const { 439 unsigned OpOffset = 440 I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ? 1 : 0; 441 Register Ptr = I.getOperand(1 + OpOffset).getReg(); 442 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad)) 443 .addDef(ResVReg) 444 .addUse(GR.getSPIRVTypeID(ResType)) 445 .addUse(Ptr); 446 if (!I.getNumMemOperands()) { 447 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS); 448 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB); 449 } else { 450 addMemoryOperands(*I.memoperands_begin(), MIB); 451 } 452 return MIB.constrainAllUses(TII, TRI, RBI); 453 } 454 455 bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const { 456 unsigned OpOffset = 457 I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ? 1 : 0; 458 Register StoreVal = I.getOperand(0 + OpOffset).getReg(); 459 Register Ptr = I.getOperand(1 + OpOffset).getReg(); 460 MachineBasicBlock &BB = *I.getParent(); 461 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore)) 462 .addUse(Ptr) 463 .addUse(StoreVal); 464 if (!I.getNumMemOperands()) { 465 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS); 466 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB); 467 } else { 468 addMemoryOperands(*I.memoperands_begin(), MIB); 469 } 470 return MIB.constrainAllUses(TII, TRI, RBI); 471 } 472 473 bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg, 474 MachineInstr &I) const { 475 MachineBasicBlock &BB = *I.getParent(); 476 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized)) 477 .addDef(I.getOperand(0).getReg()) 478 .addUse(I.getOperand(1).getReg()) 479 .addUse(I.getOperand(2).getReg()); 480 if (I.getNumMemOperands()) 481 addMemoryOperands(*I.memoperands_begin(), MIB); 482 bool Result = MIB.constrainAllUses(TII, TRI, RBI); 483 if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg()) { 484 BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), ResVReg) 485 .addUse(MIB->getOperand(0).getReg()); 486 } 487 return Result; 488 } 489 490 bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg, 491 const SPIRVType *ResType, 492 MachineInstr &I, 493 unsigned NewOpcode) const { 494 assert(I.hasOneMemOperand()); 495 const MachineMemOperand *MemOp = *I.memoperands_begin(); 496 uint32_t Scope = static_cast<uint32_t>(getScope(MemOp->getSyncScopeID())); 497 Register ScopeReg = buildI32Constant(Scope, I); 498 499 Register Ptr = I.getOperand(1).getReg(); 500 // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll 501 // auto ScSem = 502 // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr)); 503 AtomicOrdering AO = MemOp->getSuccessOrdering(); 504 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)); 505 Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I); 506 507 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode)) 508 .addDef(ResVReg) 509 .addUse(GR.getSPIRVTypeID(ResType)) 510 .addUse(Ptr) 511 .addUse(ScopeReg) 512 .addUse(MemSemReg) 513 .addUse(I.getOperand(2).getReg()) 514 .constrainAllUses(TII, TRI, RBI); 515 } 516 517 bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const { 518 AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm()); 519 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)); 520 Register MemSemReg = buildI32Constant(MemSem, I); 521 SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm()); 522 uint32_t Scope = static_cast<uint32_t>(getScope(Ord)); 523 Register ScopeReg = buildI32Constant(Scope, I); 524 MachineBasicBlock &BB = *I.getParent(); 525 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier)) 526 .addUse(ScopeReg) 527 .addUse(MemSemReg) 528 .constrainAllUses(TII, TRI, RBI); 529 } 530 531 bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg, 532 const SPIRVType *ResType, 533 MachineInstr &I) const { 534 assert(I.hasOneMemOperand()); 535 const MachineMemOperand *MemOp = *I.memoperands_begin(); 536 uint32_t Scope = static_cast<uint32_t>(getScope(MemOp->getSyncScopeID())); 537 Register ScopeReg = buildI32Constant(Scope, I); 538 539 Register Ptr = I.getOperand(2).getReg(); 540 Register Cmp = I.getOperand(3).getReg(); 541 Register Val = I.getOperand(4).getReg(); 542 543 SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val); 544 SPIRV::StorageClass SC = GR.getPointerStorageClass(Ptr); 545 uint32_t ScSem = static_cast<uint32_t>(getMemSemanticsForStorageClass(SC)); 546 AtomicOrdering AO = MemOp->getSuccessOrdering(); 547 uint32_t MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem; 548 Register MemSemEqReg = buildI32Constant(MemSemEq, I); 549 AtomicOrdering FO = MemOp->getFailureOrdering(); 550 uint32_t MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem; 551 Register MemSemNeqReg = 552 MemSemEq == MemSemNeq ? MemSemEqReg : buildI32Constant(MemSemNeq, I); 553 const DebugLoc &DL = I.getDebugLoc(); 554 return BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange)) 555 .addDef(ResVReg) 556 .addUse(GR.getSPIRVTypeID(SpvValTy)) 557 .addUse(Ptr) 558 .addUse(ScopeReg) 559 .addUse(MemSemEqReg) 560 .addUse(MemSemNeqReg) 561 .addUse(Val) 562 .addUse(Cmp) 563 .constrainAllUses(TII, TRI, RBI); 564 } 565 566 static bool isGenericCastablePtr(SPIRV::StorageClass SC) { 567 switch (SC) { 568 case SPIRV::StorageClass::Workgroup: 569 case SPIRV::StorageClass::CrossWorkgroup: 570 case SPIRV::StorageClass::Function: 571 return true; 572 default: 573 return false; 574 } 575 } 576 577 // In SPIR-V address space casting can only happen to and from the Generic 578 // storage class. We can also only case Workgroup, CrossWorkgroup, or Function 579 // pointers to and from Generic pointers. As such, we can convert e.g. from 580 // Workgroup to Function by going via a Generic pointer as an intermediary. All 581 // other combinations can only be done by a bitcast, and are probably not safe. 582 bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg, 583 const SPIRVType *ResType, 584 MachineInstr &I) const { 585 Register SrcPtr = I.getOperand(1).getReg(); 586 SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr); 587 SPIRV::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtr); 588 SPIRV::StorageClass DstSC = GR.getPointerStorageClass(ResVReg); 589 590 // Casting from an eligable pointer to Generic. 591 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC)) 592 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric); 593 // Casting from Generic to an eligable pointer. 594 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC)) 595 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr); 596 // Casting between 2 eligable pointers using Generic as an intermediary. 597 if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) { 598 Register Tmp = MRI->createVirtualRegister(&SPIRV::IDRegClass); 599 SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType( 600 SrcPtrTy, I, TII, SPIRV::StorageClass::Generic); 601 MachineBasicBlock &BB = *I.getParent(); 602 const DebugLoc &DL = I.getDebugLoc(); 603 bool Success = BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric)) 604 .addDef(Tmp) 605 .addUse(GR.getSPIRVTypeID(GenericPtrTy)) 606 .addUse(SrcPtr) 607 .constrainAllUses(TII, TRI, RBI); 608 return Success && BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr)) 609 .addDef(ResVReg) 610 .addUse(GR.getSPIRVTypeID(ResType)) 611 .addUse(Tmp) 612 .constrainAllUses(TII, TRI, RBI); 613 } 614 // TODO Should this case just be disallowed completely? 615 // We're casting 2 other arbitrary address spaces, so have to bitcast. 616 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast); 617 } 618 619 static unsigned getFCmpOpcode(unsigned PredNum) { 620 auto Pred = static_cast<CmpInst::Predicate>(PredNum); 621 switch (Pred) { 622 case CmpInst::FCMP_OEQ: 623 return SPIRV::OpFOrdEqual; 624 case CmpInst::FCMP_OGE: 625 return SPIRV::OpFOrdGreaterThanEqual; 626 case CmpInst::FCMP_OGT: 627 return SPIRV::OpFOrdGreaterThan; 628 case CmpInst::FCMP_OLE: 629 return SPIRV::OpFOrdLessThanEqual; 630 case CmpInst::FCMP_OLT: 631 return SPIRV::OpFOrdLessThan; 632 case CmpInst::FCMP_ONE: 633 return SPIRV::OpFOrdNotEqual; 634 case CmpInst::FCMP_ORD: 635 return SPIRV::OpOrdered; 636 case CmpInst::FCMP_UEQ: 637 return SPIRV::OpFUnordEqual; 638 case CmpInst::FCMP_UGE: 639 return SPIRV::OpFUnordGreaterThanEqual; 640 case CmpInst::FCMP_UGT: 641 return SPIRV::OpFUnordGreaterThan; 642 case CmpInst::FCMP_ULE: 643 return SPIRV::OpFUnordLessThanEqual; 644 case CmpInst::FCMP_ULT: 645 return SPIRV::OpFUnordLessThan; 646 case CmpInst::FCMP_UNE: 647 return SPIRV::OpFUnordNotEqual; 648 case CmpInst::FCMP_UNO: 649 return SPIRV::OpUnordered; 650 default: 651 llvm_unreachable("Unknown predicate type for FCmp"); 652 } 653 } 654 655 static unsigned getICmpOpcode(unsigned PredNum) { 656 auto Pred = static_cast<CmpInst::Predicate>(PredNum); 657 switch (Pred) { 658 case CmpInst::ICMP_EQ: 659 return SPIRV::OpIEqual; 660 case CmpInst::ICMP_NE: 661 return SPIRV::OpINotEqual; 662 case CmpInst::ICMP_SGE: 663 return SPIRV::OpSGreaterThanEqual; 664 case CmpInst::ICMP_SGT: 665 return SPIRV::OpSGreaterThan; 666 case CmpInst::ICMP_SLE: 667 return SPIRV::OpSLessThanEqual; 668 case CmpInst::ICMP_SLT: 669 return SPIRV::OpSLessThan; 670 case CmpInst::ICMP_UGE: 671 return SPIRV::OpUGreaterThanEqual; 672 case CmpInst::ICMP_UGT: 673 return SPIRV::OpUGreaterThan; 674 case CmpInst::ICMP_ULE: 675 return SPIRV::OpULessThanEqual; 676 case CmpInst::ICMP_ULT: 677 return SPIRV::OpULessThan; 678 default: 679 llvm_unreachable("Unknown predicate type for ICmp"); 680 } 681 } 682 683 static unsigned getPtrCmpOpcode(unsigned Pred) { 684 switch (static_cast<CmpInst::Predicate>(Pred)) { 685 case CmpInst::ICMP_EQ: 686 return SPIRV::OpPtrEqual; 687 case CmpInst::ICMP_NE: 688 return SPIRV::OpPtrNotEqual; 689 default: 690 llvm_unreachable("Unknown predicate type for pointer comparison"); 691 } 692 } 693 694 // Return the logical operation, or abort if none exists. 695 static unsigned getBoolCmpOpcode(unsigned PredNum) { 696 auto Pred = static_cast<CmpInst::Predicate>(PredNum); 697 switch (Pred) { 698 case CmpInst::ICMP_EQ: 699 return SPIRV::OpLogicalEqual; 700 case CmpInst::ICMP_NE: 701 return SPIRV::OpLogicalNotEqual; 702 default: 703 llvm_unreachable("Unknown predicate type for Bool comparison"); 704 } 705 } 706 707 bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg, 708 const SPIRVType *ResType, 709 MachineInstr &I) const { 710 MachineBasicBlock &BB = *I.getParent(); 711 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse)) 712 .addDef(ResVReg) 713 .addUse(GR.getSPIRVTypeID(ResType)) 714 .addUse(I.getOperand(1).getReg()) 715 .constrainAllUses(TII, TRI, RBI); 716 } 717 718 bool SPIRVInstructionSelector::selectConstVector(Register ResVReg, 719 const SPIRVType *ResType, 720 MachineInstr &I) const { 721 // TODO: only const case is supported for now. 722 assert(std::all_of( 723 I.operands_begin(), I.operands_end(), [this](const MachineOperand &MO) { 724 if (MO.isDef()) 725 return true; 726 if (!MO.isReg()) 727 return false; 728 SPIRVType *ConstTy = this->MRI->getVRegDef(MO.getReg()); 729 assert(ConstTy && ConstTy->getOpcode() == SPIRV::ASSIGN_TYPE && 730 ConstTy->getOperand(1).isReg()); 731 Register ConstReg = ConstTy->getOperand(1).getReg(); 732 const MachineInstr *Const = this->MRI->getVRegDef(ConstReg); 733 assert(Const); 734 return (Const->getOpcode() == TargetOpcode::G_CONSTANT || 735 Const->getOpcode() == TargetOpcode::G_FCONSTANT); 736 })); 737 738 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), 739 TII.get(SPIRV::OpConstantComposite)) 740 .addDef(ResVReg) 741 .addUse(GR.getSPIRVTypeID(ResType)); 742 for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i) 743 MIB.addUse(I.getOperand(i).getReg()); 744 return MIB.constrainAllUses(TII, TRI, RBI); 745 } 746 747 bool SPIRVInstructionSelector::selectCmp(Register ResVReg, 748 const SPIRVType *ResType, 749 unsigned CmpOpc, 750 MachineInstr &I) const { 751 Register Cmp0 = I.getOperand(2).getReg(); 752 Register Cmp1 = I.getOperand(3).getReg(); 753 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() == 754 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() && 755 "CMP operands should have the same type"); 756 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc)) 757 .addDef(ResVReg) 758 .addUse(GR.getSPIRVTypeID(ResType)) 759 .addUse(Cmp0) 760 .addUse(Cmp1) 761 .constrainAllUses(TII, TRI, RBI); 762 } 763 764 bool SPIRVInstructionSelector::selectICmp(Register ResVReg, 765 const SPIRVType *ResType, 766 MachineInstr &I) const { 767 auto Pred = I.getOperand(1).getPredicate(); 768 unsigned CmpOpc; 769 770 Register CmpOperand = I.getOperand(2).getReg(); 771 if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer)) 772 CmpOpc = getPtrCmpOpcode(Pred); 773 else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool)) 774 CmpOpc = getBoolCmpOpcode(Pred); 775 else 776 CmpOpc = getICmpOpcode(Pred); 777 return selectCmp(ResVReg, ResType, CmpOpc, I); 778 } 779 780 void SPIRVInstructionSelector::renderFImm32(MachineInstrBuilder &MIB, 781 const MachineInstr &I, 782 int OpIdx) const { 783 assert(I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 && 784 "Expected G_FCONSTANT"); 785 const ConstantFP *FPImm = I.getOperand(1).getFPImm(); 786 addNumImm(FPImm->getValueAPF().bitcastToAPInt(), MIB); 787 } 788 789 void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder &MIB, 790 const MachineInstr &I, 791 int OpIdx) const { 792 assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 793 "Expected G_CONSTANT"); 794 addNumImm(I.getOperand(1).getCImm()->getValue(), MIB); 795 } 796 797 Register 798 SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I, 799 const SPIRVType *ResType) const { 800 const SPIRVType *SpvI32Ty = 801 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII); 802 Register NewReg; 803 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(32)); 804 MachineInstr *MI; 805 MachineBasicBlock &BB = *I.getParent(); 806 if (Val == 0) { 807 MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) 808 .addDef(NewReg) 809 .addUse(GR.getSPIRVTypeID(SpvI32Ty)); 810 } else { 811 MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI)) 812 .addDef(NewReg) 813 .addUse(GR.getSPIRVTypeID(SpvI32Ty)) 814 .addImm(APInt(32, Val).getZExtValue()); 815 } 816 constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 817 return NewReg; 818 } 819 820 bool SPIRVInstructionSelector::selectFCmp(Register ResVReg, 821 const SPIRVType *ResType, 822 MachineInstr &I) const { 823 unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate()); 824 return selectCmp(ResVReg, ResType, CmpOp, I); 825 } 826 827 Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType, 828 MachineInstr &I) const { 829 return buildI32Constant(0, I, ResType); 830 } 831 832 Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes, 833 const SPIRVType *ResType, 834 MachineInstr &I) const { 835 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType); 836 APInt One = AllOnes ? APInt::getAllOnesValue(BitWidth) 837 : APInt::getOneBitSet(BitWidth, 0); 838 Register OneReg = buildI32Constant(One.getZExtValue(), I, ResType); 839 if (ResType->getOpcode() == SPIRV::OpTypeVector) { 840 const unsigned NumEles = ResType->getOperand(2).getImm(); 841 Register OneVec = MRI->createVirtualRegister(&SPIRV::IDRegClass); 842 unsigned Opcode = SPIRV::OpConstantComposite; 843 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) 844 .addDef(OneVec) 845 .addUse(GR.getSPIRVTypeID(ResType)); 846 for (unsigned i = 0; i < NumEles; ++i) 847 MIB.addUse(OneReg); 848 constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); 849 return OneVec; 850 } 851 return OneReg; 852 } 853 854 bool SPIRVInstructionSelector::selectSelect(Register ResVReg, 855 const SPIRVType *ResType, 856 MachineInstr &I, 857 bool IsSigned) const { 858 // To extend a bool, we need to use OpSelect between constants. 859 Register ZeroReg = buildZerosVal(ResType, I); 860 Register OneReg = buildOnesVal(IsSigned, ResType, I); 861 bool IsScalarBool = 862 GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool); 863 unsigned Opcode = 864 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectSIVCond; 865 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) 866 .addDef(ResVReg) 867 .addUse(GR.getSPIRVTypeID(ResType)) 868 .addUse(I.getOperand(1).getReg()) 869 .addUse(OneReg) 870 .addUse(ZeroReg) 871 .constrainAllUses(TII, TRI, RBI); 872 } 873 874 bool SPIRVInstructionSelector::selectIToF(Register ResVReg, 875 const SPIRVType *ResType, 876 MachineInstr &I, bool IsSigned, 877 unsigned Opcode) const { 878 Register SrcReg = I.getOperand(1).getReg(); 879 // We can convert bool value directly to float type without OpConvert*ToF, 880 // however the translator generates OpSelect+OpConvert*ToF, so we do the same. 881 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) { 882 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType); 883 SPIRVType *TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII); 884 if (ResType->getOpcode() == SPIRV::OpTypeVector) { 885 const unsigned NumElts = ResType->getOperand(2).getImm(); 886 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII); 887 } 888 SrcReg = MRI->createVirtualRegister(&SPIRV::IDRegClass); 889 selectSelect(SrcReg, TmpType, I, false); 890 } 891 return selectUnOpWithSrc(ResVReg, ResType, I, SrcReg, Opcode); 892 } 893 894 bool SPIRVInstructionSelector::selectExt(Register ResVReg, 895 const SPIRVType *ResType, 896 MachineInstr &I, bool IsSigned) const { 897 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) 898 return selectSelect(ResVReg, ResType, I, IsSigned); 899 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; 900 return selectUnOp(ResVReg, ResType, I, Opcode); 901 } 902 903 bool SPIRVInstructionSelector::selectIntToBool(Register IntReg, 904 Register ResVReg, 905 const SPIRVType *IntTy, 906 const SPIRVType *BoolTy, 907 MachineInstr &I) const { 908 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero. 909 Register BitIntReg = MRI->createVirtualRegister(&SPIRV::IDRegClass); 910 bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector; 911 unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS; 912 Register Zero = buildZerosVal(IntTy, I); 913 Register One = buildOnesVal(false, IntTy, I); 914 MachineBasicBlock &BB = *I.getParent(); 915 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 916 .addDef(BitIntReg) 917 .addUse(GR.getSPIRVTypeID(IntTy)) 918 .addUse(IntReg) 919 .addUse(One) 920 .constrainAllUses(TII, TRI, RBI); 921 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual)) 922 .addDef(ResVReg) 923 .addUse(GR.getSPIRVTypeID(BoolTy)) 924 .addUse(BitIntReg) 925 .addUse(Zero) 926 .constrainAllUses(TII, TRI, RBI); 927 } 928 929 bool SPIRVInstructionSelector::selectTrunc(Register ResVReg, 930 const SPIRVType *ResType, 931 MachineInstr &I) const { 932 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool)) { 933 Register IntReg = I.getOperand(1).getReg(); 934 const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg); 935 return selectIntToBool(IntReg, ResVReg, ArgType, ResType, I); 936 } 937 bool IsSigned = GR.isScalarOrVectorSigned(ResType); 938 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; 939 return selectUnOp(ResVReg, ResType, I, Opcode); 940 } 941 942 bool SPIRVInstructionSelector::selectConst(Register ResVReg, 943 const SPIRVType *ResType, 944 const APInt &Imm, 945 MachineInstr &I) const { 946 assert(ResType->getOpcode() != SPIRV::OpTypePointer || Imm.isNullValue()); 947 MachineBasicBlock &BB = *I.getParent(); 948 if (ResType->getOpcode() == SPIRV::OpTypePointer && Imm.isNullValue()) { 949 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) 950 .addDef(ResVReg) 951 .addUse(GR.getSPIRVTypeID(ResType)) 952 .constrainAllUses(TII, TRI, RBI); 953 } 954 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI)) 955 .addDef(ResVReg) 956 .addUse(GR.getSPIRVTypeID(ResType)); 957 // <=32-bit integers should be caught by the sdag pattern. 958 assert(Imm.getBitWidth() > 32); 959 addNumImm(Imm, MIB); 960 return MIB.constrainAllUses(TII, TRI, RBI); 961 } 962 963 bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg, 964 const SPIRVType *ResType, 965 MachineInstr &I) const { 966 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef)) 967 .addDef(ResVReg) 968 .addUse(GR.getSPIRVTypeID(ResType)) 969 .constrainAllUses(TII, TRI, RBI); 970 } 971 972 bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, 973 const SPIRVType *ResType, 974 MachineInstr &I) const { 975 llvm_unreachable("Intrinsic selection not implemented"); 976 } 977 978 bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg, 979 const SPIRVType *ResType, 980 MachineInstr &I) const { 981 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable)) 982 .addDef(ResVReg) 983 .addUse(GR.getSPIRVTypeID(ResType)) 984 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function)) 985 .constrainAllUses(TII, TRI, RBI); 986 } 987 988 bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const { 989 // InstructionSelector walks backwards through the instructions. We can use 990 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR 991 // first, so can generate an OpBranchConditional here. If there is no 992 // G_BRCOND, we just use OpBranch for a regular unconditional branch. 993 const MachineInstr *PrevI = I.getPrevNode(); 994 MachineBasicBlock &MBB = *I.getParent(); 995 if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) { 996 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional)) 997 .addUse(PrevI->getOperand(0).getReg()) 998 .addMBB(PrevI->getOperand(1).getMBB()) 999 .addMBB(I.getOperand(0).getMBB()) 1000 .constrainAllUses(TII, TRI, RBI); 1001 } 1002 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch)) 1003 .addMBB(I.getOperand(0).getMBB()) 1004 .constrainAllUses(TII, TRI, RBI); 1005 } 1006 1007 bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const { 1008 // InstructionSelector walks backwards through the instructions. For an 1009 // explicit conditional branch with no fallthrough, we use both a G_BR and a 1010 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and 1011 // generate the OpBranchConditional in selectBranch above. 1012 // 1013 // If an OpBranchConditional has been generated, we simply return, as the work 1014 // is alread done. If there is no OpBranchConditional, LLVM must be relying on 1015 // implicit fallthrough to the next basic block, so we need to create an 1016 // OpBranchConditional with an explicit "false" argument pointing to the next 1017 // basic block that LLVM would fall through to. 1018 const MachineInstr *NextI = I.getNextNode(); 1019 // Check if this has already been successfully selected. 1020 if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional) 1021 return true; 1022 // Must be relying on implicit block fallthrough, so generate an 1023 // OpBranchConditional with the "next" basic block as the "false" target. 1024 MachineBasicBlock &MBB = *I.getParent(); 1025 unsigned NextMBBNum = MBB.getNextNode()->getNumber(); 1026 MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum); 1027 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional)) 1028 .addUse(I.getOperand(0).getReg()) 1029 .addMBB(I.getOperand(1).getMBB()) 1030 .addMBB(NextMBB) 1031 .constrainAllUses(TII, TRI, RBI); 1032 } 1033 1034 bool SPIRVInstructionSelector::selectPhi(Register ResVReg, 1035 const SPIRVType *ResType, 1036 MachineInstr &I) const { 1037 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpPhi)) 1038 .addDef(ResVReg) 1039 .addUse(GR.getSPIRVTypeID(ResType)); 1040 const unsigned NumOps = I.getNumOperands(); 1041 for (unsigned i = 1; i < NumOps; i += 2) { 1042 MIB.addUse(I.getOperand(i + 0).getReg()); 1043 MIB.addMBB(I.getOperand(i + 1).getMBB()); 1044 } 1045 return MIB.constrainAllUses(TII, TRI, RBI); 1046 } 1047 1048 bool SPIRVInstructionSelector::selectGlobalValue( 1049 Register ResVReg, MachineInstr &I, const MachineInstr *Init) const { 1050 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI. 1051 MachineIRBuilder MIRBuilder(I); 1052 const GlobalValue *GV = I.getOperand(1).getGlobal(); 1053 SPIRVType *ResType = GR.getOrCreateSPIRVType( 1054 GV->getType(), MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false); 1055 1056 std::string GlobalIdent = GV->getGlobalIdentifier(); 1057 // TODO: suport @llvm.global.annotations. 1058 auto GlobalVar = cast<GlobalVariable>(GV); 1059 1060 bool HasInit = GlobalVar->hasInitializer() && 1061 !isa<UndefValue>(GlobalVar->getInitializer()); 1062 // Skip empty declaration for GVs with initilaizers till we get the decl with 1063 // passed initializer. 1064 if (HasInit && !Init) 1065 return true; 1066 1067 unsigned AddrSpace = GV->getAddressSpace(); 1068 SPIRV::StorageClass Storage = addressSpaceToStorageClass(AddrSpace); 1069 bool HasLnkTy = GV->getLinkage() != GlobalValue::InternalLinkage && 1070 Storage != SPIRV::StorageClass::Function; 1071 SPIRV::LinkageType LnkType = 1072 (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) 1073 ? SPIRV::LinkageType::Import 1074 : SPIRV::LinkageType::Export; 1075 1076 Register Reg = GR.buildGlobalVariable(ResVReg, ResType, GlobalIdent, GV, 1077 Storage, Init, GlobalVar->isConstant(), 1078 HasLnkTy, LnkType, MIRBuilder, true); 1079 return Reg.isValid(); 1080 } 1081 1082 namespace llvm { 1083 InstructionSelector * 1084 createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, 1085 const SPIRVSubtarget &Subtarget, 1086 const RegisterBankInfo &RBI) { 1087 return new SPIRVInstructionSelector(TM, Subtarget, RBI); 1088 } 1089 } // namespace llvm 1090