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, 61*5f757f3fSDimitry Andric Value *Arg, Value *Arg2, 62*5f757f3fSDimitry 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); 66*5f757f3fSDimitry Andric SmallVector<Value *, 4> Args; 67*5f757f3fSDimitry Andric Args.push_back(Arg2); 68*5f757f3fSDimitry Andric Args.push_back(VMD); 69*5f757f3fSDimitry Andric for (auto *Imm : Imms) 70*5f757f3fSDimitry Andric Args.push_back(Imm); 71*5f757f3fSDimitry Andric return IRB->CreateIntrinsic(IntrID, {Types}, Args); 7281ad6265SDimitry Andric } 7381ad6265SDimitry Andric void replaceMemInstrUses(Instruction *Old, Instruction *New); 7481ad6265SDimitry Andric void processInstrAfterVisit(Instruction *I); 75*5f757f3fSDimitry Andric void insertAssignPtrTypeIntrs(Instruction *I); 7681ad6265SDimitry Andric void insertAssignTypeIntrs(Instruction *I); 7781ad6265SDimitry Andric void processGlobalValue(GlobalVariable &GV); 7881ad6265SDimitry Andric 7981ad6265SDimitry Andric public: 8081ad6265SDimitry Andric static char ID; 8181ad6265SDimitry Andric SPIRVEmitIntrinsics() : FunctionPass(ID) { 8281ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 8381ad6265SDimitry Andric } 8481ad6265SDimitry Andric SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : FunctionPass(ID), TM(_TM) { 8581ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 8681ad6265SDimitry Andric } 8781ad6265SDimitry Andric Instruction *visitInstruction(Instruction &I) { return &I; } 8881ad6265SDimitry Andric Instruction *visitSwitchInst(SwitchInst &I); 8981ad6265SDimitry Andric Instruction *visitGetElementPtrInst(GetElementPtrInst &I); 9081ad6265SDimitry Andric Instruction *visitBitCastInst(BitCastInst &I); 9181ad6265SDimitry Andric Instruction *visitInsertElementInst(InsertElementInst &I); 9281ad6265SDimitry Andric Instruction *visitExtractElementInst(ExtractElementInst &I); 9381ad6265SDimitry Andric Instruction *visitInsertValueInst(InsertValueInst &I); 9481ad6265SDimitry Andric Instruction *visitExtractValueInst(ExtractValueInst &I); 9581ad6265SDimitry Andric Instruction *visitLoadInst(LoadInst &I); 9681ad6265SDimitry Andric Instruction *visitStoreInst(StoreInst &I); 9781ad6265SDimitry Andric Instruction *visitAllocaInst(AllocaInst &I); 98fcaf7f86SDimitry Andric Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); 99bdd1243dSDimitry Andric Instruction *visitUnreachableInst(UnreachableInst &I); 10081ad6265SDimitry Andric bool runOnFunction(Function &F) override; 10181ad6265SDimitry Andric }; 10281ad6265SDimitry Andric } // namespace 10381ad6265SDimitry Andric 10481ad6265SDimitry Andric char SPIRVEmitIntrinsics::ID = 0; 10581ad6265SDimitry Andric 10681ad6265SDimitry Andric INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics", 10781ad6265SDimitry Andric false, false) 10881ad6265SDimitry Andric 10981ad6265SDimitry Andric static inline bool isAssignTypeInstr(const Instruction *I) { 11081ad6265SDimitry Andric return isa<IntrinsicInst>(I) && 11181ad6265SDimitry Andric cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type; 11281ad6265SDimitry Andric } 11381ad6265SDimitry Andric 11481ad6265SDimitry Andric static bool isMemInstrToReplace(Instruction *I) { 11581ad6265SDimitry Andric return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) || 116fcaf7f86SDimitry Andric isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I); 11781ad6265SDimitry Andric } 11881ad6265SDimitry Andric 11981ad6265SDimitry Andric static bool isAggrToReplace(const Value *V) { 12081ad6265SDimitry Andric return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) || 12181ad6265SDimitry Andric (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()); 12281ad6265SDimitry Andric } 12381ad6265SDimitry Andric 12481ad6265SDimitry Andric static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) { 12581ad6265SDimitry Andric if (isa<PHINode>(I)) 12681ad6265SDimitry Andric B.SetInsertPoint(I->getParent(), I->getParent()->getFirstInsertionPt()); 12781ad6265SDimitry Andric else 12881ad6265SDimitry Andric B.SetInsertPoint(I); 12981ad6265SDimitry Andric } 13081ad6265SDimitry Andric 131*5f757f3fSDimitry Andric static bool requireAssignPtrType(Instruction *I) { 132*5f757f3fSDimitry Andric if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I)) 133*5f757f3fSDimitry Andric return true; 134*5f757f3fSDimitry Andric 135*5f757f3fSDimitry Andric return false; 136*5f757f3fSDimitry Andric } 137*5f757f3fSDimitry Andric 13881ad6265SDimitry Andric static bool requireAssignType(Instruction *I) { 13981ad6265SDimitry Andric IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I); 14081ad6265SDimitry Andric if (Intr) { 14181ad6265SDimitry Andric switch (Intr->getIntrinsicID()) { 14281ad6265SDimitry Andric case Intrinsic::invariant_start: 14381ad6265SDimitry Andric case Intrinsic::invariant_end: 14481ad6265SDimitry Andric return false; 14581ad6265SDimitry Andric } 14681ad6265SDimitry Andric } 14781ad6265SDimitry Andric return true; 14881ad6265SDimitry Andric } 14981ad6265SDimitry Andric 15081ad6265SDimitry Andric void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old, 15181ad6265SDimitry Andric Instruction *New) { 15281ad6265SDimitry Andric while (!Old->user_empty()) { 15381ad6265SDimitry Andric auto *U = Old->user_back(); 154fcaf7f86SDimitry Andric if (isAssignTypeInstr(U)) { 15581ad6265SDimitry Andric IRB->SetInsertPoint(U); 15681ad6265SDimitry Andric SmallVector<Value *, 2> Args = {New, U->getOperand(1)}; 15781ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args); 15881ad6265SDimitry Andric U->eraseFromParent(); 159fcaf7f86SDimitry Andric } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) || 160fcaf7f86SDimitry Andric isa<CallInst>(U)) { 161fcaf7f86SDimitry Andric U->replaceUsesOfWith(Old, New); 16281ad6265SDimitry Andric } else { 16381ad6265SDimitry Andric llvm_unreachable("illegal aggregate intrinsic user"); 16481ad6265SDimitry Andric } 16581ad6265SDimitry Andric } 16681ad6265SDimitry Andric Old->eraseFromParent(); 16781ad6265SDimitry Andric } 16881ad6265SDimitry Andric 16906c3fb27SDimitry Andric void SPIRVEmitIntrinsics::preprocessUndefs() { 17006c3fb27SDimitry Andric std::queue<Instruction *> Worklist; 17106c3fb27SDimitry Andric for (auto &I : instructions(F)) 17206c3fb27SDimitry Andric Worklist.push(&I); 17306c3fb27SDimitry Andric 17406c3fb27SDimitry Andric while (!Worklist.empty()) { 17506c3fb27SDimitry Andric Instruction *I = Worklist.front(); 17606c3fb27SDimitry Andric Worklist.pop(); 17706c3fb27SDimitry Andric 17806c3fb27SDimitry Andric for (auto &Op : I->operands()) { 17906c3fb27SDimitry Andric auto *AggrUndef = dyn_cast<UndefValue>(Op); 18006c3fb27SDimitry Andric if (!AggrUndef || !Op->getType()->isAggregateType()) 18106c3fb27SDimitry Andric continue; 18206c3fb27SDimitry Andric 18306c3fb27SDimitry Andric IRB->SetInsertPoint(I); 18406c3fb27SDimitry Andric auto *IntrUndef = IRB->CreateIntrinsic(Intrinsic::spv_undef, {}, {}); 18506c3fb27SDimitry Andric Worklist.push(IntrUndef); 18606c3fb27SDimitry Andric I->replaceUsesOfWith(Op, IntrUndef); 18706c3fb27SDimitry Andric AggrConsts[IntrUndef] = AggrUndef; 18806c3fb27SDimitry Andric } 18906c3fb27SDimitry Andric } 19006c3fb27SDimitry Andric } 19106c3fb27SDimitry Andric 19281ad6265SDimitry Andric void SPIRVEmitIntrinsics::preprocessCompositeConstants() { 19381ad6265SDimitry Andric std::queue<Instruction *> Worklist; 19481ad6265SDimitry Andric for (auto &I : instructions(F)) 19581ad6265SDimitry Andric Worklist.push(&I); 19681ad6265SDimitry Andric 19781ad6265SDimitry Andric while (!Worklist.empty()) { 19881ad6265SDimitry Andric auto *I = Worklist.front(); 19981ad6265SDimitry Andric assert(I); 20081ad6265SDimitry Andric bool KeepInst = false; 20181ad6265SDimitry Andric for (const auto &Op : I->operands()) { 20281ad6265SDimitry Andric auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &I, &Op, 20381ad6265SDimitry Andric this](Constant *AggrC, 20481ad6265SDimitry Andric ArrayRef<Value *> Args) { 20581ad6265SDimitry Andric IRB->SetInsertPoint(I); 20681ad6265SDimitry Andric auto *CCI = 20781ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args}); 20881ad6265SDimitry Andric Worklist.push(CCI); 20981ad6265SDimitry Andric I->replaceUsesOfWith(Op, CCI); 21081ad6265SDimitry Andric KeepInst = true; 21181ad6265SDimitry Andric AggrConsts[CCI] = AggrC; 21281ad6265SDimitry Andric }; 21381ad6265SDimitry Andric 21481ad6265SDimitry Andric if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) { 21581ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 21681ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 21781ad6265SDimitry Andric } else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) { 21881ad6265SDimitry Andric SmallVector<Value *> Args; 21981ad6265SDimitry Andric for (unsigned i = 0; i < AggrC->getNumElements(); ++i) 22081ad6265SDimitry Andric Args.push_back(AggrC->getElementAsConstant(i)); 22181ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 22281ad6265SDimitry Andric } else if (isa<ConstantAggregateZero>(Op) && 22381ad6265SDimitry Andric !Op->getType()->isVectorTy()) { 22481ad6265SDimitry Andric auto *AggrC = cast<ConstantAggregateZero>(Op); 22581ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 22681ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 22781ad6265SDimitry Andric } 22881ad6265SDimitry Andric } 22981ad6265SDimitry Andric if (!KeepInst) 23081ad6265SDimitry Andric Worklist.pop(); 23181ad6265SDimitry Andric } 23281ad6265SDimitry Andric } 23381ad6265SDimitry Andric 23481ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) { 23581ad6265SDimitry Andric SmallVector<Value *, 4> Args; 23681ad6265SDimitry Andric for (auto &Op : I.operands()) 23781ad6265SDimitry Andric if (Op.get()->getType()->isSized()) 23881ad6265SDimitry Andric Args.push_back(Op); 239bdd1243dSDimitry Andric IRB->SetInsertPoint(&I); 24081ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_switch, {I.getOperand(0)->getType()}, 24181ad6265SDimitry Andric {Args}); 24281ad6265SDimitry Andric return &I; 24381ad6265SDimitry Andric } 24481ad6265SDimitry Andric 24581ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) { 24681ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 24781ad6265SDimitry Andric SmallVector<Value *, 4> Args; 24881ad6265SDimitry Andric Args.push_back(IRB->getInt1(I.isInBounds())); 24981ad6265SDimitry Andric for (auto &Op : I.operands()) 25081ad6265SDimitry Andric Args.push_back(Op); 25181ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args}); 25281ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 25381ad6265SDimitry Andric I.eraseFromParent(); 25481ad6265SDimitry Andric return NewI; 25581ad6265SDimitry Andric } 25681ad6265SDimitry Andric 25781ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) { 25881ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 25981ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 26081ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args}); 26181ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 26281ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 26381ad6265SDimitry Andric I.eraseFromParent(); 26481ad6265SDimitry Andric NewI->setName(InstName); 26581ad6265SDimitry Andric return NewI; 26681ad6265SDimitry Andric } 26781ad6265SDimitry Andric 26881ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) { 26981ad6265SDimitry Andric SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(), 27081ad6265SDimitry Andric I.getOperand(1)->getType(), 27181ad6265SDimitry Andric I.getOperand(2)->getType()}; 27281ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 27381ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_insertelt, {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 28181ad6265SDimitry Andric Instruction * 28281ad6265SDimitry Andric SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) { 28381ad6265SDimitry Andric SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(), 28481ad6265SDimitry Andric I.getIndexOperand()->getType()}; 28581ad6265SDimitry Andric SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()}; 28681ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args}); 28781ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 28881ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 28981ad6265SDimitry Andric I.eraseFromParent(); 29081ad6265SDimitry Andric NewI->setName(InstName); 29181ad6265SDimitry Andric return NewI; 29281ad6265SDimitry Andric } 29381ad6265SDimitry Andric 29481ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) { 29581ad6265SDimitry Andric SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()}; 29681ad6265SDimitry Andric SmallVector<Value *> Args; 29781ad6265SDimitry Andric for (auto &Op : I.operands()) 29881ad6265SDimitry Andric if (isa<UndefValue>(Op)) 29981ad6265SDimitry Andric Args.push_back(UndefValue::get(IRB->getInt32Ty())); 30081ad6265SDimitry Andric else 30181ad6265SDimitry Andric Args.push_back(Op); 30281ad6265SDimitry Andric for (auto &Op : I.indices()) 30381ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 30481ad6265SDimitry Andric Instruction *NewI = 30581ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args}); 30681ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 30781ad6265SDimitry Andric return NewI; 30881ad6265SDimitry Andric } 30981ad6265SDimitry Andric 31081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) { 31181ad6265SDimitry Andric SmallVector<Value *> Args; 31281ad6265SDimitry Andric for (auto &Op : I.operands()) 31381ad6265SDimitry Andric Args.push_back(Op); 31481ad6265SDimitry Andric for (auto &Op : I.indices()) 31581ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 31681ad6265SDimitry Andric auto *NewI = 31781ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args}); 31881ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 31981ad6265SDimitry Andric I.eraseFromParent(); 32081ad6265SDimitry Andric return NewI; 32181ad6265SDimitry Andric } 32281ad6265SDimitry Andric 32381ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) { 32481ad6265SDimitry Andric if (!I.getType()->isAggregateType()) 32581ad6265SDimitry Andric return &I; 32681ad6265SDimitry Andric TrackConstants = false; 32781ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 32881ad6265SDimitry Andric MachineMemOperand::Flags Flags = 32981ad6265SDimitry Andric TLI->getLoadMemOperandFlags(I, F->getParent()->getDataLayout()); 33081ad6265SDimitry Andric auto *NewI = 33181ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()}, 33281ad6265SDimitry Andric {I.getPointerOperand(), IRB->getInt16(Flags), 33381ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 33481ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 33581ad6265SDimitry Andric return NewI; 33681ad6265SDimitry Andric } 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) { 33981ad6265SDimitry Andric if (!AggrStores.contains(&I)) 34081ad6265SDimitry Andric return &I; 34181ad6265SDimitry Andric TrackConstants = false; 34281ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 34381ad6265SDimitry Andric MachineMemOperand::Flags Flags = 34481ad6265SDimitry Andric TLI->getStoreMemOperandFlags(I, F->getParent()->getDataLayout()); 34581ad6265SDimitry Andric auto *PtrOp = I.getPointerOperand(); 346fcaf7f86SDimitry Andric auto *NewI = IRB->CreateIntrinsic( 347fcaf7f86SDimitry Andric Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()}, 34881ad6265SDimitry Andric {I.getValueOperand(), PtrOp, IRB->getInt16(Flags), 34981ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 35081ad6265SDimitry Andric I.eraseFromParent(); 35181ad6265SDimitry Andric return NewI; 35281ad6265SDimitry Andric } 35381ad6265SDimitry Andric 35481ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) { 35581ad6265SDimitry Andric TrackConstants = false; 356bdd1243dSDimitry Andric Type *PtrTy = I.getType(); 357bdd1243dSDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {}); 358bdd1243dSDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 359bdd1243dSDimitry Andric I.replaceAllUsesWith(NewI); 360bdd1243dSDimitry Andric I.eraseFromParent(); 361bdd1243dSDimitry Andric NewI->setName(InstName); 362bdd1243dSDimitry Andric return NewI; 36381ad6265SDimitry Andric } 36481ad6265SDimitry Andric 365fcaf7f86SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { 366fcaf7f86SDimitry Andric assert(I.getType()->isAggregateType() && "Aggregate result is expected"); 367fcaf7f86SDimitry Andric SmallVector<Value *> Args; 368fcaf7f86SDimitry Andric for (auto &Op : I.operands()) 369fcaf7f86SDimitry Andric Args.push_back(Op); 370fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32(I.getSyncScopeID())); 371fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32( 372fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering())))); 373fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32( 374fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering())))); 375fcaf7f86SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_cmpxchg, 376fcaf7f86SDimitry Andric {I.getPointerOperand()->getType()}, {Args}); 377fcaf7f86SDimitry Andric replaceMemInstrUses(&I, NewI); 378fcaf7f86SDimitry Andric return NewI; 379fcaf7f86SDimitry Andric } 380fcaf7f86SDimitry Andric 381bdd1243dSDimitry Andric Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) { 382bdd1243dSDimitry Andric IRB->SetInsertPoint(&I); 383bdd1243dSDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unreachable, {}, {}); 384bdd1243dSDimitry Andric return &I; 385bdd1243dSDimitry Andric } 386bdd1243dSDimitry Andric 38781ad6265SDimitry Andric void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) { 38881ad6265SDimitry Andric // Skip special artifical variable llvm.global.annotations. 38981ad6265SDimitry Andric if (GV.getName() == "llvm.global.annotations") 39081ad6265SDimitry Andric return; 39181ad6265SDimitry Andric if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) { 39281ad6265SDimitry Andric Constant *Init = GV.getInitializer(); 39381ad6265SDimitry Andric Type *Ty = isAggrToReplace(Init) ? IRB->getInt32Ty() : Init->getType(); 39481ad6265SDimitry Andric Constant *Const = isAggrToReplace(Init) ? IRB->getInt32(1) : Init; 39581ad6265SDimitry Andric auto *InitInst = IRB->CreateIntrinsic(Intrinsic::spv_init_global, 39681ad6265SDimitry Andric {GV.getType(), Ty}, {&GV, Const}); 39781ad6265SDimitry Andric InitInst->setArgOperand(1, Init); 39881ad6265SDimitry Andric } 39981ad6265SDimitry Andric if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) && 40081ad6265SDimitry Andric GV.getNumUses() == 0) 40181ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV); 40281ad6265SDimitry Andric } 40381ad6265SDimitry Andric 404*5f757f3fSDimitry Andric void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I) { 405*5f757f3fSDimitry Andric if (I->getType()->isVoidTy() || !requireAssignPtrType(I)) 406*5f757f3fSDimitry Andric return; 407*5f757f3fSDimitry Andric 408*5f757f3fSDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 409*5f757f3fSDimitry Andric 410*5f757f3fSDimitry Andric Constant *EltTyConst; 411*5f757f3fSDimitry Andric unsigned AddressSpace = 0; 412*5f757f3fSDimitry Andric if (auto *AI = dyn_cast<AllocaInst>(I)) { 413*5f757f3fSDimitry Andric EltTyConst = Constant::getNullValue(AI->getAllocatedType()); 414*5f757f3fSDimitry Andric AddressSpace = AI->getAddressSpace(); 415*5f757f3fSDimitry Andric } else if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) { 416*5f757f3fSDimitry Andric EltTyConst = Constant::getNullValue(GEP->getResultElementType()); 417*5f757f3fSDimitry Andric AddressSpace = GEP->getPointerAddressSpace(); 418*5f757f3fSDimitry Andric } else { 419*5f757f3fSDimitry Andric llvm_unreachable("Unexpected instruction!"); 420*5f757f3fSDimitry Andric } 421*5f757f3fSDimitry Andric 422*5f757f3fSDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {I->getType()}, EltTyConst, I, 423*5f757f3fSDimitry Andric {IRB->getInt32(AddressSpace)}); 424*5f757f3fSDimitry Andric } 425*5f757f3fSDimitry Andric 42681ad6265SDimitry Andric void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) { 42781ad6265SDimitry Andric Type *Ty = I->getType(); 428*5f757f3fSDimitry Andric if (!Ty->isVoidTy() && requireAssignType(I) && !requireAssignPtrType(I)) { 42981ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 43081ad6265SDimitry Andric Type *TypeToAssign = Ty; 43181ad6265SDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(I)) { 43206c3fb27SDimitry Andric if (II->getIntrinsicID() == Intrinsic::spv_const_composite || 43306c3fb27SDimitry Andric II->getIntrinsicID() == Intrinsic::spv_undef) { 43481ad6265SDimitry Andric auto t = AggrConsts.find(II); 43581ad6265SDimitry Andric assert(t != AggrConsts.end()); 43681ad6265SDimitry Andric TypeToAssign = t->second->getType(); 43781ad6265SDimitry Andric } 43881ad6265SDimitry Andric } 43981ad6265SDimitry Andric Constant *Const = Constant::getNullValue(TypeToAssign); 440*5f757f3fSDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I, {}); 44181ad6265SDimitry Andric } 44281ad6265SDimitry Andric for (const auto &Op : I->operands()) { 44381ad6265SDimitry Andric if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) || 44481ad6265SDimitry Andric // Check GetElementPtrConstantExpr case. 44581ad6265SDimitry Andric (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) { 446bdd1243dSDimitry Andric setInsertPointSkippingPhis(*IRB, I); 447fcaf7f86SDimitry Andric if (isa<UndefValue>(Op) && Op->getType()->isAggregateType()) 448fcaf7f86SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op, 449*5f757f3fSDimitry Andric UndefValue::get(IRB->getInt32Ty()), {}); 450fcaf7f86SDimitry Andric else 451*5f757f3fSDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op, 452*5f757f3fSDimitry Andric {}); 45381ad6265SDimitry Andric } 45481ad6265SDimitry Andric } 45581ad6265SDimitry Andric } 45681ad6265SDimitry Andric 45781ad6265SDimitry Andric void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) { 45881ad6265SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(I); 45981ad6265SDimitry Andric if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite && 46081ad6265SDimitry Andric TrackConstants) { 46181ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 46281ad6265SDimitry Andric Type *Ty = IRB->getInt32Ty(); 46381ad6265SDimitry Andric auto t = AggrConsts.find(I); 46481ad6265SDimitry Andric assert(t != AggrConsts.end()); 465*5f757f3fSDimitry Andric auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, 466*5f757f3fSDimitry Andric t->second, I, {}); 46781ad6265SDimitry Andric I->replaceAllUsesWith(NewOp); 46881ad6265SDimitry Andric NewOp->setArgOperand(0, I); 46981ad6265SDimitry Andric } 47081ad6265SDimitry Andric for (const auto &Op : I->operands()) { 47181ad6265SDimitry Andric if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) || 47281ad6265SDimitry Andric isa<PHINode>(I) || isa<SwitchInst>(I)) 47381ad6265SDimitry Andric TrackConstants = false; 474fcaf7f86SDimitry Andric if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) { 47581ad6265SDimitry Andric unsigned OpNo = Op.getOperandNo(); 47681ad6265SDimitry Andric if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) || 47781ad6265SDimitry Andric (II->paramHasAttr(OpNo, Attribute::ImmArg)))) 47881ad6265SDimitry Andric continue; 47981ad6265SDimitry Andric IRB->SetInsertPoint(I); 48081ad6265SDimitry Andric auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, 481*5f757f3fSDimitry Andric {Op->getType(), Op->getType()}, Op, Op, {}); 48281ad6265SDimitry Andric I->setOperand(OpNo, NewOp); 48381ad6265SDimitry Andric } 48481ad6265SDimitry Andric } 48581ad6265SDimitry Andric if (I->hasName()) { 48681ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 48781ad6265SDimitry Andric std::vector<Value *> Args = {I}; 48881ad6265SDimitry Andric addStringImm(I->getName(), *IRB, Args); 48981ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args); 49081ad6265SDimitry Andric } 49181ad6265SDimitry Andric } 49281ad6265SDimitry Andric 49381ad6265SDimitry Andric bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { 49481ad6265SDimitry Andric if (Func.isDeclaration()) 49581ad6265SDimitry Andric return false; 49681ad6265SDimitry Andric F = &Func; 49781ad6265SDimitry Andric IRB = new IRBuilder<>(Func.getContext()); 49881ad6265SDimitry Andric AggrConsts.clear(); 49981ad6265SDimitry Andric AggrStores.clear(); 50081ad6265SDimitry Andric 501fcaf7f86SDimitry Andric // StoreInst's operand type can be changed during the next transformations, 502fcaf7f86SDimitry Andric // so we need to store it in the set. Also store already transformed types. 503fcaf7f86SDimitry Andric for (auto &I : instructions(Func)) { 504fcaf7f86SDimitry Andric StoreInst *SI = dyn_cast<StoreInst>(&I); 505fcaf7f86SDimitry Andric if (!SI) 506fcaf7f86SDimitry Andric continue; 507fcaf7f86SDimitry Andric Type *ElTy = SI->getValueOperand()->getType(); 508*5f757f3fSDimitry Andric if (ElTy->isAggregateType() || ElTy->isVectorTy()) 509fcaf7f86SDimitry Andric AggrStores.insert(&I); 510fcaf7f86SDimitry Andric } 51181ad6265SDimitry Andric 512*5f757f3fSDimitry Andric IRB->SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin()); 51381ad6265SDimitry Andric for (auto &GV : Func.getParent()->globals()) 51481ad6265SDimitry Andric processGlobalValue(GV); 51581ad6265SDimitry Andric 51606c3fb27SDimitry Andric preprocessUndefs(); 51781ad6265SDimitry Andric preprocessCompositeConstants(); 51881ad6265SDimitry Andric SmallVector<Instruction *> Worklist; 51981ad6265SDimitry Andric for (auto &I : instructions(Func)) 52081ad6265SDimitry Andric Worklist.push_back(&I); 52181ad6265SDimitry Andric 522*5f757f3fSDimitry Andric for (auto &I : Worklist) { 523*5f757f3fSDimitry Andric insertAssignPtrTypeIntrs(I); 52481ad6265SDimitry Andric insertAssignTypeIntrs(I); 525*5f757f3fSDimitry Andric } 52681ad6265SDimitry Andric 52781ad6265SDimitry Andric for (auto *I : Worklist) { 52881ad6265SDimitry Andric TrackConstants = true; 52981ad6265SDimitry Andric if (!I->getType()->isVoidTy() || isa<StoreInst>(I)) 53081ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 53181ad6265SDimitry Andric I = visit(*I); 53281ad6265SDimitry Andric processInstrAfterVisit(I); 53381ad6265SDimitry Andric } 53481ad6265SDimitry Andric return true; 53581ad6265SDimitry Andric } 53681ad6265SDimitry Andric 53781ad6265SDimitry Andric FunctionPass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) { 53881ad6265SDimitry Andric return new SPIRVEmitIntrinsics(TM); 53981ad6265SDimitry Andric } 540