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(); 59*06c3fb27SDimitry Andric void preprocessUndefs(); 6081ad6265SDimitry Andric CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types, 6181ad6265SDimitry Andric Value *Arg, Value *Arg2) { 6281ad6265SDimitry Andric ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg); 6381ad6265SDimitry Andric MDTuple *TyMD = MDNode::get(F->getContext(), CM); 6481ad6265SDimitry Andric MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD); 6581ad6265SDimitry Andric return IRB->CreateIntrinsic(IntrID, {Types}, {Arg2, VMD}); 6681ad6265SDimitry Andric } 6781ad6265SDimitry Andric void replaceMemInstrUses(Instruction *Old, Instruction *New); 6881ad6265SDimitry Andric void processInstrAfterVisit(Instruction *I); 6981ad6265SDimitry Andric void insertAssignTypeIntrs(Instruction *I); 7081ad6265SDimitry Andric void processGlobalValue(GlobalVariable &GV); 7181ad6265SDimitry Andric 7281ad6265SDimitry Andric public: 7381ad6265SDimitry Andric static char ID; 7481ad6265SDimitry Andric SPIRVEmitIntrinsics() : FunctionPass(ID) { 7581ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 7681ad6265SDimitry Andric } 7781ad6265SDimitry Andric SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : FunctionPass(ID), TM(_TM) { 7881ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 7981ad6265SDimitry Andric } 8081ad6265SDimitry Andric Instruction *visitInstruction(Instruction &I) { return &I; } 8181ad6265SDimitry Andric Instruction *visitSwitchInst(SwitchInst &I); 8281ad6265SDimitry Andric Instruction *visitGetElementPtrInst(GetElementPtrInst &I); 8381ad6265SDimitry Andric Instruction *visitBitCastInst(BitCastInst &I); 8481ad6265SDimitry Andric Instruction *visitInsertElementInst(InsertElementInst &I); 8581ad6265SDimitry Andric Instruction *visitExtractElementInst(ExtractElementInst &I); 8681ad6265SDimitry Andric Instruction *visitInsertValueInst(InsertValueInst &I); 8781ad6265SDimitry Andric Instruction *visitExtractValueInst(ExtractValueInst &I); 8881ad6265SDimitry Andric Instruction *visitLoadInst(LoadInst &I); 8981ad6265SDimitry Andric Instruction *visitStoreInst(StoreInst &I); 9081ad6265SDimitry Andric Instruction *visitAllocaInst(AllocaInst &I); 91fcaf7f86SDimitry Andric Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); 92bdd1243dSDimitry Andric Instruction *visitUnreachableInst(UnreachableInst &I); 9381ad6265SDimitry Andric bool runOnFunction(Function &F) override; 9481ad6265SDimitry Andric }; 9581ad6265SDimitry Andric } // namespace 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric char SPIRVEmitIntrinsics::ID = 0; 9881ad6265SDimitry Andric 9981ad6265SDimitry Andric INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics", 10081ad6265SDimitry Andric false, false) 10181ad6265SDimitry Andric 10281ad6265SDimitry Andric static inline bool isAssignTypeInstr(const Instruction *I) { 10381ad6265SDimitry Andric return isa<IntrinsicInst>(I) && 10481ad6265SDimitry Andric cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type; 10581ad6265SDimitry Andric } 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric static bool isMemInstrToReplace(Instruction *I) { 10881ad6265SDimitry Andric return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) || 109fcaf7f86SDimitry Andric isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I); 11081ad6265SDimitry Andric } 11181ad6265SDimitry Andric 11281ad6265SDimitry Andric static bool isAggrToReplace(const Value *V) { 11381ad6265SDimitry Andric return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) || 11481ad6265SDimitry Andric (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()); 11581ad6265SDimitry Andric } 11681ad6265SDimitry Andric 11781ad6265SDimitry Andric static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) { 11881ad6265SDimitry Andric if (isa<PHINode>(I)) 11981ad6265SDimitry Andric B.SetInsertPoint(I->getParent(), I->getParent()->getFirstInsertionPt()); 12081ad6265SDimitry Andric else 12181ad6265SDimitry Andric B.SetInsertPoint(I); 12281ad6265SDimitry Andric } 12381ad6265SDimitry Andric 12481ad6265SDimitry Andric static bool requireAssignType(Instruction *I) { 12581ad6265SDimitry Andric IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I); 12681ad6265SDimitry Andric if (Intr) { 12781ad6265SDimitry Andric switch (Intr->getIntrinsicID()) { 12881ad6265SDimitry Andric case Intrinsic::invariant_start: 12981ad6265SDimitry Andric case Intrinsic::invariant_end: 13081ad6265SDimitry Andric return false; 13181ad6265SDimitry Andric } 13281ad6265SDimitry Andric } 13381ad6265SDimitry Andric return true; 13481ad6265SDimitry Andric } 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old, 13781ad6265SDimitry Andric Instruction *New) { 13881ad6265SDimitry Andric while (!Old->user_empty()) { 13981ad6265SDimitry Andric auto *U = Old->user_back(); 140fcaf7f86SDimitry Andric if (isAssignTypeInstr(U)) { 14181ad6265SDimitry Andric IRB->SetInsertPoint(U); 14281ad6265SDimitry Andric SmallVector<Value *, 2> Args = {New, U->getOperand(1)}; 14381ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args); 14481ad6265SDimitry Andric U->eraseFromParent(); 145fcaf7f86SDimitry Andric } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) || 146fcaf7f86SDimitry Andric isa<CallInst>(U)) { 147fcaf7f86SDimitry Andric U->replaceUsesOfWith(Old, New); 14881ad6265SDimitry Andric } else { 14981ad6265SDimitry Andric llvm_unreachable("illegal aggregate intrinsic user"); 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric Old->eraseFromParent(); 15381ad6265SDimitry Andric } 15481ad6265SDimitry Andric 155*06c3fb27SDimitry Andric void SPIRVEmitIntrinsics::preprocessUndefs() { 156*06c3fb27SDimitry Andric std::queue<Instruction *> Worklist; 157*06c3fb27SDimitry Andric for (auto &I : instructions(F)) 158*06c3fb27SDimitry Andric Worklist.push(&I); 159*06c3fb27SDimitry Andric 160*06c3fb27SDimitry Andric while (!Worklist.empty()) { 161*06c3fb27SDimitry Andric Instruction *I = Worklist.front(); 162*06c3fb27SDimitry Andric Worklist.pop(); 163*06c3fb27SDimitry Andric 164*06c3fb27SDimitry Andric for (auto &Op : I->operands()) { 165*06c3fb27SDimitry Andric auto *AggrUndef = dyn_cast<UndefValue>(Op); 166*06c3fb27SDimitry Andric if (!AggrUndef || !Op->getType()->isAggregateType()) 167*06c3fb27SDimitry Andric continue; 168*06c3fb27SDimitry Andric 169*06c3fb27SDimitry Andric IRB->SetInsertPoint(I); 170*06c3fb27SDimitry Andric auto *IntrUndef = IRB->CreateIntrinsic(Intrinsic::spv_undef, {}, {}); 171*06c3fb27SDimitry Andric Worklist.push(IntrUndef); 172*06c3fb27SDimitry Andric I->replaceUsesOfWith(Op, IntrUndef); 173*06c3fb27SDimitry Andric AggrConsts[IntrUndef] = AggrUndef; 174*06c3fb27SDimitry Andric } 175*06c3fb27SDimitry Andric } 176*06c3fb27SDimitry Andric } 177*06c3fb27SDimitry Andric 17881ad6265SDimitry Andric void SPIRVEmitIntrinsics::preprocessCompositeConstants() { 17981ad6265SDimitry Andric std::queue<Instruction *> Worklist; 18081ad6265SDimitry Andric for (auto &I : instructions(F)) 18181ad6265SDimitry Andric Worklist.push(&I); 18281ad6265SDimitry Andric 18381ad6265SDimitry Andric while (!Worklist.empty()) { 18481ad6265SDimitry Andric auto *I = Worklist.front(); 18581ad6265SDimitry Andric assert(I); 18681ad6265SDimitry Andric bool KeepInst = false; 18781ad6265SDimitry Andric for (const auto &Op : I->operands()) { 18881ad6265SDimitry Andric auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &I, &Op, 18981ad6265SDimitry Andric this](Constant *AggrC, 19081ad6265SDimitry Andric ArrayRef<Value *> Args) { 19181ad6265SDimitry Andric IRB->SetInsertPoint(I); 19281ad6265SDimitry Andric auto *CCI = 19381ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args}); 19481ad6265SDimitry Andric Worklist.push(CCI); 19581ad6265SDimitry Andric I->replaceUsesOfWith(Op, CCI); 19681ad6265SDimitry Andric KeepInst = true; 19781ad6265SDimitry Andric AggrConsts[CCI] = AggrC; 19881ad6265SDimitry Andric }; 19981ad6265SDimitry Andric 20081ad6265SDimitry Andric if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) { 20181ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 20281ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 20381ad6265SDimitry Andric } else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) { 20481ad6265SDimitry Andric SmallVector<Value *> Args; 20581ad6265SDimitry Andric for (unsigned i = 0; i < AggrC->getNumElements(); ++i) 20681ad6265SDimitry Andric Args.push_back(AggrC->getElementAsConstant(i)); 20781ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 20881ad6265SDimitry Andric } else if (isa<ConstantAggregateZero>(Op) && 20981ad6265SDimitry Andric !Op->getType()->isVectorTy()) { 21081ad6265SDimitry Andric auto *AggrC = cast<ConstantAggregateZero>(Op); 21181ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 21281ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 21381ad6265SDimitry Andric } 21481ad6265SDimitry Andric } 21581ad6265SDimitry Andric if (!KeepInst) 21681ad6265SDimitry Andric Worklist.pop(); 21781ad6265SDimitry Andric } 21881ad6265SDimitry Andric } 21981ad6265SDimitry Andric 22081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) { 22181ad6265SDimitry Andric SmallVector<Value *, 4> Args; 22281ad6265SDimitry Andric for (auto &Op : I.operands()) 22381ad6265SDimitry Andric if (Op.get()->getType()->isSized()) 22481ad6265SDimitry Andric Args.push_back(Op); 225bdd1243dSDimitry Andric IRB->SetInsertPoint(&I); 22681ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_switch, {I.getOperand(0)->getType()}, 22781ad6265SDimitry Andric {Args}); 22881ad6265SDimitry Andric return &I; 22981ad6265SDimitry Andric } 23081ad6265SDimitry Andric 23181ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) { 23281ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 23381ad6265SDimitry Andric SmallVector<Value *, 4> Args; 23481ad6265SDimitry Andric Args.push_back(IRB->getInt1(I.isInBounds())); 23581ad6265SDimitry Andric for (auto &Op : I.operands()) 23681ad6265SDimitry Andric Args.push_back(Op); 23781ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args}); 23881ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 23981ad6265SDimitry Andric I.eraseFromParent(); 24081ad6265SDimitry Andric return NewI; 24181ad6265SDimitry Andric } 24281ad6265SDimitry Andric 24381ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) { 24481ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 24581ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 24681ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args}); 24781ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 24881ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 24981ad6265SDimitry Andric I.eraseFromParent(); 25081ad6265SDimitry Andric NewI->setName(InstName); 25181ad6265SDimitry Andric return NewI; 25281ad6265SDimitry Andric } 25381ad6265SDimitry Andric 25481ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) { 25581ad6265SDimitry Andric SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(), 25681ad6265SDimitry Andric I.getOperand(1)->getType(), 25781ad6265SDimitry Andric I.getOperand(2)->getType()}; 25881ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 25981ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args}); 26081ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 26181ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 26281ad6265SDimitry Andric I.eraseFromParent(); 26381ad6265SDimitry Andric NewI->setName(InstName); 26481ad6265SDimitry Andric return NewI; 26581ad6265SDimitry Andric } 26681ad6265SDimitry Andric 26781ad6265SDimitry Andric Instruction * 26881ad6265SDimitry Andric SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) { 26981ad6265SDimitry Andric SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(), 27081ad6265SDimitry Andric I.getIndexOperand()->getType()}; 27181ad6265SDimitry Andric SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()}; 27281ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args}); 27381ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 27481ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 27581ad6265SDimitry Andric I.eraseFromParent(); 27681ad6265SDimitry Andric NewI->setName(InstName); 27781ad6265SDimitry Andric return NewI; 27881ad6265SDimitry Andric } 27981ad6265SDimitry Andric 28081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) { 28181ad6265SDimitry Andric SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()}; 28281ad6265SDimitry Andric SmallVector<Value *> Args; 28381ad6265SDimitry Andric for (auto &Op : I.operands()) 28481ad6265SDimitry Andric if (isa<UndefValue>(Op)) 28581ad6265SDimitry Andric Args.push_back(UndefValue::get(IRB->getInt32Ty())); 28681ad6265SDimitry Andric else 28781ad6265SDimitry Andric Args.push_back(Op); 28881ad6265SDimitry Andric for (auto &Op : I.indices()) 28981ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 29081ad6265SDimitry Andric Instruction *NewI = 29181ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args}); 29281ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 29381ad6265SDimitry Andric return NewI; 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric 29681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) { 29781ad6265SDimitry Andric SmallVector<Value *> Args; 29881ad6265SDimitry Andric for (auto &Op : I.operands()) 29981ad6265SDimitry Andric Args.push_back(Op); 30081ad6265SDimitry Andric for (auto &Op : I.indices()) 30181ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 30281ad6265SDimitry Andric auto *NewI = 30381ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args}); 30481ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 30581ad6265SDimitry Andric I.eraseFromParent(); 30681ad6265SDimitry Andric return NewI; 30781ad6265SDimitry Andric } 30881ad6265SDimitry Andric 30981ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) { 31081ad6265SDimitry Andric if (!I.getType()->isAggregateType()) 31181ad6265SDimitry Andric return &I; 31281ad6265SDimitry Andric TrackConstants = false; 31381ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 31481ad6265SDimitry Andric MachineMemOperand::Flags Flags = 31581ad6265SDimitry Andric TLI->getLoadMemOperandFlags(I, F->getParent()->getDataLayout()); 31681ad6265SDimitry Andric auto *NewI = 31781ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()}, 31881ad6265SDimitry Andric {I.getPointerOperand(), IRB->getInt16(Flags), 31981ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 32081ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 32181ad6265SDimitry Andric return NewI; 32281ad6265SDimitry Andric } 32381ad6265SDimitry Andric 32481ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) { 32581ad6265SDimitry Andric if (!AggrStores.contains(&I)) 32681ad6265SDimitry Andric return &I; 32781ad6265SDimitry Andric TrackConstants = false; 32881ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 32981ad6265SDimitry Andric MachineMemOperand::Flags Flags = 33081ad6265SDimitry Andric TLI->getStoreMemOperandFlags(I, F->getParent()->getDataLayout()); 33181ad6265SDimitry Andric auto *PtrOp = I.getPointerOperand(); 332fcaf7f86SDimitry Andric auto *NewI = IRB->CreateIntrinsic( 333fcaf7f86SDimitry Andric Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()}, 33481ad6265SDimitry Andric {I.getValueOperand(), PtrOp, IRB->getInt16(Flags), 33581ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 33681ad6265SDimitry Andric I.eraseFromParent(); 33781ad6265SDimitry Andric return NewI; 33881ad6265SDimitry Andric } 33981ad6265SDimitry Andric 34081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) { 34181ad6265SDimitry Andric TrackConstants = false; 342bdd1243dSDimitry Andric Type *PtrTy = I.getType(); 343bdd1243dSDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {}); 344bdd1243dSDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 345bdd1243dSDimitry Andric I.replaceAllUsesWith(NewI); 346bdd1243dSDimitry Andric I.eraseFromParent(); 347bdd1243dSDimitry Andric NewI->setName(InstName); 348bdd1243dSDimitry Andric return NewI; 34981ad6265SDimitry Andric } 35081ad6265SDimitry Andric 351fcaf7f86SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { 352fcaf7f86SDimitry Andric assert(I.getType()->isAggregateType() && "Aggregate result is expected"); 353fcaf7f86SDimitry Andric SmallVector<Value *> Args; 354fcaf7f86SDimitry Andric for (auto &Op : I.operands()) 355fcaf7f86SDimitry Andric Args.push_back(Op); 356fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32(I.getSyncScopeID())); 357fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32( 358fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering())))); 359fcaf7f86SDimitry Andric Args.push_back(IRB->getInt32( 360fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering())))); 361fcaf7f86SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_cmpxchg, 362fcaf7f86SDimitry Andric {I.getPointerOperand()->getType()}, {Args}); 363fcaf7f86SDimitry Andric replaceMemInstrUses(&I, NewI); 364fcaf7f86SDimitry Andric return NewI; 365fcaf7f86SDimitry Andric } 366fcaf7f86SDimitry Andric 367bdd1243dSDimitry Andric Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) { 368bdd1243dSDimitry Andric IRB->SetInsertPoint(&I); 369bdd1243dSDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unreachable, {}, {}); 370bdd1243dSDimitry Andric return &I; 371bdd1243dSDimitry Andric } 372bdd1243dSDimitry Andric 37381ad6265SDimitry Andric void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) { 37481ad6265SDimitry Andric // Skip special artifical variable llvm.global.annotations. 37581ad6265SDimitry Andric if (GV.getName() == "llvm.global.annotations") 37681ad6265SDimitry Andric return; 37781ad6265SDimitry Andric if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) { 37881ad6265SDimitry Andric Constant *Init = GV.getInitializer(); 37981ad6265SDimitry Andric Type *Ty = isAggrToReplace(Init) ? IRB->getInt32Ty() : Init->getType(); 38081ad6265SDimitry Andric Constant *Const = isAggrToReplace(Init) ? IRB->getInt32(1) : Init; 38181ad6265SDimitry Andric auto *InitInst = IRB->CreateIntrinsic(Intrinsic::spv_init_global, 38281ad6265SDimitry Andric {GV.getType(), Ty}, {&GV, Const}); 38381ad6265SDimitry Andric InitInst->setArgOperand(1, Init); 38481ad6265SDimitry Andric } 38581ad6265SDimitry Andric if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) && 38681ad6265SDimitry Andric GV.getNumUses() == 0) 38781ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV); 38881ad6265SDimitry Andric } 38981ad6265SDimitry Andric 39081ad6265SDimitry Andric void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) { 39181ad6265SDimitry Andric Type *Ty = I->getType(); 39281ad6265SDimitry Andric if (!Ty->isVoidTy() && requireAssignType(I)) { 39381ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 39481ad6265SDimitry Andric Type *TypeToAssign = Ty; 39581ad6265SDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(I)) { 396*06c3fb27SDimitry Andric if (II->getIntrinsicID() == Intrinsic::spv_const_composite || 397*06c3fb27SDimitry Andric II->getIntrinsicID() == Intrinsic::spv_undef) { 39881ad6265SDimitry Andric auto t = AggrConsts.find(II); 39981ad6265SDimitry Andric assert(t != AggrConsts.end()); 40081ad6265SDimitry Andric TypeToAssign = t->second->getType(); 40181ad6265SDimitry Andric } 40281ad6265SDimitry Andric } 40381ad6265SDimitry Andric Constant *Const = Constant::getNullValue(TypeToAssign); 40481ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I); 40581ad6265SDimitry Andric } 40681ad6265SDimitry Andric for (const auto &Op : I->operands()) { 40781ad6265SDimitry Andric if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) || 40881ad6265SDimitry Andric // Check GetElementPtrConstantExpr case. 40981ad6265SDimitry Andric (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) { 410bdd1243dSDimitry Andric setInsertPointSkippingPhis(*IRB, I); 411fcaf7f86SDimitry Andric if (isa<UndefValue>(Op) && Op->getType()->isAggregateType()) 412fcaf7f86SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op, 413fcaf7f86SDimitry Andric UndefValue::get(IRB->getInt32Ty())); 414fcaf7f86SDimitry Andric else 41581ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op); 41681ad6265SDimitry Andric } 41781ad6265SDimitry Andric } 41881ad6265SDimitry Andric } 41981ad6265SDimitry Andric 42081ad6265SDimitry Andric void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) { 42181ad6265SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(I); 42281ad6265SDimitry Andric if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite && 42381ad6265SDimitry Andric TrackConstants) { 42481ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 42581ad6265SDimitry Andric Type *Ty = IRB->getInt32Ty(); 42681ad6265SDimitry Andric auto t = AggrConsts.find(I); 42781ad6265SDimitry Andric assert(t != AggrConsts.end()); 42881ad6265SDimitry Andric auto *NewOp = 42981ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, t->second, I); 43081ad6265SDimitry Andric I->replaceAllUsesWith(NewOp); 43181ad6265SDimitry Andric NewOp->setArgOperand(0, I); 43281ad6265SDimitry Andric } 43381ad6265SDimitry Andric for (const auto &Op : I->operands()) { 43481ad6265SDimitry Andric if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) || 43581ad6265SDimitry Andric isa<PHINode>(I) || isa<SwitchInst>(I)) 43681ad6265SDimitry Andric TrackConstants = false; 437fcaf7f86SDimitry Andric if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) { 43881ad6265SDimitry Andric unsigned OpNo = Op.getOperandNo(); 43981ad6265SDimitry Andric if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) || 44081ad6265SDimitry Andric (II->paramHasAttr(OpNo, Attribute::ImmArg)))) 44181ad6265SDimitry Andric continue; 44281ad6265SDimitry Andric IRB->SetInsertPoint(I); 44381ad6265SDimitry Andric auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, 44481ad6265SDimitry Andric {Op->getType(), Op->getType()}, Op, Op); 44581ad6265SDimitry Andric I->setOperand(OpNo, NewOp); 44681ad6265SDimitry Andric } 44781ad6265SDimitry Andric } 44881ad6265SDimitry Andric if (I->hasName()) { 44981ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 45081ad6265SDimitry Andric std::vector<Value *> Args = {I}; 45181ad6265SDimitry Andric addStringImm(I->getName(), *IRB, Args); 45281ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args); 45381ad6265SDimitry Andric } 45481ad6265SDimitry Andric } 45581ad6265SDimitry Andric 45681ad6265SDimitry Andric bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { 45781ad6265SDimitry Andric if (Func.isDeclaration()) 45881ad6265SDimitry Andric return false; 45981ad6265SDimitry Andric F = &Func; 46081ad6265SDimitry Andric IRB = new IRBuilder<>(Func.getContext()); 46181ad6265SDimitry Andric AggrConsts.clear(); 46281ad6265SDimitry Andric AggrStores.clear(); 46381ad6265SDimitry Andric 464fcaf7f86SDimitry Andric // StoreInst's operand type can be changed during the next transformations, 465fcaf7f86SDimitry Andric // so we need to store it in the set. Also store already transformed types. 466fcaf7f86SDimitry Andric for (auto &I : instructions(Func)) { 467fcaf7f86SDimitry Andric StoreInst *SI = dyn_cast<StoreInst>(&I); 468fcaf7f86SDimitry Andric if (!SI) 469fcaf7f86SDimitry Andric continue; 470fcaf7f86SDimitry Andric Type *ElTy = SI->getValueOperand()->getType(); 471fcaf7f86SDimitry Andric PointerType *PTy = cast<PointerType>(SI->getOperand(1)->getType()); 472fcaf7f86SDimitry Andric if (ElTy->isAggregateType() || ElTy->isVectorTy() || 473fcaf7f86SDimitry Andric !PTy->isOpaqueOrPointeeTypeMatches(ElTy)) 474fcaf7f86SDimitry Andric AggrStores.insert(&I); 475fcaf7f86SDimitry Andric } 47681ad6265SDimitry Andric 477fcaf7f86SDimitry Andric IRB->SetInsertPoint(&Func.getEntryBlock().front()); 47881ad6265SDimitry Andric for (auto &GV : Func.getParent()->globals()) 47981ad6265SDimitry Andric processGlobalValue(GV); 48081ad6265SDimitry Andric 481*06c3fb27SDimitry Andric preprocessUndefs(); 48281ad6265SDimitry Andric preprocessCompositeConstants(); 48381ad6265SDimitry Andric SmallVector<Instruction *> Worklist; 48481ad6265SDimitry Andric for (auto &I : instructions(Func)) 48581ad6265SDimitry Andric Worklist.push_back(&I); 48681ad6265SDimitry Andric 48781ad6265SDimitry Andric for (auto &I : Worklist) 48881ad6265SDimitry Andric insertAssignTypeIntrs(I); 48981ad6265SDimitry Andric 49081ad6265SDimitry Andric for (auto *I : Worklist) { 49181ad6265SDimitry Andric TrackConstants = true; 49281ad6265SDimitry Andric if (!I->getType()->isVoidTy() || isa<StoreInst>(I)) 49381ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 49481ad6265SDimitry Andric I = visit(*I); 49581ad6265SDimitry Andric processInstrAfterVisit(I); 49681ad6265SDimitry Andric } 49781ad6265SDimitry Andric return true; 49881ad6265SDimitry Andric } 49981ad6265SDimitry Andric 50081ad6265SDimitry Andric FunctionPass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) { 50181ad6265SDimitry Andric return new SPIRVEmitIntrinsics(TM); 50281ad6265SDimitry Andric } 503