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