xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
1 //===-- SPIRVEmitIntrinsics.cpp - emit SPIRV intrinsics ---------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // The pass emits SPIRV intrinsics keeping essential high-level information for
10 // the translation of LLVM IR to SPIR-V.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "SPIRV.h"
15 #include "SPIRVTargetMachine.h"
16 #include "SPIRVUtils.h"
17 #include "llvm/IR/IRBuilder.h"
18 #include "llvm/IR/InstIterator.h"
19 #include "llvm/IR/InstVisitor.h"
20 #include "llvm/IR/IntrinsicsSPIRV.h"
21 
22 #include <queue>
23 
24 // This pass performs the following transformation on LLVM IR level required
25 // for the following translation to SPIR-V:
26 // - replaces direct usages of aggregate constants with target-specific
27 //   intrinsics;
28 // - replaces aggregates-related instructions (extract/insert, ld/st, etc)
29 //   with a target-specific intrinsics;
30 // - emits intrinsics for the global variable initializers since IRTranslator
31 //   doesn't handle them and it's not very convenient to translate them
32 //   ourselves;
33 // - emits intrinsics to keep track of the string names assigned to the values;
34 // - emits intrinsics to keep track of constants (this is necessary to have an
35 //   LLVM IR constant after the IRTranslation is completed) for their further
36 //   deduplication;
37 // - emits intrinsics to keep track of original LLVM types of the values
38 //   to be able to emit proper SPIR-V types eventually.
39 //
40 // TODO: consider removing spv.track.constant in favor of spv.assign.type.
41 
42 using namespace llvm;
43 
44 namespace llvm {
45 void initializeSPIRVEmitIntrinsicsPass(PassRegistry &);
46 } // namespace llvm
47 
48 namespace {
49 class SPIRVEmitIntrinsics
50     : public FunctionPass,
51       public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
52   SPIRVTargetMachine *TM = nullptr;
53   IRBuilder<> *IRB = nullptr;
54   Function *F = nullptr;
55   bool TrackConstants = true;
56   DenseMap<Instruction *, Constant *> AggrConsts;
57   DenseSet<Instruction *> AggrStores;
58   void preprocessCompositeConstants();
59   void preprocessUndefs();
60   CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
61                             Value *Arg, Value *Arg2,
62                             ArrayRef<Constant *> Imms) {
63     ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg);
64     MDTuple *TyMD = MDNode::get(F->getContext(), CM);
65     MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD);
66     SmallVector<Value *, 4> Args;
67     Args.push_back(Arg2);
68     Args.push_back(VMD);
69     for (auto *Imm : Imms)
70       Args.push_back(Imm);
71     return IRB->CreateIntrinsic(IntrID, {Types}, Args);
72   }
73   void replaceMemInstrUses(Instruction *Old, Instruction *New);
74   void processInstrAfterVisit(Instruction *I);
75   void insertAssignPtrTypeIntrs(Instruction *I);
76   void insertAssignTypeIntrs(Instruction *I);
77   void insertPtrCastInstr(Instruction *I);
78   void processGlobalValue(GlobalVariable &GV);
79 
80 public:
81   static char ID;
82   SPIRVEmitIntrinsics() : FunctionPass(ID) {
83     initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry());
84   }
85   SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : FunctionPass(ID), TM(_TM) {
86     initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry());
87   }
88   Instruction *visitInstruction(Instruction &I) { return &I; }
89   Instruction *visitSwitchInst(SwitchInst &I);
90   Instruction *visitGetElementPtrInst(GetElementPtrInst &I);
91   Instruction *visitBitCastInst(BitCastInst &I);
92   Instruction *visitInsertElementInst(InsertElementInst &I);
93   Instruction *visitExtractElementInst(ExtractElementInst &I);
94   Instruction *visitInsertValueInst(InsertValueInst &I);
95   Instruction *visitExtractValueInst(ExtractValueInst &I);
96   Instruction *visitLoadInst(LoadInst &I);
97   Instruction *visitStoreInst(StoreInst &I);
98   Instruction *visitAllocaInst(AllocaInst &I);
99   Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
100   Instruction *visitUnreachableInst(UnreachableInst &I);
101   bool runOnFunction(Function &F) override;
102 };
103 } // namespace
104 
105 char SPIRVEmitIntrinsics::ID = 0;
106 
107 INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics",
108                 false, false)
109 
110 static inline bool isAssignTypeInstr(const Instruction *I) {
111   return isa<IntrinsicInst>(I) &&
112          cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type;
113 }
114 
115 static bool isMemInstrToReplace(Instruction *I) {
116   return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) ||
117          isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I);
118 }
119 
120 static bool isAggrToReplace(const Value *V) {
121   return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) ||
122          (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
123 }
124 
125 static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
126   if (isa<PHINode>(I))
127     B.SetInsertPoint(I->getParent(), I->getParent()->getFirstInsertionPt());
128   else
129     B.SetInsertPoint(I);
130 }
131 
132 static bool requireAssignPtrType(Instruction *I) {
133   if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I))
134     return true;
135 
136   return false;
137 }
138 
139 static bool requireAssignType(Instruction *I) {
140   IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I);
141   if (Intr) {
142     switch (Intr->getIntrinsicID()) {
143     case Intrinsic::invariant_start:
144     case Intrinsic::invariant_end:
145       return false;
146     }
147   }
148   return true;
149 }
150 
151 void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
152                                               Instruction *New) {
153   while (!Old->user_empty()) {
154     auto *U = Old->user_back();
155     if (isAssignTypeInstr(U)) {
156       IRB->SetInsertPoint(U);
157       SmallVector<Value *, 2> Args = {New, U->getOperand(1)};
158       IRB->CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);
159       U->eraseFromParent();
160     } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||
161                isa<CallInst>(U)) {
162       U->replaceUsesOfWith(Old, New);
163     } else {
164       llvm_unreachable("illegal aggregate intrinsic user");
165     }
166   }
167   Old->eraseFromParent();
168 }
169 
170 void SPIRVEmitIntrinsics::preprocessUndefs() {
171   std::queue<Instruction *> Worklist;
172   for (auto &I : instructions(F))
173     Worklist.push(&I);
174 
175   while (!Worklist.empty()) {
176     Instruction *I = Worklist.front();
177     Worklist.pop();
178 
179     for (auto &Op : I->operands()) {
180       auto *AggrUndef = dyn_cast<UndefValue>(Op);
181       if (!AggrUndef || !Op->getType()->isAggregateType())
182         continue;
183 
184       IRB->SetInsertPoint(I);
185       auto *IntrUndef = IRB->CreateIntrinsic(Intrinsic::spv_undef, {}, {});
186       Worklist.push(IntrUndef);
187       I->replaceUsesOfWith(Op, IntrUndef);
188       AggrConsts[IntrUndef] = AggrUndef;
189     }
190   }
191 }
192 
193 void SPIRVEmitIntrinsics::preprocessCompositeConstants() {
194   std::queue<Instruction *> Worklist;
195   for (auto &I : instructions(F))
196     Worklist.push(&I);
197 
198   while (!Worklist.empty()) {
199     auto *I = Worklist.front();
200     assert(I);
201     bool KeepInst = false;
202     for (const auto &Op : I->operands()) {
203       auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &I, &Op,
204                                       this](Constant *AggrC,
205                                             ArrayRef<Value *> Args) {
206         IRB->SetInsertPoint(I);
207         auto *CCI =
208             IRB->CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args});
209         Worklist.push(CCI);
210         I->replaceUsesOfWith(Op, CCI);
211         KeepInst = true;
212         AggrConsts[CCI] = AggrC;
213       };
214 
215       if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) {
216         SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end());
217         BuildCompositeIntrinsic(AggrC, Args);
218       } else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) {
219         SmallVector<Value *> Args;
220         for (unsigned i = 0; i < AggrC->getNumElements(); ++i)
221           Args.push_back(AggrC->getElementAsConstant(i));
222         BuildCompositeIntrinsic(AggrC, Args);
223       } else if (isa<ConstantAggregateZero>(Op) &&
224                  !Op->getType()->isVectorTy()) {
225         auto *AggrC = cast<ConstantAggregateZero>(Op);
226         SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end());
227         BuildCompositeIntrinsic(AggrC, Args);
228       }
229     }
230     if (!KeepInst)
231       Worklist.pop();
232   }
233 }
234 
235 Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
236   SmallVector<Value *, 4> Args;
237   for (auto &Op : I.operands())
238     if (Op.get()->getType()->isSized())
239       Args.push_back(Op);
240   IRB->SetInsertPoint(&I);
241   IRB->CreateIntrinsic(Intrinsic::spv_switch, {I.getOperand(0)->getType()},
242                        {Args});
243   return &I;
244 }
245 
246 Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
247   SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
248   SmallVector<Value *, 4> Args;
249   Args.push_back(IRB->getInt1(I.isInBounds()));
250   for (auto &Op : I.operands())
251     Args.push_back(Op);
252   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
253   I.replaceAllUsesWith(NewI);
254   I.eraseFromParent();
255   return NewI;
256 }
257 
258 Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
259   Value *Source = I.getOperand(0);
260 
261   // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of
262   // varying element types. In case of IR coming from older versions of LLVM
263   // such bitcasts do not provide sufficient information, should be just skipped
264   // here, and handled in insertPtrCastInstr.
265   if (I.getType()->isPointerTy()) {
266     I.replaceAllUsesWith(Source);
267     I.eraseFromParent();
268     return nullptr;
269   }
270 
271   SmallVector<Type *, 2> Types = {I.getType(), Source->getType()};
272   SmallVector<Value *> Args(I.op_begin(), I.op_end());
273   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});
274   std::string InstName = I.hasName() ? I.getName().str() : "";
275   I.replaceAllUsesWith(NewI);
276   I.eraseFromParent();
277   NewI->setName(InstName);
278   return NewI;
279 }
280 
281 void SPIRVEmitIntrinsics::insertPtrCastInstr(Instruction *I) {
282   Value *Pointer;
283   Type *ExpectedElementType;
284   unsigned OperandToReplace;
285   if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
286     Pointer = SI->getPointerOperand();
287     ExpectedElementType = SI->getValueOperand()->getType();
288     OperandToReplace = 1;
289   } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
290     Pointer = LI->getPointerOperand();
291     ExpectedElementType = LI->getType();
292     OperandToReplace = 0;
293   } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
294     Pointer = GEPI->getPointerOperand();
295     ExpectedElementType = GEPI->getSourceElementType();
296     OperandToReplace = 0;
297   } else {
298     return;
299   }
300 
301   // If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source
302   // pointer instead. The BitCastInst should be later removed when visited.
303   while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))
304     Pointer = BC->getOperand(0);
305 
306   // Do not emit spv_ptrcast if Pointer is a GlobalValue of expected type.
307   GlobalValue *GV = dyn_cast<GlobalValue>(Pointer);
308   if (GV && GV->getValueType() == ExpectedElementType)
309     return;
310 
311   // Do not emit spv_ptrcast if Pointer is a result of alloca with expected
312   // type.
313   AllocaInst *A = dyn_cast<AllocaInst>(Pointer);
314   if (A && A->getAllocatedType() == ExpectedElementType)
315     return;
316 
317   if (dyn_cast<GetElementPtrInst>(Pointer))
318     return;
319 
320   setInsertPointSkippingPhis(*IRB, I);
321   Constant *ExpectedElementTypeConst =
322       Constant::getNullValue(ExpectedElementType);
323   ConstantAsMetadata *CM =
324       ValueAsMetadata::getConstant(ExpectedElementTypeConst);
325   MDTuple *TyMD = MDNode::get(F->getContext(), CM);
326   MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD);
327   unsigned AddressSpace = Pointer->getType()->getPointerAddressSpace();
328   bool FirstPtrCastOrAssignPtrType = true;
329 
330   // Do not emit new spv_ptrcast if equivalent one already exists or when
331   // spv_assign_ptr_type already targets this pointer with the same element
332   // type.
333   for (auto User : Pointer->users()) {
334     auto *II = dyn_cast<IntrinsicInst>(User);
335     if (!II ||
336         (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
337          II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
338         II->getOperand(0) != Pointer)
339       continue;
340 
341     // There is some spv_ptrcast/spv_assign_ptr_type already targeting this
342     // pointer.
343     FirstPtrCastOrAssignPtrType = false;
344     if (II->getOperand(1) != VMD ||
345         dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=
346             AddressSpace)
347       continue;
348 
349     // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the same
350     // element type and address space.
351     if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)
352       return;
353 
354     // This must be a spv_ptrcast, do not emit new if this one has the same BB
355     // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.
356     if (II->getParent() != I->getParent())
357       continue;
358 
359     I->setOperand(OperandToReplace, II);
360     return;
361   }
362 
363   // Do not emit spv_ptrcast if it would cast to the default pointer element
364   // type (i8) of the same address space.
365   if (ExpectedElementType->isIntegerTy(8))
366     return;
367 
368   // If this would be the first spv_ptrcast and there is no spv_assign_ptr_type
369   // for this pointer before, do not emit spv_ptrcast but emit
370   // spv_assign_ptr_type instead.
371   if (FirstPtrCastOrAssignPtrType && isa<Instruction>(Pointer)) {
372     buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {Pointer->getType()},
373                     ExpectedElementTypeConst, Pointer,
374                     {IRB->getInt32(AddressSpace)});
375     return;
376   } else {
377     SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};
378     SmallVector<Value *, 2> Args = {Pointer, VMD, IRB->getInt32(AddressSpace)};
379     auto *PtrCastI =
380         IRB->CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
381     I->setOperand(OperandToReplace, PtrCastI);
382     return;
383   }
384 }
385 
386 Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {
387   SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),
388                                   I.getOperand(1)->getType(),
389                                   I.getOperand(2)->getType()};
390   SmallVector<Value *> Args(I.op_begin(), I.op_end());
391   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
392   std::string InstName = I.hasName() ? I.getName().str() : "";
393   I.replaceAllUsesWith(NewI);
394   I.eraseFromParent();
395   NewI->setName(InstName);
396   return NewI;
397 }
398 
399 Instruction *
400 SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {
401   SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(),
402                                   I.getIndexOperand()->getType()};
403   SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};
404   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});
405   std::string InstName = I.hasName() ? I.getName().str() : "";
406   I.replaceAllUsesWith(NewI);
407   I.eraseFromParent();
408   NewI->setName(InstName);
409   return NewI;
410 }
411 
412 Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {
413   SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()};
414   SmallVector<Value *> Args;
415   for (auto &Op : I.operands())
416     if (isa<UndefValue>(Op))
417       Args.push_back(UndefValue::get(IRB->getInt32Ty()));
418     else
419       Args.push_back(Op);
420   for (auto &Op : I.indices())
421     Args.push_back(IRB->getInt32(Op));
422   Instruction *NewI =
423       IRB->CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args});
424   replaceMemInstrUses(&I, NewI);
425   return NewI;
426 }
427 
428 Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
429   SmallVector<Value *> Args;
430   for (auto &Op : I.operands())
431     Args.push_back(Op);
432   for (auto &Op : I.indices())
433     Args.push_back(IRB->getInt32(Op));
434   auto *NewI =
435       IRB->CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});
436   I.replaceAllUsesWith(NewI);
437   I.eraseFromParent();
438   return NewI;
439 }
440 
441 Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) {
442   if (!I.getType()->isAggregateType())
443     return &I;
444   TrackConstants = false;
445   const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
446   MachineMemOperand::Flags Flags =
447       TLI->getLoadMemOperandFlags(I, F->getParent()->getDataLayout());
448   auto *NewI =
449       IRB->CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()},
450                            {I.getPointerOperand(), IRB->getInt16(Flags),
451                             IRB->getInt8(I.getAlign().value())});
452   replaceMemInstrUses(&I, NewI);
453   return NewI;
454 }
455 
456 Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {
457   if (!AggrStores.contains(&I))
458     return &I;
459   TrackConstants = false;
460   const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
461   MachineMemOperand::Flags Flags =
462       TLI->getStoreMemOperandFlags(I, F->getParent()->getDataLayout());
463   auto *PtrOp = I.getPointerOperand();
464   auto *NewI = IRB->CreateIntrinsic(
465       Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()},
466       {I.getValueOperand(), PtrOp, IRB->getInt16(Flags),
467        IRB->getInt8(I.getAlign().value())});
468   I.eraseFromParent();
469   return NewI;
470 }
471 
472 Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {
473   TrackConstants = false;
474   Type *PtrTy = I.getType();
475   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {});
476   std::string InstName = I.hasName() ? I.getName().str() : "";
477   I.replaceAllUsesWith(NewI);
478   I.eraseFromParent();
479   NewI->setName(InstName);
480   return NewI;
481 }
482 
483 Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
484   assert(I.getType()->isAggregateType() && "Aggregate result is expected");
485   SmallVector<Value *> Args;
486   for (auto &Op : I.operands())
487     Args.push_back(Op);
488   Args.push_back(IRB->getInt32(I.getSyncScopeID()));
489   Args.push_back(IRB->getInt32(
490       static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering()))));
491   Args.push_back(IRB->getInt32(
492       static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering()))));
493   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_cmpxchg,
494                                     {I.getPointerOperand()->getType()}, {Args});
495   replaceMemInstrUses(&I, NewI);
496   return NewI;
497 }
498 
499 Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) {
500   IRB->SetInsertPoint(&I);
501   IRB->CreateIntrinsic(Intrinsic::spv_unreachable, {}, {});
502   return &I;
503 }
504 
505 void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) {
506   // Skip special artifical variable llvm.global.annotations.
507   if (GV.getName() == "llvm.global.annotations")
508     return;
509   if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) {
510     Constant *Init = GV.getInitializer();
511     Type *Ty = isAggrToReplace(Init) ? IRB->getInt32Ty() : Init->getType();
512     Constant *Const = isAggrToReplace(Init) ? IRB->getInt32(1) : Init;
513     auto *InitInst = IRB->CreateIntrinsic(Intrinsic::spv_init_global,
514                                           {GV.getType(), Ty}, {&GV, Const});
515     InitInst->setArgOperand(1, Init);
516   }
517   if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) &&
518       GV.getNumUses() == 0)
519     IRB->CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);
520 }
521 
522 void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I) {
523   if (I->getType()->isVoidTy() || !requireAssignPtrType(I))
524     return;
525 
526   setInsertPointSkippingPhis(*IRB, I->getNextNode());
527 
528   Constant *EltTyConst;
529   unsigned AddressSpace = 0;
530   if (auto *AI = dyn_cast<AllocaInst>(I)) {
531     EltTyConst = UndefValue::get(AI->getAllocatedType());
532     AddressSpace = AI->getAddressSpace();
533   } else if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) {
534     EltTyConst = UndefValue::get(GEP->getResultElementType());
535     AddressSpace = GEP->getPointerAddressSpace();
536   } else {
537     llvm_unreachable("Unexpected instruction!");
538   }
539 
540   buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {I->getType()}, EltTyConst, I,
541                   {IRB->getInt32(AddressSpace)});
542 }
543 
544 void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) {
545   Type *Ty = I->getType();
546   if (!Ty->isVoidTy() && requireAssignType(I) && !requireAssignPtrType(I)) {
547     setInsertPointSkippingPhis(*IRB, I->getNextNode());
548     Type *TypeToAssign = Ty;
549     if (auto *II = dyn_cast<IntrinsicInst>(I)) {
550       if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
551           II->getIntrinsicID() == Intrinsic::spv_undef) {
552         auto t = AggrConsts.find(II);
553         assert(t != AggrConsts.end());
554         TypeToAssign = t->second->getType();
555       }
556     }
557     Constant *Const = UndefValue::get(TypeToAssign);
558     buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I, {});
559   }
560   for (const auto &Op : I->operands()) {
561     if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
562         // Check GetElementPtrConstantExpr case.
563         (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) {
564       setInsertPointSkippingPhis(*IRB, I);
565       if (isa<UndefValue>(Op) && Op->getType()->isAggregateType())
566         buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op,
567                         UndefValue::get(IRB->getInt32Ty()), {});
568       else
569         buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op,
570                         {});
571     }
572   }
573 }
574 
575 void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) {
576   auto *II = dyn_cast<IntrinsicInst>(I);
577   if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
578       TrackConstants) {
579     IRB->SetInsertPoint(I->getNextNode());
580     Type *Ty = IRB->getInt32Ty();
581     auto t = AggrConsts.find(I);
582     assert(t != AggrConsts.end());
583     auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty},
584                                   t->second, I, {});
585     I->replaceAllUsesWith(NewOp);
586     NewOp->setArgOperand(0, I);
587   }
588   for (const auto &Op : I->operands()) {
589     if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) ||
590         isa<PHINode>(I) || isa<SwitchInst>(I))
591       TrackConstants = false;
592     if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) {
593       unsigned OpNo = Op.getOperandNo();
594       if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
595                  (II->paramHasAttr(OpNo, Attribute::ImmArg))))
596         continue;
597       IRB->SetInsertPoint(I);
598       auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
599                                     {Op->getType(), Op->getType()}, Op, Op, {});
600       I->setOperand(OpNo, NewOp);
601     }
602   }
603   if (I->hasName()) {
604     setInsertPointSkippingPhis(*IRB, I->getNextNode());
605     std::vector<Value *> Args = {I};
606     addStringImm(I->getName(), *IRB, Args);
607     IRB->CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);
608   }
609 }
610 
611 bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
612   if (Func.isDeclaration())
613     return false;
614   F = &Func;
615   IRB = new IRBuilder<>(Func.getContext());
616   AggrConsts.clear();
617   AggrStores.clear();
618 
619   // StoreInst's operand type can be changed during the next transformations,
620   // so we need to store it in the set. Also store already transformed types.
621   for (auto &I : instructions(Func)) {
622     StoreInst *SI = dyn_cast<StoreInst>(&I);
623     if (!SI)
624       continue;
625     Type *ElTy = SI->getValueOperand()->getType();
626     if (ElTy->isAggregateType() || ElTy->isVectorTy())
627       AggrStores.insert(&I);
628   }
629 
630   IRB->SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin());
631   for (auto &GV : Func.getParent()->globals())
632     processGlobalValue(GV);
633 
634   preprocessUndefs();
635   preprocessCompositeConstants();
636   SmallVector<Instruction *> Worklist;
637   for (auto &I : instructions(Func))
638     Worklist.push_back(&I);
639 
640   for (auto &I : Worklist) {
641     insertAssignPtrTypeIntrs(I);
642     insertAssignTypeIntrs(I);
643     insertPtrCastInstr(I);
644   }
645 
646   for (auto *I : Worklist) {
647     TrackConstants = true;
648     if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
649       IRB->SetInsertPoint(I->getNextNode());
650     // Visitors return either the original/newly created instruction for further
651     // processing, nullptr otherwise.
652     I = visit(*I);
653     if (!I)
654       continue;
655     processInstrAfterVisit(I);
656   }
657   return true;
658 }
659 
660 FunctionPass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) {
661   return new SPIRVEmitIntrinsics(TM);
662 }
663