1*81ad6265SDimitry Andric //===-- SPIRVEmitIntrinsics.cpp - emit SPIRV intrinsics ---------*- C++ -*-===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // The pass emits SPIRV intrinsics keeping essential high-level information for 10*81ad6265SDimitry Andric // the translation of LLVM IR to SPIR-V. 11*81ad6265SDimitry Andric // 12*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 13*81ad6265SDimitry Andric 14*81ad6265SDimitry Andric #include "SPIRV.h" 15*81ad6265SDimitry Andric #include "SPIRVTargetMachine.h" 16*81ad6265SDimitry Andric #include "SPIRVUtils.h" 17*81ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h" 18*81ad6265SDimitry Andric #include "llvm/IR/InstIterator.h" 19*81ad6265SDimitry Andric #include "llvm/IR/InstVisitor.h" 20*81ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h" 21*81ad6265SDimitry Andric 22*81ad6265SDimitry Andric #include <queue> 23*81ad6265SDimitry Andric 24*81ad6265SDimitry Andric // This pass performs the following transformation on LLVM IR level required 25*81ad6265SDimitry Andric // for the following translation to SPIR-V: 26*81ad6265SDimitry Andric // - replaces direct usages of aggregate constants with target-specific 27*81ad6265SDimitry Andric // intrinsics; 28*81ad6265SDimitry Andric // - replaces aggregates-related instructions (extract/insert, ld/st, etc) 29*81ad6265SDimitry Andric // with a target-specific intrinsics; 30*81ad6265SDimitry Andric // - emits intrinsics for the global variable initializers since IRTranslator 31*81ad6265SDimitry Andric // doesn't handle them and it's not very convenient to translate them 32*81ad6265SDimitry Andric // ourselves; 33*81ad6265SDimitry Andric // - emits intrinsics to keep track of the string names assigned to the values; 34*81ad6265SDimitry Andric // - emits intrinsics to keep track of constants (this is necessary to have an 35*81ad6265SDimitry Andric // LLVM IR constant after the IRTranslation is completed) for their further 36*81ad6265SDimitry Andric // deduplication; 37*81ad6265SDimitry Andric // - emits intrinsics to keep track of original LLVM types of the values 38*81ad6265SDimitry Andric // to be able to emit proper SPIR-V types eventually. 39*81ad6265SDimitry Andric // 40*81ad6265SDimitry Andric // TODO: consider removing spv.track.constant in favor of spv.assign.type. 41*81ad6265SDimitry Andric 42*81ad6265SDimitry Andric using namespace llvm; 43*81ad6265SDimitry Andric 44*81ad6265SDimitry Andric namespace llvm { 45*81ad6265SDimitry Andric void initializeSPIRVEmitIntrinsicsPass(PassRegistry &); 46*81ad6265SDimitry Andric } // namespace llvm 47*81ad6265SDimitry Andric 48*81ad6265SDimitry Andric namespace { 49*81ad6265SDimitry Andric class SPIRVEmitIntrinsics 50*81ad6265SDimitry Andric : public FunctionPass, 51*81ad6265SDimitry Andric public InstVisitor<SPIRVEmitIntrinsics, Instruction *> { 52*81ad6265SDimitry Andric SPIRVTargetMachine *TM = nullptr; 53*81ad6265SDimitry Andric IRBuilder<> *IRB = nullptr; 54*81ad6265SDimitry Andric Function *F = nullptr; 55*81ad6265SDimitry Andric bool TrackConstants = true; 56*81ad6265SDimitry Andric DenseMap<Instruction *, Constant *> AggrConsts; 57*81ad6265SDimitry Andric DenseSet<Instruction *> AggrStores; 58*81ad6265SDimitry Andric void preprocessCompositeConstants(); 59*81ad6265SDimitry Andric CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types, 60*81ad6265SDimitry Andric Value *Arg, Value *Arg2) { 61*81ad6265SDimitry Andric ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg); 62*81ad6265SDimitry Andric MDTuple *TyMD = MDNode::get(F->getContext(), CM); 63*81ad6265SDimitry Andric MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD); 64*81ad6265SDimitry Andric return IRB->CreateIntrinsic(IntrID, {Types}, {Arg2, VMD}); 65*81ad6265SDimitry Andric } 66*81ad6265SDimitry Andric void replaceMemInstrUses(Instruction *Old, Instruction *New); 67*81ad6265SDimitry Andric void processInstrAfterVisit(Instruction *I); 68*81ad6265SDimitry Andric void insertAssignTypeIntrs(Instruction *I); 69*81ad6265SDimitry Andric void processGlobalValue(GlobalVariable &GV); 70*81ad6265SDimitry Andric 71*81ad6265SDimitry Andric public: 72*81ad6265SDimitry Andric static char ID; 73*81ad6265SDimitry Andric SPIRVEmitIntrinsics() : FunctionPass(ID) { 74*81ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 75*81ad6265SDimitry Andric } 76*81ad6265SDimitry Andric SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : FunctionPass(ID), TM(_TM) { 77*81ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 78*81ad6265SDimitry Andric } 79*81ad6265SDimitry Andric Instruction *visitInstruction(Instruction &I) { return &I; } 80*81ad6265SDimitry Andric Instruction *visitSwitchInst(SwitchInst &I); 81*81ad6265SDimitry Andric Instruction *visitGetElementPtrInst(GetElementPtrInst &I); 82*81ad6265SDimitry Andric Instruction *visitBitCastInst(BitCastInst &I); 83*81ad6265SDimitry Andric Instruction *visitInsertElementInst(InsertElementInst &I); 84*81ad6265SDimitry Andric Instruction *visitExtractElementInst(ExtractElementInst &I); 85*81ad6265SDimitry Andric Instruction *visitInsertValueInst(InsertValueInst &I); 86*81ad6265SDimitry Andric Instruction *visitExtractValueInst(ExtractValueInst &I); 87*81ad6265SDimitry Andric Instruction *visitLoadInst(LoadInst &I); 88*81ad6265SDimitry Andric Instruction *visitStoreInst(StoreInst &I); 89*81ad6265SDimitry Andric Instruction *visitAllocaInst(AllocaInst &I); 90*81ad6265SDimitry Andric bool runOnFunction(Function &F) override; 91*81ad6265SDimitry Andric }; 92*81ad6265SDimitry Andric } // namespace 93*81ad6265SDimitry Andric 94*81ad6265SDimitry Andric char SPIRVEmitIntrinsics::ID = 0; 95*81ad6265SDimitry Andric 96*81ad6265SDimitry Andric INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics", 97*81ad6265SDimitry Andric false, false) 98*81ad6265SDimitry Andric 99*81ad6265SDimitry Andric static inline bool isAssignTypeInstr(const Instruction *I) { 100*81ad6265SDimitry Andric return isa<IntrinsicInst>(I) && 101*81ad6265SDimitry Andric cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type; 102*81ad6265SDimitry Andric } 103*81ad6265SDimitry Andric 104*81ad6265SDimitry Andric static bool isMemInstrToReplace(Instruction *I) { 105*81ad6265SDimitry Andric return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) || 106*81ad6265SDimitry Andric isa<ExtractValueInst>(I); 107*81ad6265SDimitry Andric } 108*81ad6265SDimitry Andric 109*81ad6265SDimitry Andric static bool isAggrToReplace(const Value *V) { 110*81ad6265SDimitry Andric return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) || 111*81ad6265SDimitry Andric (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()); 112*81ad6265SDimitry Andric } 113*81ad6265SDimitry Andric 114*81ad6265SDimitry Andric static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) { 115*81ad6265SDimitry Andric if (isa<PHINode>(I)) 116*81ad6265SDimitry Andric B.SetInsertPoint(I->getParent(), I->getParent()->getFirstInsertionPt()); 117*81ad6265SDimitry Andric else 118*81ad6265SDimitry Andric B.SetInsertPoint(I); 119*81ad6265SDimitry Andric } 120*81ad6265SDimitry Andric 121*81ad6265SDimitry Andric static bool requireAssignType(Instruction *I) { 122*81ad6265SDimitry Andric IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I); 123*81ad6265SDimitry Andric if (Intr) { 124*81ad6265SDimitry Andric switch (Intr->getIntrinsicID()) { 125*81ad6265SDimitry Andric case Intrinsic::invariant_start: 126*81ad6265SDimitry Andric case Intrinsic::invariant_end: 127*81ad6265SDimitry Andric return false; 128*81ad6265SDimitry Andric } 129*81ad6265SDimitry Andric } 130*81ad6265SDimitry Andric return true; 131*81ad6265SDimitry Andric } 132*81ad6265SDimitry Andric 133*81ad6265SDimitry Andric void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old, 134*81ad6265SDimitry Andric Instruction *New) { 135*81ad6265SDimitry Andric while (!Old->user_empty()) { 136*81ad6265SDimitry Andric auto *U = Old->user_back(); 137*81ad6265SDimitry Andric if (isMemInstrToReplace(U) || isa<ReturnInst>(U)) { 138*81ad6265SDimitry Andric U->replaceUsesOfWith(Old, New); 139*81ad6265SDimitry Andric } else if (isAssignTypeInstr(U)) { 140*81ad6265SDimitry Andric IRB->SetInsertPoint(U); 141*81ad6265SDimitry Andric SmallVector<Value *, 2> Args = {New, U->getOperand(1)}; 142*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args); 143*81ad6265SDimitry Andric U->eraseFromParent(); 144*81ad6265SDimitry Andric } else { 145*81ad6265SDimitry Andric llvm_unreachable("illegal aggregate intrinsic user"); 146*81ad6265SDimitry Andric } 147*81ad6265SDimitry Andric } 148*81ad6265SDimitry Andric Old->eraseFromParent(); 149*81ad6265SDimitry Andric } 150*81ad6265SDimitry Andric 151*81ad6265SDimitry Andric void SPIRVEmitIntrinsics::preprocessCompositeConstants() { 152*81ad6265SDimitry Andric std::queue<Instruction *> Worklist; 153*81ad6265SDimitry Andric for (auto &I : instructions(F)) 154*81ad6265SDimitry Andric Worklist.push(&I); 155*81ad6265SDimitry Andric 156*81ad6265SDimitry Andric while (!Worklist.empty()) { 157*81ad6265SDimitry Andric auto *I = Worklist.front(); 158*81ad6265SDimitry Andric assert(I); 159*81ad6265SDimitry Andric bool KeepInst = false; 160*81ad6265SDimitry Andric for (const auto &Op : I->operands()) { 161*81ad6265SDimitry Andric auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &I, &Op, 162*81ad6265SDimitry Andric this](Constant *AggrC, 163*81ad6265SDimitry Andric ArrayRef<Value *> Args) { 164*81ad6265SDimitry Andric IRB->SetInsertPoint(I); 165*81ad6265SDimitry Andric auto *CCI = 166*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args}); 167*81ad6265SDimitry Andric Worklist.push(CCI); 168*81ad6265SDimitry Andric I->replaceUsesOfWith(Op, CCI); 169*81ad6265SDimitry Andric KeepInst = true; 170*81ad6265SDimitry Andric AggrConsts[CCI] = AggrC; 171*81ad6265SDimitry Andric }; 172*81ad6265SDimitry Andric 173*81ad6265SDimitry Andric if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) { 174*81ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 175*81ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 176*81ad6265SDimitry Andric } else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) { 177*81ad6265SDimitry Andric SmallVector<Value *> Args; 178*81ad6265SDimitry Andric for (unsigned i = 0; i < AggrC->getNumElements(); ++i) 179*81ad6265SDimitry Andric Args.push_back(AggrC->getElementAsConstant(i)); 180*81ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 181*81ad6265SDimitry Andric } else if (isa<ConstantAggregateZero>(Op) && 182*81ad6265SDimitry Andric !Op->getType()->isVectorTy()) { 183*81ad6265SDimitry Andric auto *AggrC = cast<ConstantAggregateZero>(Op); 184*81ad6265SDimitry Andric SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end()); 185*81ad6265SDimitry Andric BuildCompositeIntrinsic(AggrC, Args); 186*81ad6265SDimitry Andric } 187*81ad6265SDimitry Andric } 188*81ad6265SDimitry Andric if (!KeepInst) 189*81ad6265SDimitry Andric Worklist.pop(); 190*81ad6265SDimitry Andric } 191*81ad6265SDimitry Andric } 192*81ad6265SDimitry Andric 193*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) { 194*81ad6265SDimitry Andric SmallVector<Value *, 4> Args; 195*81ad6265SDimitry Andric for (auto &Op : I.operands()) 196*81ad6265SDimitry Andric if (Op.get()->getType()->isSized()) 197*81ad6265SDimitry Andric Args.push_back(Op); 198*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_switch, {I.getOperand(0)->getType()}, 199*81ad6265SDimitry Andric {Args}); 200*81ad6265SDimitry Andric return &I; 201*81ad6265SDimitry Andric } 202*81ad6265SDimitry Andric 203*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) { 204*81ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 205*81ad6265SDimitry Andric SmallVector<Value *, 4> Args; 206*81ad6265SDimitry Andric Args.push_back(IRB->getInt1(I.isInBounds())); 207*81ad6265SDimitry Andric for (auto &Op : I.operands()) 208*81ad6265SDimitry Andric Args.push_back(Op); 209*81ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args}); 210*81ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 211*81ad6265SDimitry Andric I.eraseFromParent(); 212*81ad6265SDimitry Andric return NewI; 213*81ad6265SDimitry Andric } 214*81ad6265SDimitry Andric 215*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) { 216*81ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()}; 217*81ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 218*81ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args}); 219*81ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 220*81ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 221*81ad6265SDimitry Andric I.eraseFromParent(); 222*81ad6265SDimitry Andric NewI->setName(InstName); 223*81ad6265SDimitry Andric return NewI; 224*81ad6265SDimitry Andric } 225*81ad6265SDimitry Andric 226*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) { 227*81ad6265SDimitry Andric SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(), 228*81ad6265SDimitry Andric I.getOperand(1)->getType(), 229*81ad6265SDimitry Andric I.getOperand(2)->getType()}; 230*81ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end()); 231*81ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args}); 232*81ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 233*81ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 234*81ad6265SDimitry Andric I.eraseFromParent(); 235*81ad6265SDimitry Andric NewI->setName(InstName); 236*81ad6265SDimitry Andric return NewI; 237*81ad6265SDimitry Andric } 238*81ad6265SDimitry Andric 239*81ad6265SDimitry Andric Instruction * 240*81ad6265SDimitry Andric SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) { 241*81ad6265SDimitry Andric SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(), 242*81ad6265SDimitry Andric I.getIndexOperand()->getType()}; 243*81ad6265SDimitry Andric SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()}; 244*81ad6265SDimitry Andric auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args}); 245*81ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : ""; 246*81ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 247*81ad6265SDimitry Andric I.eraseFromParent(); 248*81ad6265SDimitry Andric NewI->setName(InstName); 249*81ad6265SDimitry Andric return NewI; 250*81ad6265SDimitry Andric } 251*81ad6265SDimitry Andric 252*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) { 253*81ad6265SDimitry Andric SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()}; 254*81ad6265SDimitry Andric SmallVector<Value *> Args; 255*81ad6265SDimitry Andric for (auto &Op : I.operands()) 256*81ad6265SDimitry Andric if (isa<UndefValue>(Op)) 257*81ad6265SDimitry Andric Args.push_back(UndefValue::get(IRB->getInt32Ty())); 258*81ad6265SDimitry Andric else 259*81ad6265SDimitry Andric Args.push_back(Op); 260*81ad6265SDimitry Andric for (auto &Op : I.indices()) 261*81ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 262*81ad6265SDimitry Andric Instruction *NewI = 263*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args}); 264*81ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 265*81ad6265SDimitry Andric return NewI; 266*81ad6265SDimitry Andric } 267*81ad6265SDimitry Andric 268*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) { 269*81ad6265SDimitry Andric SmallVector<Value *> Args; 270*81ad6265SDimitry Andric for (auto &Op : I.operands()) 271*81ad6265SDimitry Andric Args.push_back(Op); 272*81ad6265SDimitry Andric for (auto &Op : I.indices()) 273*81ad6265SDimitry Andric Args.push_back(IRB->getInt32(Op)); 274*81ad6265SDimitry Andric auto *NewI = 275*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args}); 276*81ad6265SDimitry Andric I.replaceAllUsesWith(NewI); 277*81ad6265SDimitry Andric I.eraseFromParent(); 278*81ad6265SDimitry Andric return NewI; 279*81ad6265SDimitry Andric } 280*81ad6265SDimitry Andric 281*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) { 282*81ad6265SDimitry Andric if (!I.getType()->isAggregateType()) 283*81ad6265SDimitry Andric return &I; 284*81ad6265SDimitry Andric TrackConstants = false; 285*81ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 286*81ad6265SDimitry Andric MachineMemOperand::Flags Flags = 287*81ad6265SDimitry Andric TLI->getLoadMemOperandFlags(I, F->getParent()->getDataLayout()); 288*81ad6265SDimitry Andric auto *NewI = 289*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()}, 290*81ad6265SDimitry Andric {I.getPointerOperand(), IRB->getInt16(Flags), 291*81ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 292*81ad6265SDimitry Andric replaceMemInstrUses(&I, NewI); 293*81ad6265SDimitry Andric return NewI; 294*81ad6265SDimitry Andric } 295*81ad6265SDimitry Andric 296*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) { 297*81ad6265SDimitry Andric if (!AggrStores.contains(&I)) 298*81ad6265SDimitry Andric return &I; 299*81ad6265SDimitry Andric TrackConstants = false; 300*81ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering(); 301*81ad6265SDimitry Andric MachineMemOperand::Flags Flags = 302*81ad6265SDimitry Andric TLI->getStoreMemOperandFlags(I, F->getParent()->getDataLayout()); 303*81ad6265SDimitry Andric auto *PtrOp = I.getPointerOperand(); 304*81ad6265SDimitry Andric auto *NewI = 305*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_store, {PtrOp->getType()}, 306*81ad6265SDimitry Andric {I.getValueOperand(), PtrOp, IRB->getInt16(Flags), 307*81ad6265SDimitry Andric IRB->getInt8(I.getAlign().value())}); 308*81ad6265SDimitry Andric I.eraseFromParent(); 309*81ad6265SDimitry Andric return NewI; 310*81ad6265SDimitry Andric } 311*81ad6265SDimitry Andric 312*81ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) { 313*81ad6265SDimitry Andric TrackConstants = false; 314*81ad6265SDimitry Andric return &I; 315*81ad6265SDimitry Andric } 316*81ad6265SDimitry Andric 317*81ad6265SDimitry Andric void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) { 318*81ad6265SDimitry Andric // Skip special artifical variable llvm.global.annotations. 319*81ad6265SDimitry Andric if (GV.getName() == "llvm.global.annotations") 320*81ad6265SDimitry Andric return; 321*81ad6265SDimitry Andric if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) { 322*81ad6265SDimitry Andric Constant *Init = GV.getInitializer(); 323*81ad6265SDimitry Andric Type *Ty = isAggrToReplace(Init) ? IRB->getInt32Ty() : Init->getType(); 324*81ad6265SDimitry Andric Constant *Const = isAggrToReplace(Init) ? IRB->getInt32(1) : Init; 325*81ad6265SDimitry Andric auto *InitInst = IRB->CreateIntrinsic(Intrinsic::spv_init_global, 326*81ad6265SDimitry Andric {GV.getType(), Ty}, {&GV, Const}); 327*81ad6265SDimitry Andric InitInst->setArgOperand(1, Init); 328*81ad6265SDimitry Andric } 329*81ad6265SDimitry Andric if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) && 330*81ad6265SDimitry Andric GV.getNumUses() == 0) 331*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV); 332*81ad6265SDimitry Andric } 333*81ad6265SDimitry Andric 334*81ad6265SDimitry Andric void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) { 335*81ad6265SDimitry Andric Type *Ty = I->getType(); 336*81ad6265SDimitry Andric if (!Ty->isVoidTy() && requireAssignType(I)) { 337*81ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 338*81ad6265SDimitry Andric Type *TypeToAssign = Ty; 339*81ad6265SDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(I)) { 340*81ad6265SDimitry Andric if (II->getIntrinsicID() == Intrinsic::spv_const_composite) { 341*81ad6265SDimitry Andric auto t = AggrConsts.find(II); 342*81ad6265SDimitry Andric assert(t != AggrConsts.end()); 343*81ad6265SDimitry Andric TypeToAssign = t->second->getType(); 344*81ad6265SDimitry Andric } 345*81ad6265SDimitry Andric } 346*81ad6265SDimitry Andric Constant *Const = Constant::getNullValue(TypeToAssign); 347*81ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I); 348*81ad6265SDimitry Andric } 349*81ad6265SDimitry Andric for (const auto &Op : I->operands()) { 350*81ad6265SDimitry Andric if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) || 351*81ad6265SDimitry Andric // Check GetElementPtrConstantExpr case. 352*81ad6265SDimitry Andric (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) { 353*81ad6265SDimitry Andric IRB->SetInsertPoint(I); 354*81ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op); 355*81ad6265SDimitry Andric } 356*81ad6265SDimitry Andric } 357*81ad6265SDimitry Andric // StoreInst's operand type can be changed in the next stage so we need to 358*81ad6265SDimitry Andric // store it in the set. 359*81ad6265SDimitry Andric if (isa<StoreInst>(I) && 360*81ad6265SDimitry Andric cast<StoreInst>(I)->getValueOperand()->getType()->isAggregateType()) 361*81ad6265SDimitry Andric AggrStores.insert(I); 362*81ad6265SDimitry Andric } 363*81ad6265SDimitry Andric 364*81ad6265SDimitry Andric void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) { 365*81ad6265SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(I); 366*81ad6265SDimitry Andric if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite && 367*81ad6265SDimitry Andric TrackConstants) { 368*81ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 369*81ad6265SDimitry Andric Type *Ty = IRB->getInt32Ty(); 370*81ad6265SDimitry Andric auto t = AggrConsts.find(I); 371*81ad6265SDimitry Andric assert(t != AggrConsts.end()); 372*81ad6265SDimitry Andric auto *NewOp = 373*81ad6265SDimitry Andric buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, t->second, I); 374*81ad6265SDimitry Andric I->replaceAllUsesWith(NewOp); 375*81ad6265SDimitry Andric NewOp->setArgOperand(0, I); 376*81ad6265SDimitry Andric } 377*81ad6265SDimitry Andric for (const auto &Op : I->operands()) { 378*81ad6265SDimitry Andric if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) || 379*81ad6265SDimitry Andric isa<PHINode>(I) || isa<SwitchInst>(I)) 380*81ad6265SDimitry Andric TrackConstants = false; 381*81ad6265SDimitry Andric if (isa<ConstantData>(Op) && TrackConstants) { 382*81ad6265SDimitry Andric unsigned OpNo = Op.getOperandNo(); 383*81ad6265SDimitry Andric if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) || 384*81ad6265SDimitry Andric (II->paramHasAttr(OpNo, Attribute::ImmArg)))) 385*81ad6265SDimitry Andric continue; 386*81ad6265SDimitry Andric IRB->SetInsertPoint(I); 387*81ad6265SDimitry Andric auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, 388*81ad6265SDimitry Andric {Op->getType(), Op->getType()}, Op, Op); 389*81ad6265SDimitry Andric I->setOperand(OpNo, NewOp); 390*81ad6265SDimitry Andric } 391*81ad6265SDimitry Andric } 392*81ad6265SDimitry Andric if (I->hasName()) { 393*81ad6265SDimitry Andric setInsertPointSkippingPhis(*IRB, I->getNextNode()); 394*81ad6265SDimitry Andric std::vector<Value *> Args = {I}; 395*81ad6265SDimitry Andric addStringImm(I->getName(), *IRB, Args); 396*81ad6265SDimitry Andric IRB->CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args); 397*81ad6265SDimitry Andric } 398*81ad6265SDimitry Andric } 399*81ad6265SDimitry Andric 400*81ad6265SDimitry Andric bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { 401*81ad6265SDimitry Andric if (Func.isDeclaration()) 402*81ad6265SDimitry Andric return false; 403*81ad6265SDimitry Andric F = &Func; 404*81ad6265SDimitry Andric IRB = new IRBuilder<>(Func.getContext()); 405*81ad6265SDimitry Andric AggrConsts.clear(); 406*81ad6265SDimitry Andric AggrStores.clear(); 407*81ad6265SDimitry Andric 408*81ad6265SDimitry Andric IRB->SetInsertPoint(&Func.getEntryBlock().front()); 409*81ad6265SDimitry Andric 410*81ad6265SDimitry Andric for (auto &GV : Func.getParent()->globals()) 411*81ad6265SDimitry Andric processGlobalValue(GV); 412*81ad6265SDimitry Andric 413*81ad6265SDimitry Andric preprocessCompositeConstants(); 414*81ad6265SDimitry Andric SmallVector<Instruction *> Worklist; 415*81ad6265SDimitry Andric for (auto &I : instructions(Func)) 416*81ad6265SDimitry Andric Worklist.push_back(&I); 417*81ad6265SDimitry Andric 418*81ad6265SDimitry Andric for (auto &I : Worklist) 419*81ad6265SDimitry Andric insertAssignTypeIntrs(I); 420*81ad6265SDimitry Andric 421*81ad6265SDimitry Andric for (auto *I : Worklist) { 422*81ad6265SDimitry Andric TrackConstants = true; 423*81ad6265SDimitry Andric if (!I->getType()->isVoidTy() || isa<StoreInst>(I)) 424*81ad6265SDimitry Andric IRB->SetInsertPoint(I->getNextNode()); 425*81ad6265SDimitry Andric I = visit(*I); 426*81ad6265SDimitry Andric processInstrAfterVisit(I); 427*81ad6265SDimitry Andric } 428*81ad6265SDimitry Andric return true; 429*81ad6265SDimitry Andric } 430*81ad6265SDimitry Andric 431*81ad6265SDimitry Andric FunctionPass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) { 432*81ad6265SDimitry Andric return new SPIRVEmitIntrinsics(TM); 433*81ad6265SDimitry Andric } 434