1 //===-- SPIRVEmitIntrinsics.cpp - emit SPIRV intrinsics ---------*- 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 // The pass emits SPIRV intrinsics keeping essential high-level information for 10 // the translation of LLVM IR to SPIR-V. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "SPIRV.h" 15 #include "SPIRVTargetMachine.h" 16 #include "SPIRVUtils.h" 17 #include "llvm/IR/IRBuilder.h" 18 #include "llvm/IR/InstIterator.h" 19 #include "llvm/IR/InstVisitor.h" 20 #include "llvm/IR/IntrinsicsSPIRV.h" 21 22 #include <queue> 23 24 // This pass performs the following transformation on LLVM IR level required 25 // for the following translation to SPIR-V: 26 // - replaces direct usages of aggregate constants with target-specific 27 // intrinsics; 28 // - replaces aggregates-related instructions (extract/insert, ld/st, etc) 29 // with a target-specific intrinsics; 30 // - emits intrinsics for the global variable initializers since IRTranslator 31 // doesn't handle them and it's not very convenient to translate them 32 // ourselves; 33 // - emits intrinsics to keep track of the string names assigned to the values; 34 // - emits intrinsics to keep track of constants (this is necessary to have an 35 // LLVM IR constant after the IRTranslation is completed) for their further 36 // deduplication; 37 // - emits intrinsics to keep track of original LLVM types of the values 38 // to be able to emit proper SPIR-V types eventually. 39 // 40 // TODO: consider removing spv.track.constant in favor of spv.assign.type. 41 42 using namespace llvm; 43 44 namespace llvm { 45 void initializeSPIRVEmitIntrinsicsPass(PassRegistry &); 46 } // namespace llvm 47 48 namespace { 49 class SPIRVEmitIntrinsics 50 : public FunctionPass, 51 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> { 52 SPIRVTargetMachine *TM = nullptr; 53 IRBuilder<> *IRB = nullptr; 54 Function *F = nullptr; 55 bool TrackConstants = true; 56 DenseMap<Instruction *, Constant *> AggrConsts; 57 DenseSet<Instruction *> AggrStores; 58 void preprocessCompositeConstants(); 59 void preprocessUndefs(); 60 CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types, 61 Value *Arg, Value *Arg2, 62 ArrayRef<Constant *> Imms) { 63 ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg); 64 MDTuple *TyMD = MDNode::get(F->getContext(), CM); 65 MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD); 66 SmallVector<Value *, 4> Args; 67 Args.push_back(Arg2); 68 Args.push_back(VMD); 69 for (auto *Imm : Imms) 70 Args.push_back(Imm); 71 return IRB->CreateIntrinsic(IntrID, {Types}, Args); 72 } 73 void replaceMemInstrUses(Instruction *Old, Instruction *New); 74 void processInstrAfterVisit(Instruction *I); 75 void insertAssignPtrTypeIntrs(Instruction *I); 76 void insertAssignTypeIntrs(Instruction *I); 77 void insertPtrCastInstr(Instruction *I); 78 void processGlobalValue(GlobalVariable &GV); 79 80 public: 81 static char ID; 82 SPIRVEmitIntrinsics() : FunctionPass(ID) { 83 initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 84 } 85 SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : FunctionPass(ID), TM(_TM) { 86 initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 87 } 88 Instruction *visitInstruction(Instruction &I) { return &I; } 89 Instruction *visitSwitchInst(SwitchInst &I); 90 Instruction *visitGetElementPtrInst(GetElementPtrInst &I); 91 Instruction *visitBitCastInst(BitCastInst &I); 92 Instruction *visitInsertElementInst(InsertElementInst &I); 93 Instruction *visitExtractElementInst(ExtractElementInst &I); 94 Instruction *visitInsertValueInst(InsertValueInst &I); 95 Instruction *visitExtractValueInst(ExtractValueInst &I); 96 Instruction *visitLoadInst(LoadInst &I); 97 Instruction *visitStoreInst(StoreInst &I); 98 Instruction *visitAllocaInst(AllocaInst &I); 99 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); 100 Instruction *visitUnreachableInst(UnreachableInst &I); 101 bool runOnFunction(Function &F) override; 102 }; 103 } // namespace 104 105 char SPIRVEmitIntrinsics::ID = 0; 106 107 INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics", 108 false, false) 109 110 static inline bool isAssignTypeInstr(const Instruction *I) { 111 return isa<IntrinsicInst>(I) && 112 cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type; 113 } 114 115 static bool isMemInstrToReplace(Instruction *I) { 116 return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) || 117 isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I); 118 } 119 120 static bool isAggrToReplace(const Value *V) { 121 return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) || 122 (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()); 123 } 124 125 static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) { 126 if (isa<PHINode>(I)) 127 B.SetInsertPoint(I->getParent(), I->getParent()->getFirstInsertionPt()); 128 else 129 B.SetInsertPoint(I); 130 } 131 132 static bool requireAssignPtrType(Instruction *I) { 133 if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I)) 134 return true; 135 136 return false; 137 } 138 139 static bool requireAssignType(Instruction *I) { 140 IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I); 141 if (Intr) { 142 switch (Intr->getIntrinsicID()) { 143 case Intrinsic::invariant_start: 144 case Intrinsic::invariant_end: 145 return false; 146 } 147 } 148 return true; 149 } 150 151 void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old, 152 Instruction *New) { 153 while (!Old->user_empty()) { 154 auto *U = Old->user_back(); 155 if (isAssignTypeInstr(U)) { 156 IRB->SetInsertPoint(U); 157 SmallVector<Value *, 2> Args = {New, U->getOperand(1)}; 158 IRB->CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args); 159 U->eraseFromParent(); 160 } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) || 161 isa<CallInst>(U)) { 162 U->replaceUsesOfWith(Old, New); 163 } else { 164 llvm_unreachable("illegal aggregate intrinsic user"); 165 } 166 } 167 Old->eraseFromParent(); 168 } 169 170 void SPIRVEmitIntrinsics::preprocessUndefs() { 171 std::queue<Instruction *> Worklist; 172 for (auto &I : instructions(F)) 173 Worklist.push(&I); 174 175 while (!Worklist.empty()) { 176 Instruction *I = Worklist.front(); 177 Worklist.pop(); 178 179 for (auto &Op : I->operands()) { 180 auto *AggrUndef = dyn_cast<UndefValue>(Op); 181 if (!AggrUndef || !Op->getType()->isAggregateType()) 182 continue; 183 184 IRB->SetInsertPoint(I); 185 auto *IntrUndef = IRB->CreateIntrinsic(Intrinsic::spv_undef, {}, {}); 186 Worklist.push(IntrUndef); 187 I->replaceUsesOfWith(Op, IntrUndef); 188 AggrConsts[IntrUndef] = AggrUndef; 189 } 190 } 191 } 192 193 void SPIRVEmitIntrinsics::preprocessCompositeConstants() { 194 std::queue<Instruction *> Worklist; 195 for (auto &I : instructions(F)) 196 Worklist.push(&I); 197 198 while (!Worklist.empty()) { 199 auto *I = Worklist.front(); 200 assert(I); 201 bool KeepInst = false; 202 for (const auto &Op : I->operands()) { 203 auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &I, &Op, 204 this](Constant *AggrC, 205 ArrayRef<Value *> Args) { 206 IRB->SetInsertPoint(I); 207 auto *CCI = 208 IRB->CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args}); 209 Worklist.push(CCI); 210 I->replaceUsesOfWith(Op, CCI); 211 KeepInst = true; 212 AggrConsts[CCI] = AggrC; 213 }; 214 215 if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) { 216 SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 217 BuildCompositeIntrinsic(AggrC, Args); 218 } else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) { 219 SmallVector<Value *> Args; 220 for (unsigned i = 0; i < AggrC->getNumElements(); ++i) 221 Args.push_back(AggrC->getElementAsConstant(i)); 222 BuildCompositeIntrinsic(AggrC, Args); 223 } else if (isa<ConstantAggregateZero>(Op) && 224 !Op->getType()->isVectorTy()) { 225 auto *AggrC = cast<ConstantAggregateZero>(Op); 226 SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 227 BuildCompositeIntrinsic(AggrC, Args); 228 } 229 } 230 if (!KeepInst) 231 Worklist.pop(); 232 } 233 } 234 235 Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) { 236 SmallVector<Value *, 4> Args; 237 for (auto &Op : I.operands()) 238 if (Op.get()->getType()->isSized()) 239 Args.push_back(Op); 240 IRB->SetInsertPoint(&I); 241 IRB->CreateIntrinsic(Intrinsic::spv_switch, {I.getOperand(0)->getType()}, 242 {Args}); 243 return &I; 244 } 245 246 Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) { 247 SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 248 SmallVector<Value *, 4> Args; 249 Args.push_back(IRB->getInt1(I.isInBounds())); 250 for (auto &Op : I.operands()) 251 Args.push_back(Op); 252 auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args}); 253 I.replaceAllUsesWith(NewI); 254 I.eraseFromParent(); 255 return NewI; 256 } 257 258 Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) { 259 Value *Source = I.getOperand(0); 260 261 // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of 262 // varying element types. In case of IR coming from older versions of LLVM 263 // such bitcasts do not provide sufficient information, should be just skipped 264 // here, and handled in insertPtrCastInstr. 265 if (I.getType()->isPointerTy()) { 266 I.replaceAllUsesWith(Source); 267 I.eraseFromParent(); 268 return nullptr; 269 } 270 271 SmallVector<Type *, 2> Types = {I.getType(), Source->getType()}; 272 SmallVector<Value *> Args(I.op_begin(), I.op_end()); 273 auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args}); 274 std::string InstName = I.hasName() ? I.getName().str() : ""; 275 I.replaceAllUsesWith(NewI); 276 I.eraseFromParent(); 277 NewI->setName(InstName); 278 return NewI; 279 } 280 281 void SPIRVEmitIntrinsics::insertPtrCastInstr(Instruction *I) { 282 Value *Pointer; 283 Type *ExpectedElementType; 284 unsigned OperandToReplace; 285 if (StoreInst *SI = dyn_cast<StoreInst>(I)) { 286 Pointer = SI->getPointerOperand(); 287 ExpectedElementType = SI->getValueOperand()->getType(); 288 OperandToReplace = 1; 289 } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) { 290 Pointer = LI->getPointerOperand(); 291 ExpectedElementType = LI->getType(); 292 OperandToReplace = 0; 293 } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) { 294 Pointer = GEPI->getPointerOperand(); 295 ExpectedElementType = GEPI->getSourceElementType(); 296 OperandToReplace = 0; 297 } else { 298 return; 299 } 300 301 // If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source 302 // pointer instead. The BitCastInst should be later removed when visited. 303 while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer)) 304 Pointer = BC->getOperand(0); 305 306 // Do not emit spv_ptrcast if Pointer is a GlobalValue of expected type. 307 GlobalValue *GV = dyn_cast<GlobalValue>(Pointer); 308 if (GV && GV->getValueType() == ExpectedElementType) 309 return; 310 311 // Do not emit spv_ptrcast if Pointer is a result of alloca with expected 312 // type. 313 AllocaInst *A = dyn_cast<AllocaInst>(Pointer); 314 if (A && A->getAllocatedType() == ExpectedElementType) 315 return; 316 317 if (dyn_cast<GetElementPtrInst>(Pointer)) 318 return; 319 320 setInsertPointSkippingPhis(*IRB, I); 321 Constant *ExpectedElementTypeConst = 322 Constant::getNullValue(ExpectedElementType); 323 ConstantAsMetadata *CM = 324 ValueAsMetadata::getConstant(ExpectedElementTypeConst); 325 MDTuple *TyMD = MDNode::get(F->getContext(), CM); 326 MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD); 327 unsigned AddressSpace = Pointer->getType()->getPointerAddressSpace(); 328 bool FirstPtrCastOrAssignPtrType = true; 329 330 // Do not emit new spv_ptrcast if equivalent one already exists or when 331 // spv_assign_ptr_type already targets this pointer with the same element 332 // type. 333 for (auto User : Pointer->users()) { 334 auto *II = dyn_cast<IntrinsicInst>(User); 335 if (!II || 336 (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type && 337 II->getIntrinsicID() != Intrinsic::spv_ptrcast) || 338 II->getOperand(0) != Pointer) 339 continue; 340 341 // There is some spv_ptrcast/spv_assign_ptr_type already targeting this 342 // pointer. 343 FirstPtrCastOrAssignPtrType = false; 344 if (II->getOperand(1) != VMD || 345 dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() != 346 AddressSpace) 347 continue; 348 349 // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the same 350 // element type and address space. 351 if (II->getIntrinsicID() != Intrinsic::spv_ptrcast) 352 return; 353 354 // This must be a spv_ptrcast, do not emit new if this one has the same BB 355 // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type. 356 if (II->getParent() != I->getParent()) 357 continue; 358 359 I->setOperand(OperandToReplace, II); 360 return; 361 } 362 363 // Do not emit spv_ptrcast if it would cast to the default pointer element 364 // type (i8) of the same address space. 365 if (ExpectedElementType->isIntegerTy(8)) 366 return; 367 368 // If this would be the first spv_ptrcast and there is no spv_assign_ptr_type 369 // for this pointer before, do not emit spv_ptrcast but emit 370 // spv_assign_ptr_type instead. 371 if (FirstPtrCastOrAssignPtrType && isa<Instruction>(Pointer)) { 372 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {Pointer->getType()}, 373 ExpectedElementTypeConst, Pointer, 374 {IRB->getInt32(AddressSpace)}); 375 return; 376 } else { 377 SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()}; 378 SmallVector<Value *, 2> Args = {Pointer, VMD, IRB->getInt32(AddressSpace)}; 379 auto *PtrCastI = 380 IRB->CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args); 381 I->setOperand(OperandToReplace, PtrCastI); 382 return; 383 } 384 } 385 386 Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) { 387 SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(), 388 I.getOperand(1)->getType(), 389 I.getOperand(2)->getType()}; 390 SmallVector<Value *> Args(I.op_begin(), I.op_end()); 391 auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args}); 392 std::string InstName = I.hasName() ? I.getName().str() : ""; 393 I.replaceAllUsesWith(NewI); 394 I.eraseFromParent(); 395 NewI->setName(InstName); 396 return NewI; 397 } 398 399 Instruction * 400 SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) { 401 SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(), 402 I.getIndexOperand()->getType()}; 403 SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()}; 404 auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args}); 405 std::string InstName = I.hasName() ? I.getName().str() : ""; 406 I.replaceAllUsesWith(NewI); 407 I.eraseFromParent(); 408 NewI->setName(InstName); 409 return NewI; 410 } 411 412 Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) { 413 SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()}; 414 SmallVector<Value *> Args; 415 for (auto &Op : I.operands()) 416 if (isa<UndefValue>(Op)) 417 Args.push_back(UndefValue::get(IRB->getInt32Ty())); 418 else 419 Args.push_back(Op); 420 for (auto &Op : I.indices()) 421 Args.push_back(IRB->getInt32(Op)); 422 Instruction *NewI = 423 IRB->CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args}); 424 replaceMemInstrUses(&I, NewI); 425 return NewI; 426 } 427 428 Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) { 429 SmallVector<Value *> Args; 430 for (auto &Op : I.operands()) 431 Args.push_back(Op); 432 for (auto &Op : I.indices()) 433 Args.push_back(IRB->getInt32(Op)); 434 auto *NewI = 435 IRB->CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args}); 436 I.replaceAllUsesWith(NewI); 437 I.eraseFromParent(); 438 return NewI; 439 } 440 441 Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) { 442 if (!I.getType()->isAggregateType()) 443 return &I; 444 TrackConstants = false; 445 const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 446 MachineMemOperand::Flags Flags = 447 TLI->getLoadMemOperandFlags(I, F->getParent()->getDataLayout()); 448 auto *NewI = 449 IRB->CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()}, 450 {I.getPointerOperand(), IRB->getInt16(Flags), 451 IRB->getInt8(I.getAlign().value())}); 452 replaceMemInstrUses(&I, NewI); 453 return NewI; 454 } 455 456 Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) { 457 if (!AggrStores.contains(&I)) 458 return &I; 459 TrackConstants = false; 460 const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 461 MachineMemOperand::Flags Flags = 462 TLI->getStoreMemOperandFlags(I, F->getParent()->getDataLayout()); 463 auto *PtrOp = I.getPointerOperand(); 464 auto *NewI = IRB->CreateIntrinsic( 465 Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()}, 466 {I.getValueOperand(), PtrOp, IRB->getInt16(Flags), 467 IRB->getInt8(I.getAlign().value())}); 468 I.eraseFromParent(); 469 return NewI; 470 } 471 472 Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) { 473 TrackConstants = false; 474 Type *PtrTy = I.getType(); 475 auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {}); 476 std::string InstName = I.hasName() ? I.getName().str() : ""; 477 I.replaceAllUsesWith(NewI); 478 I.eraseFromParent(); 479 NewI->setName(InstName); 480 return NewI; 481 } 482 483 Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { 484 assert(I.getType()->isAggregateType() && "Aggregate result is expected"); 485 SmallVector<Value *> Args; 486 for (auto &Op : I.operands()) 487 Args.push_back(Op); 488 Args.push_back(IRB->getInt32(I.getSyncScopeID())); 489 Args.push_back(IRB->getInt32( 490 static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering())))); 491 Args.push_back(IRB->getInt32( 492 static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering())))); 493 auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_cmpxchg, 494 {I.getPointerOperand()->getType()}, {Args}); 495 replaceMemInstrUses(&I, NewI); 496 return NewI; 497 } 498 499 Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) { 500 IRB->SetInsertPoint(&I); 501 IRB->CreateIntrinsic(Intrinsic::spv_unreachable, {}, {}); 502 return &I; 503 } 504 505 void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) { 506 // Skip special artifical variable llvm.global.annotations. 507 if (GV.getName() == "llvm.global.annotations") 508 return; 509 if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) { 510 Constant *Init = GV.getInitializer(); 511 Type *Ty = isAggrToReplace(Init) ? IRB->getInt32Ty() : Init->getType(); 512 Constant *Const = isAggrToReplace(Init) ? IRB->getInt32(1) : Init; 513 auto *InitInst = IRB->CreateIntrinsic(Intrinsic::spv_init_global, 514 {GV.getType(), Ty}, {&GV, Const}); 515 InitInst->setArgOperand(1, Init); 516 } 517 if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) && 518 GV.getNumUses() == 0) 519 IRB->CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV); 520 } 521 522 void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I) { 523 if (I->getType()->isVoidTy() || !requireAssignPtrType(I)) 524 return; 525 526 setInsertPointSkippingPhis(*IRB, I->getNextNode()); 527 528 Constant *EltTyConst; 529 unsigned AddressSpace = 0; 530 if (auto *AI = dyn_cast<AllocaInst>(I)) { 531 EltTyConst = UndefValue::get(AI->getAllocatedType()); 532 AddressSpace = AI->getAddressSpace(); 533 } else if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) { 534 EltTyConst = UndefValue::get(GEP->getResultElementType()); 535 AddressSpace = GEP->getPointerAddressSpace(); 536 } else { 537 llvm_unreachable("Unexpected instruction!"); 538 } 539 540 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {I->getType()}, EltTyConst, I, 541 {IRB->getInt32(AddressSpace)}); 542 } 543 544 void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) { 545 Type *Ty = I->getType(); 546 if (!Ty->isVoidTy() && requireAssignType(I) && !requireAssignPtrType(I)) { 547 setInsertPointSkippingPhis(*IRB, I->getNextNode()); 548 Type *TypeToAssign = Ty; 549 if (auto *II = dyn_cast<IntrinsicInst>(I)) { 550 if (II->getIntrinsicID() == Intrinsic::spv_const_composite || 551 II->getIntrinsicID() == Intrinsic::spv_undef) { 552 auto t = AggrConsts.find(II); 553 assert(t != AggrConsts.end()); 554 TypeToAssign = t->second->getType(); 555 } 556 } 557 Constant *Const = UndefValue::get(TypeToAssign); 558 buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I, {}); 559 } 560 for (const auto &Op : I->operands()) { 561 if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) || 562 // Check GetElementPtrConstantExpr case. 563 (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) { 564 setInsertPointSkippingPhis(*IRB, I); 565 if (isa<UndefValue>(Op) && Op->getType()->isAggregateType()) 566 buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op, 567 UndefValue::get(IRB->getInt32Ty()), {}); 568 else 569 buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op, 570 {}); 571 } 572 } 573 } 574 575 void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) { 576 auto *II = dyn_cast<IntrinsicInst>(I); 577 if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite && 578 TrackConstants) { 579 IRB->SetInsertPoint(I->getNextNode()); 580 Type *Ty = IRB->getInt32Ty(); 581 auto t = AggrConsts.find(I); 582 assert(t != AggrConsts.end()); 583 auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, 584 t->second, I, {}); 585 I->replaceAllUsesWith(NewOp); 586 NewOp->setArgOperand(0, I); 587 } 588 for (const auto &Op : I->operands()) { 589 if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) || 590 isa<PHINode>(I) || isa<SwitchInst>(I)) 591 TrackConstants = false; 592 if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) { 593 unsigned OpNo = Op.getOperandNo(); 594 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) || 595 (II->paramHasAttr(OpNo, Attribute::ImmArg)))) 596 continue; 597 IRB->SetInsertPoint(I); 598 auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, 599 {Op->getType(), Op->getType()}, Op, Op, {}); 600 I->setOperand(OpNo, NewOp); 601 } 602 } 603 if (I->hasName()) { 604 setInsertPointSkippingPhis(*IRB, I->getNextNode()); 605 std::vector<Value *> Args = {I}; 606 addStringImm(I->getName(), *IRB, Args); 607 IRB->CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args); 608 } 609 } 610 611 bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { 612 if (Func.isDeclaration()) 613 return false; 614 F = &Func; 615 IRB = new IRBuilder<>(Func.getContext()); 616 AggrConsts.clear(); 617 AggrStores.clear(); 618 619 // StoreInst's operand type can be changed during the next transformations, 620 // so we need to store it in the set. Also store already transformed types. 621 for (auto &I : instructions(Func)) { 622 StoreInst *SI = dyn_cast<StoreInst>(&I); 623 if (!SI) 624 continue; 625 Type *ElTy = SI->getValueOperand()->getType(); 626 if (ElTy->isAggregateType() || ElTy->isVectorTy()) 627 AggrStores.insert(&I); 628 } 629 630 IRB->SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin()); 631 for (auto &GV : Func.getParent()->globals()) 632 processGlobalValue(GV); 633 634 preprocessUndefs(); 635 preprocessCompositeConstants(); 636 SmallVector<Instruction *> Worklist; 637 for (auto &I : instructions(Func)) 638 Worklist.push_back(&I); 639 640 for (auto &I : Worklist) { 641 insertAssignPtrTypeIntrs(I); 642 insertAssignTypeIntrs(I); 643 insertPtrCastInstr(I); 644 } 645 646 for (auto *I : Worklist) { 647 TrackConstants = true; 648 if (!I->getType()->isVoidTy() || isa<StoreInst>(I)) 649 IRB->SetInsertPoint(I->getNextNode()); 650 // Visitors return either the original/newly created instruction for further 651 // processing, nullptr otherwise. 652 I = visit(*I); 653 if (!I) 654 continue; 655 processInstrAfterVisit(I); 656 } 657 return true; 658 } 659 660 FunctionPass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) { 661 return new SPIRVEmitIntrinsics(TM); 662 } 663