181ad6265SDimitry Andric //===-- SPIRVEmitIntrinsics.cpp - emit SPIRV intrinsics ---------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // The pass emits SPIRV intrinsics keeping essential high-level information for 1081ad6265SDimitry Andric // the translation of LLVM IR to SPIR-V. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include "SPIRV.h" 1581ad6265SDimitry Andric #include "SPIRVTargetMachine.h" 1681ad6265SDimitry Andric #include "SPIRVUtils.h" 1781ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h" 1881ad6265SDimitry Andric #include "llvm/IR/InstIterator.h" 1981ad6265SDimitry Andric #include "llvm/IR/InstVisitor.h" 2081ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h" 2181ad6265SDimitry Andric 2281ad6265SDimitry Andric #include <queue> 2381ad6265SDimitry Andric 2481ad6265SDimitry Andric // This pass performs the following transformation on LLVM IR level required 2581ad6265SDimitry Andric // for the following translation to SPIR-V: 2681ad6265SDimitry Andric // - replaces direct usages of aggregate constants with target-specific 2781ad6265SDimitry Andric // intrinsics; 2881ad6265SDimitry Andric // - replaces aggregates-related instructions (extract/insert, ld/st, etc) 2981ad6265SDimitry Andric // with a target-specific intrinsics; 3081ad6265SDimitry Andric // - emits intrinsics for the global variable initializers since IRTranslator 3181ad6265SDimitry Andric // doesn't handle them and it's not very convenient to translate them 3281ad6265SDimitry Andric // ourselves; 3381ad6265SDimitry Andric // - emits intrinsics to keep track of the string names assigned to the values; 3481ad6265SDimitry Andric // - emits intrinsics to keep track of constants (this is necessary to have an 3581ad6265SDimitry Andric // LLVM IR constant after the IRTranslation is completed) for their further 3681ad6265SDimitry Andric // deduplication; 3781ad6265SDimitry Andric // - emits intrinsics to keep track of original LLVM types of the values 3881ad6265SDimitry Andric // to be able to emit proper SPIR-V types eventually. 3981ad6265SDimitry Andric // 4081ad6265SDimitry Andric // TODO: consider removing spv.track.constant in favor of spv.assign.type. 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric using namespace llvm; 4381ad6265SDimitry Andric 4481ad6265SDimitry Andric namespace llvm { 4581ad6265SDimitry Andric void initializeSPIRVEmitIntrinsicsPass(PassRegistry &); 4681ad6265SDimitry Andric } // namespace llvm 4781ad6265SDimitry Andric 4881ad6265SDimitry Andric namespace { 4981ad6265SDimitry Andric class SPIRVEmitIntrinsics 5081ad6265SDimitry Andric : public FunctionPass, 5181ad6265SDimitry Andric public InstVisitor<SPIRVEmitIntrinsics, Instruction *> { 5281ad6265SDimitry Andric SPIRVTargetMachine *TM = nullptr; 5381ad6265SDimitry Andric IRBuilder<> *IRB = nullptr; 5481ad6265SDimitry Andric Function *F = nullptr; 5581ad6265SDimitry Andric bool TrackConstants = true; 5681ad6265SDimitry Andric DenseMap<Instruction *, Constant *> AggrConsts; 5781ad6265SDimitry Andric DenseSet<Instruction *> AggrStores; 5881ad6265SDimitry Andric void preprocessCompositeConstants(); 5906c3fb27SDimitry Andric void preprocessUndefs(); 6081ad6265SDimitry Andric CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types, 615f757f3fSDimitry Andric Value *Arg, Value *Arg2, 625f757f3fSDimitry Andric ArrayRef<Constant *> Imms) { 6381ad6265SDimitry Andric ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg); 6481ad6265SDimitry Andric MDTuple *TyMD = MDNode::get(F->getContext(), CM); 6581ad6265SDimitry Andric MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD); 665f757f3fSDimitry Andric SmallVector<Value *, 4> Args; 675f757f3fSDimitry Andric Args.push_back(Arg2); 685f757f3fSDimitry Andric Args.push_back(VMD); 695f757f3fSDimitry Andric for (auto *Imm : Imms) 705f757f3fSDimitry Andric Args.push_back(Imm); 715f757f3fSDimitry Andric return IRB->CreateIntrinsic(IntrID, {Types}, Args); 7281ad6265SDimitry Andric } 7381ad6265SDimitry Andric void replaceMemInstrUses(Instruction *Old, Instruction *New); 7481ad6265SDimitry Andric void processInstrAfterVisit(Instruction *I); 755f757f3fSDimitry Andric void insertAssignPtrTypeIntrs(Instruction *I); 7681ad6265SDimitry Andric void insertAssignTypeIntrs(Instruction *I); 77*1db9f3b2SDimitry Andric void insertPtrCastInstr(Instruction *I); 7881ad6265SDimitry Andric void processGlobalValue(GlobalVariable &GV); 7981ad6265SDimitry Andric 8081ad6265SDimitry Andric public: 8181ad6265SDimitry Andric static char ID; 8281ad6265SDimitry Andric SPIRVEmitIntrinsics() : FunctionPass(ID) { 8381ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 8481ad6265SDimitry Andric } 8581ad6265SDimitry Andric SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : FunctionPass(ID), TM(_TM) { 8681ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 8781ad6265SDimitry Andric } 8881ad6265SDimitry Andric Instruction *visitInstruction(Instruction &I) { return &I; } 8981ad6265SDimitry Andric Instruction *visitSwitchInst(SwitchInst &I); 9081ad6265SDimitry Andric Instruction *visitGetElementPtrInst(GetElementPtrInst &I); 9181ad6265SDimitry Andric Instruction *visitBitCastInst(BitCastInst &I); 9281ad6265SDimitry Andric Instruction *visitInsertElementInst(InsertElementInst &I); 9381ad6265SDimitry Andric Instruction *visitExtractElementInst(ExtractElementInst &I); 9481ad6265SDimitry Andric Instruction *visitInsertValueInst(InsertValueInst &I); 9581ad6265SDimitry Andric Instruction *visitExtractValueInst(ExtractValueInst &I); 9681ad6265SDimitry Andric Instruction *visitLoadInst(LoadInst &I); 9781ad6265SDimitry Andric Instruction *visitStoreInst(StoreInst &I); 9881ad6265SDimitry Andric Instruction *visitAllocaInst(AllocaInst &I); 99fcaf7f86SDimitry Andric Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); 100bdd1243dSDimitry Andric Instruction *visitUnreachableInst(UnreachableInst &I); 10181ad6265SDimitry Andric bool runOnFunction(Function &F) override; 10281ad6265SDimitry Andric }; 10381ad6265SDimitry Andric } // namespace 10481ad6265SDimitry Andric 10581ad6265SDimitry Andric char SPIRVEmitIntrinsics::ID = 0; 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics", 10881ad6265SDimitry Andric false, false) 10981ad6265SDimitry Andric 11081ad6265SDimitry Andric static inline bool isAssignTypeInstr(const Instruction *I) { 11181ad6265SDimitry Andric return isa<IntrinsicInst>(I) && 11281ad6265SDimitry Andric cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type; 11381ad6265SDimitry Andric } 11481ad6265SDimitry Andric 11581ad6265SDimitry Andric static bool isMemInstrToReplace(Instruction *I) { 11681ad6265SDimitry Andric return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) || 117fcaf7f86SDimitry Andric isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I); 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric 12081ad6265SDimitry Andric static bool isAggrToReplace(const Value *V) { 12181ad6265SDimitry Andric return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) || 12281ad6265SDimitry Andric (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()); 12381ad6265SDimitry Andric } 12481ad6265SDimitry Andric 12581ad6265SDimitry Andric static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) { 12681ad6265SDimitry Andric if (isa<PHINode>(I)) 12781ad6265SDimitry Andric B.SetInsertPoint(I->getParent(), I->getParent()->getFirstInsertionPt()); 12881ad6265SDimitry Andric else 12981ad6265SDimitry Andric B.SetInsertPoint(I); 13081ad6265SDimitry Andric } 13181ad6265SDimitry Andric 1325f757f3fSDimitry Andric static bool requireAssignPtrType(Instruction *I) { 1335f757f3fSDimitry Andric if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I)) 1345f757f3fSDimitry Andric return true; 1355f757f3fSDimitry Andric 1365f757f3fSDimitry Andric return false; 1375f757f3fSDimitry Andric } 1385f757f3fSDimitry Andric 13981ad6265SDimitry Andric static bool requireAssignType(Instruction *I) { 14081ad6265SDimitry Andric IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I); 14181ad6265SDimitry Andric if (Intr) { 14281ad6265SDimitry Andric switch (Intr->getIntrinsicID()) { 14381ad6265SDimitry Andric case Intrinsic::invariant_start: 14481ad6265SDimitry Andric case Intrinsic::invariant_end: 14581ad6265SDimitry Andric return false; 14681ad6265SDimitry Andric } 14781ad6265SDimitry Andric } 14881ad6265SDimitry Andric return true; 14981ad6265SDimitry Andric } 15081ad6265SDimitry Andric 15181ad6265SDimitry Andric void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old, 15281ad6265SDimitry Andric Instruction *New) { 15381ad6265SDimitry Andric while (!Old->user_empty()) { 15481ad6265SDimitry Andric auto *U = Old->user_back(); 155fcaf7f86SDimitry Andric if (isAssignTypeInstr(U)) { 15681ad6265SDimitry Andric IRB->SetInsertPoint(U); 15781ad6265SDimitry Andric SmallVector<Value *, 2> Args = {New, U->getOperand(1)}; 15881ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args); 15981ad6265SDimitry Andric U->eraseFromParent(); 160fcaf7f86SDimitry Andric } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) || 161fcaf7f86SDimitry Andric isa<CallInst>(U)) { 162fcaf7f86SDimitry Andric U->replaceUsesOfWith(Old, New); 16381ad6265SDimitry Andric } else { 16481ad6265SDimitry Andric llvm_unreachable("illegal aggregate intrinsic user"); 16581ad6265SDimitry Andric } 16681ad6265SDimitry Andric } 16781ad6265SDimitry Andric Old->eraseFromParent(); 16881ad6265SDimitry Andric } 16981ad6265SDimitry Andric 17006c3fb27SDimitry Andric void SPIRVEmitIntrinsics::preprocessUndefs() { 17106c3fb27SDimitry Andric std::queue<Instruction *> Worklist; 17206c3fb27SDimitry Andric for (auto &I : instructions(F)) 17306c3fb27SDimitry Andric Worklist.push(&I); 17406c3fb27SDimitry Andric 17506c3fb27SDimitry Andric while (!Worklist.empty()) { 17606c3fb27SDimitry Andric Instruction *I = Worklist.front(); 17706c3fb27SDimitry Andric Worklist.pop(); 17806c3fb27SDimitry Andric 17906c3fb27SDimitry Andric for (auto &Op : I->operands()) { 18006c3fb27SDimitry Andric auto *AggrUndef = dyn_cast<UndefValue>(Op); 18106c3fb27SDimitry Andric if (!AggrUndef || !Op->getType()->isAggregateType()) 18206c3fb27SDimitry Andric continue; 18306c3fb27SDimitry Andric 18406c3fb27SDimitry Andric IRB->SetInsertPoint(I); 18506c3fb27SDimitry Andric auto *IntrUndef = IRB->CreateIntrinsic(Intrinsic::spv_undef, {}, {}); 18606c3fb27SDimitry Andric Worklist.push(IntrUndef); 18706c3fb27SDimitry Andric I->replaceUsesOfWith(Op, IntrUndef); 18806c3fb27SDimitry Andric AggrConsts[IntrUndef] = AggrUndef; 18906c3fb27SDimitry Andric } 19006c3fb27SDimitry Andric } 19106c3fb27SDimitry Andric } 19206c3fb27SDimitry Andric 19381ad6265SDimitry Andric void SPIRVEmitIntrinsics::preprocessCompositeConstants() { 19481ad6265SDimitry Andric std::queue<Instruction *> Worklist; 19581ad6265SDimitry Andric for (auto &I : instructions(F)) 19681ad6265SDimitry Andric Worklist.push(&I); 19781ad6265SDimitry Andric 19881ad6265SDimitry Andric while (!Worklist.empty()) { 19981ad6265SDimitry Andric auto *I = Worklist.front(); 20081ad6265SDimitry Andric assert(I); 20181ad6265SDimitry Andric bool KeepInst = false; 20281ad6265SDimitry Andric for (const auto &Op : I->operands()) { 20381ad6265SDimitry Andric auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &I, &Op, 20481ad6265SDimitry Andric this](Constant *AggrC, 20581ad6265SDimitry Andric ArrayRef<Value *> Args) { 20681ad6265SDimitry Andric IRB->SetInsertPoint(I); 20781ad6265SDimitry Andric auto *CCI = 20881ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args}); 20981ad6265SDimitry Andric Worklist.push(CCI); 21081ad6265SDimitry Andric I->replaceUsesOfWith(Op, CCI); 21181ad6265SDimitry Andric KeepInst = true; 21281ad6265SDimitry Andric AggrConsts[CCI] = AggrC; 21381ad6265SDimitry Andric }; 21481ad6265SDimitry Andric 21581ad6265SDimitry Andric if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) { 21681ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 21781ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 21881ad6265SDimitry Andric } else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) { 21981ad6265SDimitry Andric SmallVector<Value *> Args; 22081ad6265SDimitry Andric for (unsigned i = 0; i < AggrC->getNumElements(); ++i) 22181ad6265SDimitry Andric Args.push_back(AggrC->getElementAsConstant(i)); 22281ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 22381ad6265SDimitry Andric } else if (isa<ConstantAggregateZero>(Op) && 22481ad6265SDimitry Andric !Op->getType()->isVectorTy()) { 22581ad6265SDimitry Andric auto *AggrC = cast<ConstantAggregateZero>(Op); 22681ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 22781ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 22881ad6265SDimitry Andric } 22981ad6265SDimitry Andric } 23081ad6265SDimitry Andric if (!KeepInst) 23181ad6265SDimitry Andric Worklist.pop(); 23281ad6265SDimitry Andric } 23381ad6265SDimitry Andric } 23481ad6265SDimitry Andric 23581ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) { 23681ad6265SDimitry Andric SmallVector<Value *, 4> Args; 23781ad6265SDimitry Andric for (auto &Op : I.operands()) 23881ad6265SDimitry Andric if (Op.get()->getType()->isSized()) 23981ad6265SDimitry Andric Args.push_back(Op); 240bdd1243dSDimitry Andric IRB->SetInsertPoint(&I); 24181ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_switch, {I.getOperand(0)->getType()}, 24281ad6265SDimitry Andric {Args}); 24381ad6265SDimitry Andric return &I; 24481ad6265SDimitry Andric } 24581ad6265SDimitry Andric 24681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) { 24781ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 24881ad6265SDimitry Andric SmallVector<Value *, 4> Args; 24981ad6265SDimitry Andric Args.push_back(IRB->getInt1(I.isInBounds())); 25081ad6265SDimitry Andric for (auto &Op : I.operands()) 25181ad6265SDimitry Andric Args.push_back(Op); 25281ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args}); 25381ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 25481ad6265SDimitry Andric I.eraseFromParent(); 25581ad6265SDimitry Andric return NewI; 25681ad6265SDimitry Andric } 25781ad6265SDimitry Andric 25881ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) { 259*1db9f3b2SDimitry Andric Value *Source = I.getOperand(0); 260*1db9f3b2SDimitry Andric 261*1db9f3b2SDimitry Andric // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of 262*1db9f3b2SDimitry Andric // varying element types. In case of IR coming from older versions of LLVM 263*1db9f3b2SDimitry Andric // such bitcasts do not provide sufficient information, should be just skipped 264*1db9f3b2SDimitry Andric // here, and handled in insertPtrCastInstr. 265*1db9f3b2SDimitry Andric if (I.getType()->isPointerTy()) { 266*1db9f3b2SDimitry Andric I.replaceAllUsesWith(Source); 267*1db9f3b2SDimitry Andric I.eraseFromParent(); 268*1db9f3b2SDimitry Andric return nullptr; 269*1db9f3b2SDimitry Andric } 270*1db9f3b2SDimitry Andric 271*1db9f3b2SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), Source->getType()}; 27281ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 27381ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args}); 27481ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 27581ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 27681ad6265SDimitry Andric I.eraseFromParent(); 27781ad6265SDimitry Andric NewI->setName(InstName); 27881ad6265SDimitry Andric return NewI; 27981ad6265SDimitry Andric } 28081ad6265SDimitry Andric 281*1db9f3b2SDimitry Andric void SPIRVEmitIntrinsics::insertPtrCastInstr(Instruction *I) { 282*1db9f3b2SDimitry Andric Value *Pointer; 283*1db9f3b2SDimitry Andric Type *ExpectedElementType; 284*1db9f3b2SDimitry Andric unsigned OperandToReplace; 285*1db9f3b2SDimitry Andric if (StoreInst *SI = dyn_cast<StoreInst>(I)) { 286*1db9f3b2SDimitry Andric Pointer = SI->getPointerOperand(); 287*1db9f3b2SDimitry Andric ExpectedElementType = SI->getValueOperand()->getType(); 288*1db9f3b2SDimitry Andric OperandToReplace = 1; 289*1db9f3b2SDimitry Andric } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) { 290*1db9f3b2SDimitry Andric Pointer = LI->getPointerOperand(); 291*1db9f3b2SDimitry Andric ExpectedElementType = LI->getType(); 292*1db9f3b2SDimitry Andric OperandToReplace = 0; 293*1db9f3b2SDimitry Andric } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) { 294*1db9f3b2SDimitry Andric Pointer = GEPI->getPointerOperand(); 295*1db9f3b2SDimitry Andric ExpectedElementType = GEPI->getSourceElementType(); 296*1db9f3b2SDimitry Andric OperandToReplace = 0; 297*1db9f3b2SDimitry Andric } else { 298*1db9f3b2SDimitry Andric return; 299*1db9f3b2SDimitry Andric } 300*1db9f3b2SDimitry Andric 301*1db9f3b2SDimitry Andric // If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source 302*1db9f3b2SDimitry Andric // pointer instead. The BitCastInst should be later removed when visited. 303*1db9f3b2SDimitry Andric while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer)) 304*1db9f3b2SDimitry Andric Pointer = BC->getOperand(0); 305*1db9f3b2SDimitry Andric 306*1db9f3b2SDimitry Andric // Do not emit spv_ptrcast if Pointer is a GlobalValue of expected type. 307*1db9f3b2SDimitry Andric GlobalValue *GV = dyn_cast<GlobalValue>(Pointer); 308*1db9f3b2SDimitry Andric if (GV && GV->getValueType() == ExpectedElementType) 309*1db9f3b2SDimitry Andric return; 310*1db9f3b2SDimitry Andric 311*1db9f3b2SDimitry Andric // Do not emit spv_ptrcast if Pointer is a result of alloca with expected 312*1db9f3b2SDimitry Andric // type. 313*1db9f3b2SDimitry Andric AllocaInst *A = dyn_cast<AllocaInst>(Pointer); 314*1db9f3b2SDimitry Andric if (A && A->getAllocatedType() == ExpectedElementType) 315*1db9f3b2SDimitry Andric return; 316*1db9f3b2SDimitry Andric 317*1db9f3b2SDimitry Andric if (dyn_cast<GetElementPtrInst>(Pointer)) 318*1db9f3b2SDimitry Andric return; 319*1db9f3b2SDimitry Andric 320*1db9f3b2SDimitry Andric setInsertPointSkippingPhis(*IRB, I); 321*1db9f3b2SDimitry Andric Constant *ExpectedElementTypeConst = 322*1db9f3b2SDimitry Andric Constant::getNullValue(ExpectedElementType); 323*1db9f3b2SDimitry Andric ConstantAsMetadata *CM = 324*1db9f3b2SDimitry Andric ValueAsMetadata::getConstant(ExpectedElementTypeConst); 325*1db9f3b2SDimitry Andric MDTuple *TyMD = MDNode::get(F->getContext(), CM); 326*1db9f3b2SDimitry Andric MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD); 327*1db9f3b2SDimitry Andric unsigned AddressSpace = Pointer->getType()->getPointerAddressSpace(); 328*1db9f3b2SDimitry Andric bool FirstPtrCastOrAssignPtrType = true; 329*1db9f3b2SDimitry Andric 330*1db9f3b2SDimitry Andric // Do not emit new spv_ptrcast if equivalent one already exists or when 331*1db9f3b2SDimitry Andric // spv_assign_ptr_type already targets this pointer with the same element 332*1db9f3b2SDimitry Andric // type. 333*1db9f3b2SDimitry Andric for (auto User : Pointer->users()) { 334*1db9f3b2SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(User); 335*1db9f3b2SDimitry Andric if (!II || 336*1db9f3b2SDimitry Andric (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type && 337*1db9f3b2SDimitry Andric II->getIntrinsicID() != Intrinsic::spv_ptrcast) || 338*1db9f3b2SDimitry Andric II->getOperand(0) != Pointer) 339*1db9f3b2SDimitry Andric continue; 340*1db9f3b2SDimitry Andric 341*1db9f3b2SDimitry Andric // There is some spv_ptrcast/spv_assign_ptr_type already targeting this 342*1db9f3b2SDimitry Andric // pointer. 343*1db9f3b2SDimitry Andric FirstPtrCastOrAssignPtrType = false; 344*1db9f3b2SDimitry Andric if (II->getOperand(1) != VMD || 345*1db9f3b2SDimitry Andric dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() != 346*1db9f3b2SDimitry Andric AddressSpace) 347*1db9f3b2SDimitry Andric continue; 348*1db9f3b2SDimitry Andric 349*1db9f3b2SDimitry Andric // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the same 350*1db9f3b2SDimitry Andric // element type and address space. 351*1db9f3b2SDimitry Andric if (II->getIntrinsicID() != Intrinsic::spv_ptrcast) 352*1db9f3b2SDimitry Andric return; 353*1db9f3b2SDimitry Andric 354*1db9f3b2SDimitry Andric // This must be a spv_ptrcast, do not emit new if this one has the same BB 355*1db9f3b2SDimitry Andric // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type. 356*1db9f3b2SDimitry Andric if (II->getParent() != I->getParent()) 357*1db9f3b2SDimitry Andric continue; 358*1db9f3b2SDimitry Andric 359*1db9f3b2SDimitry Andric I->setOperand(OperandToReplace, II); 360*1db9f3b2SDimitry Andric return; 361*1db9f3b2SDimitry Andric } 362*1db9f3b2SDimitry Andric 363*1db9f3b2SDimitry Andric // Do not emit spv_ptrcast if it would cast to the default pointer element 364*1db9f3b2SDimitry Andric // type (i8) of the same address space. 365*1db9f3b2SDimitry Andric if (ExpectedElementType->isIntegerTy(8)) 366*1db9f3b2SDimitry Andric return; 367*1db9f3b2SDimitry Andric 368*1db9f3b2SDimitry Andric // If this would be the first spv_ptrcast and there is no spv_assign_ptr_type 369*1db9f3b2SDimitry Andric // for this pointer before, do not emit spv_ptrcast but emit 370*1db9f3b2SDimitry Andric // spv_assign_ptr_type instead. 371*1db9f3b2SDimitry Andric if (FirstPtrCastOrAssignPtrType && isa<Instruction>(Pointer)) { 372*1db9f3b2SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {Pointer->getType()}, 373*1db9f3b2SDimitry Andric ExpectedElementTypeConst, Pointer, 374*1db9f3b2SDimitry Andric {IRB->getInt32(AddressSpace)}); 375*1db9f3b2SDimitry Andric return; 376*1db9f3b2SDimitry Andric } else { 377*1db9f3b2SDimitry Andric SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()}; 378*1db9f3b2SDimitry Andric SmallVector<Value *, 2> Args = {Pointer, VMD, IRB->getInt32(AddressSpace)}; 379*1db9f3b2SDimitry Andric auto *PtrCastI = 380*1db9f3b2SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args); 381*1db9f3b2SDimitry Andric I->setOperand(OperandToReplace, PtrCastI); 382*1db9f3b2SDimitry Andric return; 383*1db9f3b2SDimitry Andric } 384*1db9f3b2SDimitry Andric } 385*1db9f3b2SDimitry Andric 38681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) { 38781ad6265SDimitry Andric SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(), 38881ad6265SDimitry Andric I.getOperand(1)->getType(), 38981ad6265SDimitry Andric I.getOperand(2)->getType()}; 39081ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 39181ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args}); 39281ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 39381ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 39481ad6265SDimitry Andric I.eraseFromParent(); 39581ad6265SDimitry Andric NewI->setName(InstName); 39681ad6265SDimitry Andric return NewI; 39781ad6265SDimitry Andric } 39881ad6265SDimitry Andric 39981ad6265SDimitry Andric Instruction * 40081ad6265SDimitry Andric SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) { 40181ad6265SDimitry Andric SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(), 40281ad6265SDimitry Andric I.getIndexOperand()->getType()}; 40381ad6265SDimitry Andric SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()}; 40481ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args}); 40581ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 40681ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 40781ad6265SDimitry Andric I.eraseFromParent(); 40881ad6265SDimitry Andric NewI->setName(InstName); 40981ad6265SDimitry Andric return NewI; 41081ad6265SDimitry Andric } 41181ad6265SDimitry Andric 41281ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) { 41381ad6265SDimitry Andric SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()}; 41481ad6265SDimitry Andric SmallVector<Value *> Args; 41581ad6265SDimitry Andric for (auto &Op : I.operands()) 41681ad6265SDimitry Andric if (isa<UndefValue>(Op)) 41781ad6265SDimitry Andric Args.push_back(UndefValue::get(IRB->getInt32Ty())); 41881ad6265SDimitry Andric else 41981ad6265SDimitry Andric Args.push_back(Op); 42081ad6265SDimitry Andric for (auto &Op : I.indices()) 42181ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 42281ad6265SDimitry Andric Instruction *NewI = 42381ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args}); 42481ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 42581ad6265SDimitry Andric return NewI; 42681ad6265SDimitry Andric } 42781ad6265SDimitry Andric 42881ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) { 42981ad6265SDimitry Andric SmallVector<Value *> Args; 43081ad6265SDimitry Andric for (auto &Op : I.operands()) 43181ad6265SDimitry Andric Args.push_back(Op); 43281ad6265SDimitry Andric for (auto &Op : I.indices()) 43381ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 43481ad6265SDimitry Andric auto *NewI = 43581ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args}); 43681ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 43781ad6265SDimitry Andric I.eraseFromParent(); 43881ad6265SDimitry Andric return NewI; 43981ad6265SDimitry Andric } 44081ad6265SDimitry Andric 44181ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) { 44281ad6265SDimitry Andric if (!I.getType()->isAggregateType()) 44381ad6265SDimitry Andric return &I; 44481ad6265SDimitry Andric TrackConstants = false; 44581ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 44681ad6265SDimitry Andric MachineMemOperand::Flags Flags = 44781ad6265SDimitry Andric TLI->getLoadMemOperandFlags(I, F->getParent()->getDataLayout()); 44881ad6265SDimitry Andric auto *NewI = 44981ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()}, 45081ad6265SDimitry Andric {I.getPointerOperand(), IRB->getInt16(Flags), 45181ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 45281ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 45381ad6265SDimitry Andric return NewI; 45481ad6265SDimitry Andric } 45581ad6265SDimitry Andric 45681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) { 45781ad6265SDimitry Andric if (!AggrStores.contains(&I)) 45881ad6265SDimitry Andric return &I; 45981ad6265SDimitry Andric TrackConstants = false; 46081ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 46181ad6265SDimitry Andric MachineMemOperand::Flags Flags = 46281ad6265SDimitry Andric TLI->getStoreMemOperandFlags(I, F->getParent()->getDataLayout()); 46381ad6265SDimitry Andric auto *PtrOp = I.getPointerOperand(); 464fcaf7f86SDimitry Andric auto *NewI = IRB->CreateIntrinsic( 465fcaf7f86SDimitry Andric Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()}, 46681ad6265SDimitry Andric {I.getValueOperand(), PtrOp, IRB->getInt16(Flags), 46781ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 46881ad6265SDimitry Andric I.eraseFromParent(); 46981ad6265SDimitry Andric return NewI; 47081ad6265SDimitry Andric } 47181ad6265SDimitry Andric 47281ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) { 47381ad6265SDimitry Andric TrackConstants = false; 474bdd1243dSDimitry Andric Type *PtrTy = I.getType(); 475bdd1243dSDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {}); 476bdd1243dSDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 477bdd1243dSDimitry Andric I.replaceAllUsesWith(NewI); 478bdd1243dSDimitry Andric I.eraseFromParent(); 479bdd1243dSDimitry Andric NewI->setName(InstName); 480bdd1243dSDimitry Andric return NewI; 48181ad6265SDimitry Andric } 48281ad6265SDimitry Andric 483fcaf7f86SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { 484fcaf7f86SDimitry Andric assert(I.getType()->isAggregateType() && "Aggregate result is expected"); 485fcaf7f86SDimitry Andric SmallVector<Value *> Args; 486fcaf7f86SDimitry Andric for (auto &Op : I.operands()) 487fcaf7f86SDimitry Andric Args.push_back(Op); 488fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32(I.getSyncScopeID())); 489fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32( 490fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering())))); 491fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32( 492fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering())))); 493fcaf7f86SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_cmpxchg, 494fcaf7f86SDimitry Andric {I.getPointerOperand()->getType()}, {Args}); 495fcaf7f86SDimitry Andric replaceMemInstrUses(&I, NewI); 496fcaf7f86SDimitry Andric return NewI; 497fcaf7f86SDimitry Andric } 498fcaf7f86SDimitry Andric 499bdd1243dSDimitry Andric Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) { 500bdd1243dSDimitry Andric IRB->SetInsertPoint(&I); 501bdd1243dSDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unreachable, {}, {}); 502bdd1243dSDimitry Andric return &I; 503bdd1243dSDimitry Andric } 504bdd1243dSDimitry Andric 50581ad6265SDimitry Andric void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) { 50681ad6265SDimitry Andric // Skip special artifical variable llvm.global.annotations. 50781ad6265SDimitry Andric if (GV.getName() == "llvm.global.annotations") 50881ad6265SDimitry Andric return; 50981ad6265SDimitry Andric if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) { 51081ad6265SDimitry Andric Constant *Init = GV.getInitializer(); 51181ad6265SDimitry Andric Type *Ty = isAggrToReplace(Init) ? IRB->getInt32Ty() : Init->getType(); 51281ad6265SDimitry Andric Constant *Const = isAggrToReplace(Init) ? IRB->getInt32(1) : Init; 51381ad6265SDimitry Andric auto *InitInst = IRB->CreateIntrinsic(Intrinsic::spv_init_global, 51481ad6265SDimitry Andric {GV.getType(), Ty}, {&GV, Const}); 51581ad6265SDimitry Andric InitInst->setArgOperand(1, Init); 51681ad6265SDimitry Andric } 51781ad6265SDimitry Andric if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) && 51881ad6265SDimitry Andric GV.getNumUses() == 0) 51981ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV); 52081ad6265SDimitry Andric } 52181ad6265SDimitry Andric 5225f757f3fSDimitry Andric void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I) { 5235f757f3fSDimitry Andric if (I->getType()->isVoidTy() || !requireAssignPtrType(I)) 5245f757f3fSDimitry Andric return; 5255f757f3fSDimitry Andric 5265f757f3fSDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 5275f757f3fSDimitry Andric 5285f757f3fSDimitry Andric Constant *EltTyConst; 5295f757f3fSDimitry Andric unsigned AddressSpace = 0; 5305f757f3fSDimitry Andric if (auto *AI = dyn_cast<AllocaInst>(I)) { 531cb14a3feSDimitry Andric EltTyConst = UndefValue::get(AI->getAllocatedType()); 5325f757f3fSDimitry Andric AddressSpace = AI->getAddressSpace(); 5335f757f3fSDimitry Andric } else if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) { 534cb14a3feSDimitry Andric EltTyConst = UndefValue::get(GEP->getResultElementType()); 5355f757f3fSDimitry Andric AddressSpace = GEP->getPointerAddressSpace(); 5365f757f3fSDimitry Andric } else { 5375f757f3fSDimitry Andric llvm_unreachable("Unexpected instruction!"); 5385f757f3fSDimitry Andric } 5395f757f3fSDimitry Andric 5405f757f3fSDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {I->getType()}, EltTyConst, I, 5415f757f3fSDimitry Andric {IRB->getInt32(AddressSpace)}); 5425f757f3fSDimitry Andric } 5435f757f3fSDimitry Andric 54481ad6265SDimitry Andric void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) { 54581ad6265SDimitry Andric Type *Ty = I->getType(); 5465f757f3fSDimitry Andric if (!Ty->isVoidTy() && requireAssignType(I) && !requireAssignPtrType(I)) { 54781ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 54881ad6265SDimitry Andric Type *TypeToAssign = Ty; 54981ad6265SDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(I)) { 55006c3fb27SDimitry Andric if (II->getIntrinsicID() == Intrinsic::spv_const_composite || 55106c3fb27SDimitry Andric II->getIntrinsicID() == Intrinsic::spv_undef) { 55281ad6265SDimitry Andric auto t = AggrConsts.find(II); 55381ad6265SDimitry Andric assert(t != AggrConsts.end()); 55481ad6265SDimitry Andric TypeToAssign = t->second->getType(); 55581ad6265SDimitry Andric } 55681ad6265SDimitry Andric } 557cb14a3feSDimitry Andric Constant *Const = UndefValue::get(TypeToAssign); 5585f757f3fSDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I, {}); 55981ad6265SDimitry Andric } 56081ad6265SDimitry Andric for (const auto &Op : I->operands()) { 56181ad6265SDimitry Andric if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) || 56281ad6265SDimitry Andric // Check GetElementPtrConstantExpr case. 56381ad6265SDimitry Andric (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) { 564bdd1243dSDimitry Andric setInsertPointSkippingPhis(*IRB, I); 565fcaf7f86SDimitry Andric if (isa<UndefValue>(Op) && Op->getType()->isAggregateType()) 566fcaf7f86SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op, 5675f757f3fSDimitry Andric UndefValue::get(IRB->getInt32Ty()), {}); 568fcaf7f86SDimitry Andric else 5695f757f3fSDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op, 5705f757f3fSDimitry Andric {}); 57181ad6265SDimitry Andric } 57281ad6265SDimitry Andric } 57381ad6265SDimitry Andric } 57481ad6265SDimitry Andric 57581ad6265SDimitry Andric void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) { 57681ad6265SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(I); 57781ad6265SDimitry Andric if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite && 57881ad6265SDimitry Andric TrackConstants) { 57981ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 58081ad6265SDimitry Andric Type *Ty = IRB->getInt32Ty(); 58181ad6265SDimitry Andric auto t = AggrConsts.find(I); 58281ad6265SDimitry Andric assert(t != AggrConsts.end()); 5835f757f3fSDimitry Andric auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, 5845f757f3fSDimitry Andric t->second, I, {}); 58581ad6265SDimitry Andric I->replaceAllUsesWith(NewOp); 58681ad6265SDimitry Andric NewOp->setArgOperand(0, I); 58781ad6265SDimitry Andric } 58881ad6265SDimitry Andric for (const auto &Op : I->operands()) { 58981ad6265SDimitry Andric if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) || 59081ad6265SDimitry Andric isa<PHINode>(I) || isa<SwitchInst>(I)) 59181ad6265SDimitry Andric TrackConstants = false; 592fcaf7f86SDimitry Andric if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) { 59381ad6265SDimitry Andric unsigned OpNo = Op.getOperandNo(); 59481ad6265SDimitry Andric if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) || 59581ad6265SDimitry Andric (II->paramHasAttr(OpNo, Attribute::ImmArg)))) 59681ad6265SDimitry Andric continue; 59781ad6265SDimitry Andric IRB->SetInsertPoint(I); 59881ad6265SDimitry Andric auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, 5995f757f3fSDimitry Andric {Op->getType(), Op->getType()}, Op, Op, {}); 60081ad6265SDimitry Andric I->setOperand(OpNo, NewOp); 60181ad6265SDimitry Andric } 60281ad6265SDimitry Andric } 60381ad6265SDimitry Andric if (I->hasName()) { 60481ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 60581ad6265SDimitry Andric std::vector<Value *> Args = {I}; 60681ad6265SDimitry Andric addStringImm(I->getName(), *IRB, Args); 60781ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args); 60881ad6265SDimitry Andric } 60981ad6265SDimitry Andric } 61081ad6265SDimitry Andric 61181ad6265SDimitry Andric bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { 61281ad6265SDimitry Andric if (Func.isDeclaration()) 61381ad6265SDimitry Andric return false; 61481ad6265SDimitry Andric F = &Func; 61581ad6265SDimitry Andric IRB = new IRBuilder<>(Func.getContext()); 61681ad6265SDimitry Andric AggrConsts.clear(); 61781ad6265SDimitry Andric AggrStores.clear(); 61881ad6265SDimitry Andric 619fcaf7f86SDimitry Andric // StoreInst's operand type can be changed during the next transformations, 620fcaf7f86SDimitry Andric // so we need to store it in the set. Also store already transformed types. 621fcaf7f86SDimitry Andric for (auto &I : instructions(Func)) { 622fcaf7f86SDimitry Andric StoreInst *SI = dyn_cast<StoreInst>(&I); 623fcaf7f86SDimitry Andric if (!SI) 624fcaf7f86SDimitry Andric continue; 625fcaf7f86SDimitry Andric Type *ElTy = SI->getValueOperand()->getType(); 6265f757f3fSDimitry Andric if (ElTy->isAggregateType() || ElTy->isVectorTy()) 627fcaf7f86SDimitry Andric AggrStores.insert(&I); 628fcaf7f86SDimitry Andric } 62981ad6265SDimitry Andric 6305f757f3fSDimitry Andric IRB->SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin()); 63181ad6265SDimitry Andric for (auto &GV : Func.getParent()->globals()) 63281ad6265SDimitry Andric processGlobalValue(GV); 63381ad6265SDimitry Andric 63406c3fb27SDimitry Andric preprocessUndefs(); 63581ad6265SDimitry Andric preprocessCompositeConstants(); 63681ad6265SDimitry Andric SmallVector<Instruction *> Worklist; 63781ad6265SDimitry Andric for (auto &I : instructions(Func)) 63881ad6265SDimitry Andric Worklist.push_back(&I); 63981ad6265SDimitry Andric 6405f757f3fSDimitry Andric for (auto &I : Worklist) { 6415f757f3fSDimitry Andric insertAssignPtrTypeIntrs(I); 64281ad6265SDimitry Andric insertAssignTypeIntrs(I); 643*1db9f3b2SDimitry Andric insertPtrCastInstr(I); 6445f757f3fSDimitry Andric } 64581ad6265SDimitry Andric 64681ad6265SDimitry Andric for (auto *I : Worklist) { 64781ad6265SDimitry Andric TrackConstants = true; 64881ad6265SDimitry Andric if (!I->getType()->isVoidTy() || isa<StoreInst>(I)) 64981ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 650*1db9f3b2SDimitry Andric // Visitors return either the original/newly created instruction for further 651*1db9f3b2SDimitry Andric // processing, nullptr otherwise. 65281ad6265SDimitry Andric I = visit(*I); 653*1db9f3b2SDimitry Andric if (!I) 654*1db9f3b2SDimitry Andric continue; 65581ad6265SDimitry Andric processInstrAfterVisit(I); 65681ad6265SDimitry Andric } 65781ad6265SDimitry Andric return true; 65881ad6265SDimitry Andric } 65981ad6265SDimitry Andric 66081ad6265SDimitry Andric FunctionPass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) { 66181ad6265SDimitry Andric return new SPIRVEmitIntrinsics(TM); 66281ad6265SDimitry Andric } 663