xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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