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