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(); 5981ad6265SDimitry Andric CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types, 6081ad6265SDimitry Andric Value *Arg, Value *Arg2) { 6181ad6265SDimitry Andric ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg); 6281ad6265SDimitry Andric MDTuple *TyMD = MDNode::get(F->getContext(), CM); 6381ad6265SDimitry Andric MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD); 6481ad6265SDimitry Andric return IRB->CreateIntrinsic(IntrID, {Types}, {Arg2, VMD}); 6581ad6265SDimitry Andric } 6681ad6265SDimitry Andric void replaceMemInstrUses(Instruction *Old, Instruction *New); 6781ad6265SDimitry Andric void processInstrAfterVisit(Instruction *I); 6881ad6265SDimitry Andric void insertAssignTypeIntrs(Instruction *I); 6981ad6265SDimitry Andric void processGlobalValue(GlobalVariable &GV); 7081ad6265SDimitry Andric 7181ad6265SDimitry Andric public: 7281ad6265SDimitry Andric static char ID; 7381ad6265SDimitry Andric SPIRVEmitIntrinsics() : FunctionPass(ID) { 7481ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 7581ad6265SDimitry Andric } 7681ad6265SDimitry Andric SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : FunctionPass(ID), TM(_TM) { 7781ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 7881ad6265SDimitry Andric } 7981ad6265SDimitry Andric Instruction *visitInstruction(Instruction &I) { return &I; } 8081ad6265SDimitry Andric Instruction *visitSwitchInst(SwitchInst &I); 8181ad6265SDimitry Andric Instruction *visitGetElementPtrInst(GetElementPtrInst &I); 8281ad6265SDimitry Andric Instruction *visitBitCastInst(BitCastInst &I); 8381ad6265SDimitry Andric Instruction *visitInsertElementInst(InsertElementInst &I); 8481ad6265SDimitry Andric Instruction *visitExtractElementInst(ExtractElementInst &I); 8581ad6265SDimitry Andric Instruction *visitInsertValueInst(InsertValueInst &I); 8681ad6265SDimitry Andric Instruction *visitExtractValueInst(ExtractValueInst &I); 8781ad6265SDimitry Andric Instruction *visitLoadInst(LoadInst &I); 8881ad6265SDimitry Andric Instruction *visitStoreInst(StoreInst &I); 8981ad6265SDimitry Andric Instruction *visitAllocaInst(AllocaInst &I); 90fcaf7f86SDimitry Andric Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); 91*bdd1243dSDimitry Andric Instruction *visitUnreachableInst(UnreachableInst &I); 9281ad6265SDimitry Andric bool runOnFunction(Function &F) override; 9381ad6265SDimitry Andric }; 9481ad6265SDimitry Andric } // namespace 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric char SPIRVEmitIntrinsics::ID = 0; 9781ad6265SDimitry Andric 9881ad6265SDimitry Andric INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics", 9981ad6265SDimitry Andric false, false) 10081ad6265SDimitry Andric 10181ad6265SDimitry Andric static inline bool isAssignTypeInstr(const Instruction *I) { 10281ad6265SDimitry Andric return isa<IntrinsicInst>(I) && 10381ad6265SDimitry Andric cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type; 10481ad6265SDimitry Andric } 10581ad6265SDimitry Andric 10681ad6265SDimitry Andric static bool isMemInstrToReplace(Instruction *I) { 10781ad6265SDimitry Andric return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) || 108fcaf7f86SDimitry Andric isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I); 10981ad6265SDimitry Andric } 11081ad6265SDimitry Andric 11181ad6265SDimitry Andric static bool isAggrToReplace(const Value *V) { 11281ad6265SDimitry Andric return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) || 11381ad6265SDimitry Andric (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()); 11481ad6265SDimitry Andric } 11581ad6265SDimitry Andric 11681ad6265SDimitry Andric static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) { 11781ad6265SDimitry Andric if (isa<PHINode>(I)) 11881ad6265SDimitry Andric B.SetInsertPoint(I->getParent(), I->getParent()->getFirstInsertionPt()); 11981ad6265SDimitry Andric else 12081ad6265SDimitry Andric B.SetInsertPoint(I); 12181ad6265SDimitry Andric } 12281ad6265SDimitry Andric 12381ad6265SDimitry Andric static bool requireAssignType(Instruction *I) { 12481ad6265SDimitry Andric IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I); 12581ad6265SDimitry Andric if (Intr) { 12681ad6265SDimitry Andric switch (Intr->getIntrinsicID()) { 12781ad6265SDimitry Andric case Intrinsic::invariant_start: 12881ad6265SDimitry Andric case Intrinsic::invariant_end: 12981ad6265SDimitry Andric return false; 13081ad6265SDimitry Andric } 13181ad6265SDimitry Andric } 13281ad6265SDimitry Andric return true; 13381ad6265SDimitry Andric } 13481ad6265SDimitry Andric 13581ad6265SDimitry Andric void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old, 13681ad6265SDimitry Andric Instruction *New) { 13781ad6265SDimitry Andric while (!Old->user_empty()) { 13881ad6265SDimitry Andric auto *U = Old->user_back(); 139fcaf7f86SDimitry Andric if (isAssignTypeInstr(U)) { 14081ad6265SDimitry Andric IRB->SetInsertPoint(U); 14181ad6265SDimitry Andric SmallVector<Value *, 2> Args = {New, U->getOperand(1)}; 14281ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args); 14381ad6265SDimitry Andric U->eraseFromParent(); 144fcaf7f86SDimitry Andric } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) || 145fcaf7f86SDimitry Andric isa<CallInst>(U)) { 146fcaf7f86SDimitry Andric U->replaceUsesOfWith(Old, New); 14781ad6265SDimitry Andric } else { 14881ad6265SDimitry Andric llvm_unreachable("illegal aggregate intrinsic user"); 14981ad6265SDimitry Andric } 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric Old->eraseFromParent(); 15281ad6265SDimitry Andric } 15381ad6265SDimitry Andric 15481ad6265SDimitry Andric void SPIRVEmitIntrinsics::preprocessCompositeConstants() { 15581ad6265SDimitry Andric std::queue<Instruction *> Worklist; 15681ad6265SDimitry Andric for (auto &I : instructions(F)) 15781ad6265SDimitry Andric Worklist.push(&I); 15881ad6265SDimitry Andric 15981ad6265SDimitry Andric while (!Worklist.empty()) { 16081ad6265SDimitry Andric auto *I = Worklist.front(); 16181ad6265SDimitry Andric assert(I); 16281ad6265SDimitry Andric bool KeepInst = false; 16381ad6265SDimitry Andric for (const auto &Op : I->operands()) { 16481ad6265SDimitry Andric auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &I, &Op, 16581ad6265SDimitry Andric this](Constant *AggrC, 16681ad6265SDimitry Andric ArrayRef<Value *> Args) { 16781ad6265SDimitry Andric IRB->SetInsertPoint(I); 16881ad6265SDimitry Andric auto *CCI = 16981ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args}); 17081ad6265SDimitry Andric Worklist.push(CCI); 17181ad6265SDimitry Andric I->replaceUsesOfWith(Op, CCI); 17281ad6265SDimitry Andric KeepInst = true; 17381ad6265SDimitry Andric AggrConsts[CCI] = AggrC; 17481ad6265SDimitry Andric }; 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) { 17781ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 17881ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 17981ad6265SDimitry Andric } else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) { 18081ad6265SDimitry Andric SmallVector<Value *> Args; 18181ad6265SDimitry Andric for (unsigned i = 0; i < AggrC->getNumElements(); ++i) 18281ad6265SDimitry Andric Args.push_back(AggrC->getElementAsConstant(i)); 18381ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 18481ad6265SDimitry Andric } else if (isa<ConstantAggregateZero>(Op) && 18581ad6265SDimitry Andric !Op->getType()->isVectorTy()) { 18681ad6265SDimitry Andric auto *AggrC = cast<ConstantAggregateZero>(Op); 18781ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 18881ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 18981ad6265SDimitry Andric } 19081ad6265SDimitry Andric } 19181ad6265SDimitry Andric if (!KeepInst) 19281ad6265SDimitry Andric Worklist.pop(); 19381ad6265SDimitry Andric } 19481ad6265SDimitry Andric } 19581ad6265SDimitry Andric 19681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) { 19781ad6265SDimitry Andric SmallVector<Value *, 4> Args; 19881ad6265SDimitry Andric for (auto &Op : I.operands()) 19981ad6265SDimitry Andric if (Op.get()->getType()->isSized()) 20081ad6265SDimitry Andric Args.push_back(Op); 201*bdd1243dSDimitry Andric IRB->SetInsertPoint(&I); 20281ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_switch, {I.getOperand(0)->getType()}, 20381ad6265SDimitry Andric {Args}); 20481ad6265SDimitry Andric return &I; 20581ad6265SDimitry Andric } 20681ad6265SDimitry Andric 20781ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) { 20881ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 20981ad6265SDimitry Andric SmallVector<Value *, 4> Args; 21081ad6265SDimitry Andric Args.push_back(IRB->getInt1(I.isInBounds())); 21181ad6265SDimitry Andric for (auto &Op : I.operands()) 21281ad6265SDimitry Andric Args.push_back(Op); 21381ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args}); 21481ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 21581ad6265SDimitry Andric I.eraseFromParent(); 21681ad6265SDimitry Andric return NewI; 21781ad6265SDimitry Andric } 21881ad6265SDimitry Andric 21981ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) { 22081ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 22181ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 22281ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args}); 22381ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 22481ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 22581ad6265SDimitry Andric I.eraseFromParent(); 22681ad6265SDimitry Andric NewI->setName(InstName); 22781ad6265SDimitry Andric return NewI; 22881ad6265SDimitry Andric } 22981ad6265SDimitry Andric 23081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) { 23181ad6265SDimitry Andric SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(), 23281ad6265SDimitry Andric I.getOperand(1)->getType(), 23381ad6265SDimitry Andric I.getOperand(2)->getType()}; 23481ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 23581ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args}); 23681ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 23781ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 23881ad6265SDimitry Andric I.eraseFromParent(); 23981ad6265SDimitry Andric NewI->setName(InstName); 24081ad6265SDimitry Andric return NewI; 24181ad6265SDimitry Andric } 24281ad6265SDimitry Andric 24381ad6265SDimitry Andric Instruction * 24481ad6265SDimitry Andric SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) { 24581ad6265SDimitry Andric SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(), 24681ad6265SDimitry Andric I.getIndexOperand()->getType()}; 24781ad6265SDimitry Andric SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()}; 24881ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args}); 24981ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 25081ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 25181ad6265SDimitry Andric I.eraseFromParent(); 25281ad6265SDimitry Andric NewI->setName(InstName); 25381ad6265SDimitry Andric return NewI; 25481ad6265SDimitry Andric } 25581ad6265SDimitry Andric 25681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) { 25781ad6265SDimitry Andric SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()}; 25881ad6265SDimitry Andric SmallVector<Value *> Args; 25981ad6265SDimitry Andric for (auto &Op : I.operands()) 26081ad6265SDimitry Andric if (isa<UndefValue>(Op)) 26181ad6265SDimitry Andric Args.push_back(UndefValue::get(IRB->getInt32Ty())); 26281ad6265SDimitry Andric else 26381ad6265SDimitry Andric Args.push_back(Op); 26481ad6265SDimitry Andric for (auto &Op : I.indices()) 26581ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 26681ad6265SDimitry Andric Instruction *NewI = 26781ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args}); 26881ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 26981ad6265SDimitry Andric return NewI; 27081ad6265SDimitry Andric } 27181ad6265SDimitry Andric 27281ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) { 27381ad6265SDimitry Andric SmallVector<Value *> Args; 27481ad6265SDimitry Andric for (auto &Op : I.operands()) 27581ad6265SDimitry Andric Args.push_back(Op); 27681ad6265SDimitry Andric for (auto &Op : I.indices()) 27781ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 27881ad6265SDimitry Andric auto *NewI = 27981ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args}); 28081ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 28181ad6265SDimitry Andric I.eraseFromParent(); 28281ad6265SDimitry Andric return NewI; 28381ad6265SDimitry Andric } 28481ad6265SDimitry Andric 28581ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) { 28681ad6265SDimitry Andric if (!I.getType()->isAggregateType()) 28781ad6265SDimitry Andric return &I; 28881ad6265SDimitry Andric TrackConstants = false; 28981ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 29081ad6265SDimitry Andric MachineMemOperand::Flags Flags = 29181ad6265SDimitry Andric TLI->getLoadMemOperandFlags(I, F->getParent()->getDataLayout()); 29281ad6265SDimitry Andric auto *NewI = 29381ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()}, 29481ad6265SDimitry Andric {I.getPointerOperand(), IRB->getInt16(Flags), 29581ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 29681ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 29781ad6265SDimitry Andric return NewI; 29881ad6265SDimitry Andric } 29981ad6265SDimitry Andric 30081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) { 30181ad6265SDimitry Andric if (!AggrStores.contains(&I)) 30281ad6265SDimitry Andric return &I; 30381ad6265SDimitry Andric TrackConstants = false; 30481ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 30581ad6265SDimitry Andric MachineMemOperand::Flags Flags = 30681ad6265SDimitry Andric TLI->getStoreMemOperandFlags(I, F->getParent()->getDataLayout()); 30781ad6265SDimitry Andric auto *PtrOp = I.getPointerOperand(); 308fcaf7f86SDimitry Andric auto *NewI = IRB->CreateIntrinsic( 309fcaf7f86SDimitry Andric Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()}, 31081ad6265SDimitry Andric {I.getValueOperand(), PtrOp, IRB->getInt16(Flags), 31181ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 31281ad6265SDimitry Andric I.eraseFromParent(); 31381ad6265SDimitry Andric return NewI; 31481ad6265SDimitry Andric } 31581ad6265SDimitry Andric 31681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) { 31781ad6265SDimitry Andric TrackConstants = false; 318*bdd1243dSDimitry Andric Type *PtrTy = I.getType(); 319*bdd1243dSDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {}); 320*bdd1243dSDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 321*bdd1243dSDimitry Andric I.replaceAllUsesWith(NewI); 322*bdd1243dSDimitry Andric I.eraseFromParent(); 323*bdd1243dSDimitry Andric NewI->setName(InstName); 324*bdd1243dSDimitry Andric return NewI; 32581ad6265SDimitry Andric } 32681ad6265SDimitry Andric 327fcaf7f86SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { 328fcaf7f86SDimitry Andric assert(I.getType()->isAggregateType() && "Aggregate result is expected"); 329fcaf7f86SDimitry Andric SmallVector<Value *> Args; 330fcaf7f86SDimitry Andric for (auto &Op : I.operands()) 331fcaf7f86SDimitry Andric Args.push_back(Op); 332fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32(I.getSyncScopeID())); 333fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32( 334fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering())))); 335fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32( 336fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering())))); 337fcaf7f86SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_cmpxchg, 338fcaf7f86SDimitry Andric {I.getPointerOperand()->getType()}, {Args}); 339fcaf7f86SDimitry Andric replaceMemInstrUses(&I, NewI); 340fcaf7f86SDimitry Andric return NewI; 341fcaf7f86SDimitry Andric } 342fcaf7f86SDimitry Andric 343*bdd1243dSDimitry Andric Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) { 344*bdd1243dSDimitry Andric IRB->SetInsertPoint(&I); 345*bdd1243dSDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unreachable, {}, {}); 346*bdd1243dSDimitry Andric return &I; 347*bdd1243dSDimitry Andric } 348*bdd1243dSDimitry Andric 34981ad6265SDimitry Andric void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) { 35081ad6265SDimitry Andric // Skip special artifical variable llvm.global.annotations. 35181ad6265SDimitry Andric if (GV.getName() == "llvm.global.annotations") 35281ad6265SDimitry Andric return; 35381ad6265SDimitry Andric if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) { 35481ad6265SDimitry Andric Constant *Init = GV.getInitializer(); 35581ad6265SDimitry Andric Type *Ty = isAggrToReplace(Init) ? IRB->getInt32Ty() : Init->getType(); 35681ad6265SDimitry Andric Constant *Const = isAggrToReplace(Init) ? IRB->getInt32(1) : Init; 35781ad6265SDimitry Andric auto *InitInst = IRB->CreateIntrinsic(Intrinsic::spv_init_global, 35881ad6265SDimitry Andric {GV.getType(), Ty}, {&GV, Const}); 35981ad6265SDimitry Andric InitInst->setArgOperand(1, Init); 36081ad6265SDimitry Andric } 36181ad6265SDimitry Andric if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) && 36281ad6265SDimitry Andric GV.getNumUses() == 0) 36381ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV); 36481ad6265SDimitry Andric } 36581ad6265SDimitry Andric 36681ad6265SDimitry Andric void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) { 36781ad6265SDimitry Andric Type *Ty = I->getType(); 36881ad6265SDimitry Andric if (!Ty->isVoidTy() && requireAssignType(I)) { 36981ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 37081ad6265SDimitry Andric Type *TypeToAssign = Ty; 37181ad6265SDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(I)) { 37281ad6265SDimitry Andric if (II->getIntrinsicID() == Intrinsic::spv_const_composite) { 37381ad6265SDimitry Andric auto t = AggrConsts.find(II); 37481ad6265SDimitry Andric assert(t != AggrConsts.end()); 37581ad6265SDimitry Andric TypeToAssign = t->second->getType(); 37681ad6265SDimitry Andric } 37781ad6265SDimitry Andric } 37881ad6265SDimitry Andric Constant *Const = Constant::getNullValue(TypeToAssign); 37981ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I); 38081ad6265SDimitry Andric } 38181ad6265SDimitry Andric for (const auto &Op : I->operands()) { 38281ad6265SDimitry Andric if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) || 38381ad6265SDimitry Andric // Check GetElementPtrConstantExpr case. 38481ad6265SDimitry Andric (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) { 385*bdd1243dSDimitry Andric setInsertPointSkippingPhis(*IRB, I); 386fcaf7f86SDimitry Andric if (isa<UndefValue>(Op) && Op->getType()->isAggregateType()) 387fcaf7f86SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op, 388fcaf7f86SDimitry Andric UndefValue::get(IRB->getInt32Ty())); 389fcaf7f86SDimitry Andric else 39081ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op); 39181ad6265SDimitry Andric } 39281ad6265SDimitry Andric } 39381ad6265SDimitry Andric } 39481ad6265SDimitry Andric 39581ad6265SDimitry Andric void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) { 39681ad6265SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(I); 39781ad6265SDimitry Andric if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite && 39881ad6265SDimitry Andric TrackConstants) { 39981ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 40081ad6265SDimitry Andric Type *Ty = IRB->getInt32Ty(); 40181ad6265SDimitry Andric auto t = AggrConsts.find(I); 40281ad6265SDimitry Andric assert(t != AggrConsts.end()); 40381ad6265SDimitry Andric auto *NewOp = 40481ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, t->second, I); 40581ad6265SDimitry Andric I->replaceAllUsesWith(NewOp); 40681ad6265SDimitry Andric NewOp->setArgOperand(0, I); 40781ad6265SDimitry Andric } 40881ad6265SDimitry Andric for (const auto &Op : I->operands()) { 40981ad6265SDimitry Andric if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) || 41081ad6265SDimitry Andric isa<PHINode>(I) || isa<SwitchInst>(I)) 41181ad6265SDimitry Andric TrackConstants = false; 412fcaf7f86SDimitry Andric if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) { 41381ad6265SDimitry Andric unsigned OpNo = Op.getOperandNo(); 41481ad6265SDimitry Andric if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) || 41581ad6265SDimitry Andric (II->paramHasAttr(OpNo, Attribute::ImmArg)))) 41681ad6265SDimitry Andric continue; 41781ad6265SDimitry Andric IRB->SetInsertPoint(I); 41881ad6265SDimitry Andric auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, 41981ad6265SDimitry Andric {Op->getType(), Op->getType()}, Op, Op); 42081ad6265SDimitry Andric I->setOperand(OpNo, NewOp); 42181ad6265SDimitry Andric } 42281ad6265SDimitry Andric } 42381ad6265SDimitry Andric if (I->hasName()) { 42481ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 42581ad6265SDimitry Andric std::vector<Value *> Args = {I}; 42681ad6265SDimitry Andric addStringImm(I->getName(), *IRB, Args); 42781ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args); 42881ad6265SDimitry Andric } 42981ad6265SDimitry Andric } 43081ad6265SDimitry Andric 43181ad6265SDimitry Andric bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { 43281ad6265SDimitry Andric if (Func.isDeclaration()) 43381ad6265SDimitry Andric return false; 43481ad6265SDimitry Andric F = &Func; 43581ad6265SDimitry Andric IRB = new IRBuilder<>(Func.getContext()); 43681ad6265SDimitry Andric AggrConsts.clear(); 43781ad6265SDimitry Andric AggrStores.clear(); 43881ad6265SDimitry Andric 439fcaf7f86SDimitry Andric // StoreInst's operand type can be changed during the next transformations, 440fcaf7f86SDimitry Andric // so we need to store it in the set. Also store already transformed types. 441fcaf7f86SDimitry Andric for (auto &I : instructions(Func)) { 442fcaf7f86SDimitry Andric StoreInst *SI = dyn_cast<StoreInst>(&I); 443fcaf7f86SDimitry Andric if (!SI) 444fcaf7f86SDimitry Andric continue; 445fcaf7f86SDimitry Andric Type *ElTy = SI->getValueOperand()->getType(); 446fcaf7f86SDimitry Andric PointerType *PTy = cast<PointerType>(SI->getOperand(1)->getType()); 447fcaf7f86SDimitry Andric if (ElTy->isAggregateType() || ElTy->isVectorTy() || 448fcaf7f86SDimitry Andric !PTy->isOpaqueOrPointeeTypeMatches(ElTy)) 449fcaf7f86SDimitry Andric AggrStores.insert(&I); 450fcaf7f86SDimitry Andric } 45181ad6265SDimitry Andric 452fcaf7f86SDimitry Andric IRB->SetInsertPoint(&Func.getEntryBlock().front()); 45381ad6265SDimitry Andric for (auto &GV : Func.getParent()->globals()) 45481ad6265SDimitry Andric processGlobalValue(GV); 45581ad6265SDimitry Andric 45681ad6265SDimitry Andric preprocessCompositeConstants(); 45781ad6265SDimitry Andric SmallVector<Instruction *> Worklist; 45881ad6265SDimitry Andric for (auto &I : instructions(Func)) 45981ad6265SDimitry Andric Worklist.push_back(&I); 46081ad6265SDimitry Andric 46181ad6265SDimitry Andric for (auto &I : Worklist) 46281ad6265SDimitry Andric insertAssignTypeIntrs(I); 46381ad6265SDimitry Andric 46481ad6265SDimitry Andric for (auto *I : Worklist) { 46581ad6265SDimitry Andric TrackConstants = true; 46681ad6265SDimitry Andric if (!I->getType()->isVoidTy() || isa<StoreInst>(I)) 46781ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 46881ad6265SDimitry Andric I = visit(*I); 46981ad6265SDimitry Andric processInstrAfterVisit(I); 47081ad6265SDimitry Andric } 47181ad6265SDimitry Andric return true; 47281ad6265SDimitry Andric } 47381ad6265SDimitry Andric 47481ad6265SDimitry Andric FunctionPass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) { 47581ad6265SDimitry Andric return new SPIRVEmitIntrinsics(TM); 47681ad6265SDimitry Andric } 477