xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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();
5981ad6265SDimitry Andric   CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
6081ad6265SDimitry Andric                             Value *Arg, Value *Arg2) {
6181ad6265SDimitry Andric     ConstantAsMetadata *CM = ValueAsMetadata::getConstant(Arg);
6281ad6265SDimitry Andric     MDTuple *TyMD = MDNode::get(F->getContext(), CM);
6381ad6265SDimitry Andric     MetadataAsValue *VMD = MetadataAsValue::get(F->getContext(), TyMD);
6481ad6265SDimitry Andric     return IRB->CreateIntrinsic(IntrID, {Types}, {Arg2, VMD});
6581ad6265SDimitry Andric   }
6681ad6265SDimitry Andric   void replaceMemInstrUses(Instruction *Old, Instruction *New);
6781ad6265SDimitry Andric   void processInstrAfterVisit(Instruction *I);
6881ad6265SDimitry Andric   void insertAssignTypeIntrs(Instruction *I);
6981ad6265SDimitry Andric   void processGlobalValue(GlobalVariable &GV);
7081ad6265SDimitry Andric 
7181ad6265SDimitry Andric public:
7281ad6265SDimitry Andric   static char ID;
7381ad6265SDimitry Andric   SPIRVEmitIntrinsics() : FunctionPass(ID) {
7481ad6265SDimitry Andric     initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry());
7581ad6265SDimitry Andric   }
7681ad6265SDimitry Andric   SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : FunctionPass(ID), TM(_TM) {
7781ad6265SDimitry Andric     initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry());
7881ad6265SDimitry Andric   }
7981ad6265SDimitry Andric   Instruction *visitInstruction(Instruction &I) { return &I; }
8081ad6265SDimitry Andric   Instruction *visitSwitchInst(SwitchInst &I);
8181ad6265SDimitry Andric   Instruction *visitGetElementPtrInst(GetElementPtrInst &I);
8281ad6265SDimitry Andric   Instruction *visitBitCastInst(BitCastInst &I);
8381ad6265SDimitry Andric   Instruction *visitInsertElementInst(InsertElementInst &I);
8481ad6265SDimitry Andric   Instruction *visitExtractElementInst(ExtractElementInst &I);
8581ad6265SDimitry Andric   Instruction *visitInsertValueInst(InsertValueInst &I);
8681ad6265SDimitry Andric   Instruction *visitExtractValueInst(ExtractValueInst &I);
8781ad6265SDimitry Andric   Instruction *visitLoadInst(LoadInst &I);
8881ad6265SDimitry Andric   Instruction *visitStoreInst(StoreInst &I);
8981ad6265SDimitry Andric   Instruction *visitAllocaInst(AllocaInst &I);
90fcaf7f86SDimitry Andric   Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
91*bdd1243dSDimitry Andric   Instruction *visitUnreachableInst(UnreachableInst &I);
9281ad6265SDimitry Andric   bool runOnFunction(Function &F) override;
9381ad6265SDimitry Andric };
9481ad6265SDimitry Andric } // namespace
9581ad6265SDimitry Andric 
9681ad6265SDimitry Andric char SPIRVEmitIntrinsics::ID = 0;
9781ad6265SDimitry Andric 
9881ad6265SDimitry Andric INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics",
9981ad6265SDimitry Andric                 false, false)
10081ad6265SDimitry Andric 
10181ad6265SDimitry Andric static inline bool isAssignTypeInstr(const Instruction *I) {
10281ad6265SDimitry Andric   return isa<IntrinsicInst>(I) &&
10381ad6265SDimitry Andric          cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type;
10481ad6265SDimitry Andric }
10581ad6265SDimitry Andric 
10681ad6265SDimitry Andric static bool isMemInstrToReplace(Instruction *I) {
10781ad6265SDimitry Andric   return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) ||
108fcaf7f86SDimitry Andric          isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I);
10981ad6265SDimitry Andric }
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric static bool isAggrToReplace(const Value *V) {
11281ad6265SDimitry Andric   return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) ||
11381ad6265SDimitry Andric          (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
11481ad6265SDimitry Andric }
11581ad6265SDimitry Andric 
11681ad6265SDimitry Andric static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
11781ad6265SDimitry Andric   if (isa<PHINode>(I))
11881ad6265SDimitry Andric     B.SetInsertPoint(I->getParent(), I->getParent()->getFirstInsertionPt());
11981ad6265SDimitry Andric   else
12081ad6265SDimitry Andric     B.SetInsertPoint(I);
12181ad6265SDimitry Andric }
12281ad6265SDimitry Andric 
12381ad6265SDimitry Andric static bool requireAssignType(Instruction *I) {
12481ad6265SDimitry Andric   IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I);
12581ad6265SDimitry Andric   if (Intr) {
12681ad6265SDimitry Andric     switch (Intr->getIntrinsicID()) {
12781ad6265SDimitry Andric     case Intrinsic::invariant_start:
12881ad6265SDimitry Andric     case Intrinsic::invariant_end:
12981ad6265SDimitry Andric       return false;
13081ad6265SDimitry Andric     }
13181ad6265SDimitry Andric   }
13281ad6265SDimitry Andric   return true;
13381ad6265SDimitry Andric }
13481ad6265SDimitry Andric 
13581ad6265SDimitry Andric void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
13681ad6265SDimitry Andric                                               Instruction *New) {
13781ad6265SDimitry Andric   while (!Old->user_empty()) {
13881ad6265SDimitry Andric     auto *U = Old->user_back();
139fcaf7f86SDimitry Andric     if (isAssignTypeInstr(U)) {
14081ad6265SDimitry Andric       IRB->SetInsertPoint(U);
14181ad6265SDimitry Andric       SmallVector<Value *, 2> Args = {New, U->getOperand(1)};
14281ad6265SDimitry Andric       IRB->CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);
14381ad6265SDimitry Andric       U->eraseFromParent();
144fcaf7f86SDimitry Andric     } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||
145fcaf7f86SDimitry Andric                isa<CallInst>(U)) {
146fcaf7f86SDimitry Andric       U->replaceUsesOfWith(Old, New);
14781ad6265SDimitry Andric     } else {
14881ad6265SDimitry Andric       llvm_unreachable("illegal aggregate intrinsic user");
14981ad6265SDimitry Andric     }
15081ad6265SDimitry Andric   }
15181ad6265SDimitry Andric   Old->eraseFromParent();
15281ad6265SDimitry Andric }
15381ad6265SDimitry Andric 
15481ad6265SDimitry Andric void SPIRVEmitIntrinsics::preprocessCompositeConstants() {
15581ad6265SDimitry Andric   std::queue<Instruction *> Worklist;
15681ad6265SDimitry Andric   for (auto &I : instructions(F))
15781ad6265SDimitry Andric     Worklist.push(&I);
15881ad6265SDimitry Andric 
15981ad6265SDimitry Andric   while (!Worklist.empty()) {
16081ad6265SDimitry Andric     auto *I = Worklist.front();
16181ad6265SDimitry Andric     assert(I);
16281ad6265SDimitry Andric     bool KeepInst = false;
16381ad6265SDimitry Andric     for (const auto &Op : I->operands()) {
16481ad6265SDimitry Andric       auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &I, &Op,
16581ad6265SDimitry Andric                                       this](Constant *AggrC,
16681ad6265SDimitry Andric                                             ArrayRef<Value *> Args) {
16781ad6265SDimitry Andric         IRB->SetInsertPoint(I);
16881ad6265SDimitry Andric         auto *CCI =
16981ad6265SDimitry Andric             IRB->CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args});
17081ad6265SDimitry Andric         Worklist.push(CCI);
17181ad6265SDimitry Andric         I->replaceUsesOfWith(Op, CCI);
17281ad6265SDimitry Andric         KeepInst = true;
17381ad6265SDimitry Andric         AggrConsts[CCI] = AggrC;
17481ad6265SDimitry Andric       };
17581ad6265SDimitry Andric 
17681ad6265SDimitry Andric       if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) {
17781ad6265SDimitry Andric         SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end());
17881ad6265SDimitry Andric         BuildCompositeIntrinsic(AggrC, Args);
17981ad6265SDimitry Andric       } else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) {
18081ad6265SDimitry Andric         SmallVector<Value *> Args;
18181ad6265SDimitry Andric         for (unsigned i = 0; i < AggrC->getNumElements(); ++i)
18281ad6265SDimitry Andric           Args.push_back(AggrC->getElementAsConstant(i));
18381ad6265SDimitry Andric         BuildCompositeIntrinsic(AggrC, Args);
18481ad6265SDimitry Andric       } else if (isa<ConstantAggregateZero>(Op) &&
18581ad6265SDimitry Andric                  !Op->getType()->isVectorTy()) {
18681ad6265SDimitry Andric         auto *AggrC = cast<ConstantAggregateZero>(Op);
18781ad6265SDimitry Andric         SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end());
18881ad6265SDimitry Andric         BuildCompositeIntrinsic(AggrC, Args);
18981ad6265SDimitry Andric       }
19081ad6265SDimitry Andric     }
19181ad6265SDimitry Andric     if (!KeepInst)
19281ad6265SDimitry Andric       Worklist.pop();
19381ad6265SDimitry Andric   }
19481ad6265SDimitry Andric }
19581ad6265SDimitry Andric 
19681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
19781ad6265SDimitry Andric   SmallVector<Value *, 4> Args;
19881ad6265SDimitry Andric   for (auto &Op : I.operands())
19981ad6265SDimitry Andric     if (Op.get()->getType()->isSized())
20081ad6265SDimitry Andric       Args.push_back(Op);
201*bdd1243dSDimitry Andric   IRB->SetInsertPoint(&I);
20281ad6265SDimitry Andric   IRB->CreateIntrinsic(Intrinsic::spv_switch, {I.getOperand(0)->getType()},
20381ad6265SDimitry Andric                        {Args});
20481ad6265SDimitry Andric   return &I;
20581ad6265SDimitry Andric }
20681ad6265SDimitry Andric 
20781ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
20881ad6265SDimitry Andric   SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
20981ad6265SDimitry Andric   SmallVector<Value *, 4> Args;
21081ad6265SDimitry Andric   Args.push_back(IRB->getInt1(I.isInBounds()));
21181ad6265SDimitry Andric   for (auto &Op : I.operands())
21281ad6265SDimitry Andric     Args.push_back(Op);
21381ad6265SDimitry Andric   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
21481ad6265SDimitry Andric   I.replaceAllUsesWith(NewI);
21581ad6265SDimitry Andric   I.eraseFromParent();
21681ad6265SDimitry Andric   return NewI;
21781ad6265SDimitry Andric }
21881ad6265SDimitry Andric 
21981ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
22081ad6265SDimitry Andric   SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
22181ad6265SDimitry Andric   SmallVector<Value *> Args(I.op_begin(), I.op_end());
22281ad6265SDimitry Andric   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});
22381ad6265SDimitry Andric   std::string InstName = I.hasName() ? I.getName().str() : "";
22481ad6265SDimitry Andric   I.replaceAllUsesWith(NewI);
22581ad6265SDimitry Andric   I.eraseFromParent();
22681ad6265SDimitry Andric   NewI->setName(InstName);
22781ad6265SDimitry Andric   return NewI;
22881ad6265SDimitry Andric }
22981ad6265SDimitry Andric 
23081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {
23181ad6265SDimitry Andric   SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),
23281ad6265SDimitry Andric                                   I.getOperand(1)->getType(),
23381ad6265SDimitry Andric                                   I.getOperand(2)->getType()};
23481ad6265SDimitry Andric   SmallVector<Value *> Args(I.op_begin(), I.op_end());
23581ad6265SDimitry Andric   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
23681ad6265SDimitry Andric   std::string InstName = I.hasName() ? I.getName().str() : "";
23781ad6265SDimitry Andric   I.replaceAllUsesWith(NewI);
23881ad6265SDimitry Andric   I.eraseFromParent();
23981ad6265SDimitry Andric   NewI->setName(InstName);
24081ad6265SDimitry Andric   return NewI;
24181ad6265SDimitry Andric }
24281ad6265SDimitry Andric 
24381ad6265SDimitry Andric Instruction *
24481ad6265SDimitry Andric SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {
24581ad6265SDimitry Andric   SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(),
24681ad6265SDimitry Andric                                   I.getIndexOperand()->getType()};
24781ad6265SDimitry Andric   SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};
24881ad6265SDimitry Andric   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});
24981ad6265SDimitry Andric   std::string InstName = I.hasName() ? I.getName().str() : "";
25081ad6265SDimitry Andric   I.replaceAllUsesWith(NewI);
25181ad6265SDimitry Andric   I.eraseFromParent();
25281ad6265SDimitry Andric   NewI->setName(InstName);
25381ad6265SDimitry Andric   return NewI;
25481ad6265SDimitry Andric }
25581ad6265SDimitry Andric 
25681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {
25781ad6265SDimitry Andric   SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()};
25881ad6265SDimitry Andric   SmallVector<Value *> Args;
25981ad6265SDimitry Andric   for (auto &Op : I.operands())
26081ad6265SDimitry Andric     if (isa<UndefValue>(Op))
26181ad6265SDimitry Andric       Args.push_back(UndefValue::get(IRB->getInt32Ty()));
26281ad6265SDimitry Andric     else
26381ad6265SDimitry Andric       Args.push_back(Op);
26481ad6265SDimitry Andric   for (auto &Op : I.indices())
26581ad6265SDimitry Andric     Args.push_back(IRB->getInt32(Op));
26681ad6265SDimitry Andric   Instruction *NewI =
26781ad6265SDimitry Andric       IRB->CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args});
26881ad6265SDimitry Andric   replaceMemInstrUses(&I, NewI);
26981ad6265SDimitry Andric   return NewI;
27081ad6265SDimitry Andric }
27181ad6265SDimitry Andric 
27281ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
27381ad6265SDimitry Andric   SmallVector<Value *> Args;
27481ad6265SDimitry Andric   for (auto &Op : I.operands())
27581ad6265SDimitry Andric     Args.push_back(Op);
27681ad6265SDimitry Andric   for (auto &Op : I.indices())
27781ad6265SDimitry Andric     Args.push_back(IRB->getInt32(Op));
27881ad6265SDimitry Andric   auto *NewI =
27981ad6265SDimitry Andric       IRB->CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});
28081ad6265SDimitry Andric   I.replaceAllUsesWith(NewI);
28181ad6265SDimitry Andric   I.eraseFromParent();
28281ad6265SDimitry Andric   return NewI;
28381ad6265SDimitry Andric }
28481ad6265SDimitry Andric 
28581ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) {
28681ad6265SDimitry Andric   if (!I.getType()->isAggregateType())
28781ad6265SDimitry Andric     return &I;
28881ad6265SDimitry Andric   TrackConstants = false;
28981ad6265SDimitry Andric   const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
29081ad6265SDimitry Andric   MachineMemOperand::Flags Flags =
29181ad6265SDimitry Andric       TLI->getLoadMemOperandFlags(I, F->getParent()->getDataLayout());
29281ad6265SDimitry Andric   auto *NewI =
29381ad6265SDimitry Andric       IRB->CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()},
29481ad6265SDimitry Andric                            {I.getPointerOperand(), IRB->getInt16(Flags),
29581ad6265SDimitry Andric                             IRB->getInt8(I.getAlign().value())});
29681ad6265SDimitry Andric   replaceMemInstrUses(&I, NewI);
29781ad6265SDimitry Andric   return NewI;
29881ad6265SDimitry Andric }
29981ad6265SDimitry Andric 
30081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {
30181ad6265SDimitry Andric   if (!AggrStores.contains(&I))
30281ad6265SDimitry Andric     return &I;
30381ad6265SDimitry Andric   TrackConstants = false;
30481ad6265SDimitry Andric   const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
30581ad6265SDimitry Andric   MachineMemOperand::Flags Flags =
30681ad6265SDimitry Andric       TLI->getStoreMemOperandFlags(I, F->getParent()->getDataLayout());
30781ad6265SDimitry Andric   auto *PtrOp = I.getPointerOperand();
308fcaf7f86SDimitry Andric   auto *NewI = IRB->CreateIntrinsic(
309fcaf7f86SDimitry Andric       Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()},
31081ad6265SDimitry Andric       {I.getValueOperand(), PtrOp, IRB->getInt16(Flags),
31181ad6265SDimitry Andric        IRB->getInt8(I.getAlign().value())});
31281ad6265SDimitry Andric   I.eraseFromParent();
31381ad6265SDimitry Andric   return NewI;
31481ad6265SDimitry Andric }
31581ad6265SDimitry Andric 
31681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {
31781ad6265SDimitry Andric   TrackConstants = false;
318*bdd1243dSDimitry Andric   Type *PtrTy = I.getType();
319*bdd1243dSDimitry Andric   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {});
320*bdd1243dSDimitry Andric   std::string InstName = I.hasName() ? I.getName().str() : "";
321*bdd1243dSDimitry Andric   I.replaceAllUsesWith(NewI);
322*bdd1243dSDimitry Andric   I.eraseFromParent();
323*bdd1243dSDimitry Andric   NewI->setName(InstName);
324*bdd1243dSDimitry Andric   return NewI;
32581ad6265SDimitry Andric }
32681ad6265SDimitry Andric 
327fcaf7f86SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
328fcaf7f86SDimitry Andric   assert(I.getType()->isAggregateType() && "Aggregate result is expected");
329fcaf7f86SDimitry Andric   SmallVector<Value *> Args;
330fcaf7f86SDimitry Andric   for (auto &Op : I.operands())
331fcaf7f86SDimitry Andric     Args.push_back(Op);
332fcaf7f86SDimitry Andric   Args.push_back(IRB->getInt32(I.getSyncScopeID()));
333fcaf7f86SDimitry Andric   Args.push_back(IRB->getInt32(
334fcaf7f86SDimitry Andric       static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering()))));
335fcaf7f86SDimitry Andric   Args.push_back(IRB->getInt32(
336fcaf7f86SDimitry Andric       static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering()))));
337fcaf7f86SDimitry Andric   auto *NewI = IRB->CreateIntrinsic(Intrinsic::spv_cmpxchg,
338fcaf7f86SDimitry Andric                                     {I.getPointerOperand()->getType()}, {Args});
339fcaf7f86SDimitry Andric   replaceMemInstrUses(&I, NewI);
340fcaf7f86SDimitry Andric   return NewI;
341fcaf7f86SDimitry Andric }
342fcaf7f86SDimitry Andric 
343*bdd1243dSDimitry Andric Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) {
344*bdd1243dSDimitry Andric   IRB->SetInsertPoint(&I);
345*bdd1243dSDimitry Andric   IRB->CreateIntrinsic(Intrinsic::spv_unreachable, {}, {});
346*bdd1243dSDimitry Andric   return &I;
347*bdd1243dSDimitry Andric }
348*bdd1243dSDimitry Andric 
34981ad6265SDimitry Andric void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) {
35081ad6265SDimitry Andric   // Skip special artifical variable llvm.global.annotations.
35181ad6265SDimitry Andric   if (GV.getName() == "llvm.global.annotations")
35281ad6265SDimitry Andric     return;
35381ad6265SDimitry Andric   if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) {
35481ad6265SDimitry Andric     Constant *Init = GV.getInitializer();
35581ad6265SDimitry Andric     Type *Ty = isAggrToReplace(Init) ? IRB->getInt32Ty() : Init->getType();
35681ad6265SDimitry Andric     Constant *Const = isAggrToReplace(Init) ? IRB->getInt32(1) : Init;
35781ad6265SDimitry Andric     auto *InitInst = IRB->CreateIntrinsic(Intrinsic::spv_init_global,
35881ad6265SDimitry Andric                                           {GV.getType(), Ty}, {&GV, Const});
35981ad6265SDimitry Andric     InitInst->setArgOperand(1, Init);
36081ad6265SDimitry Andric   }
36181ad6265SDimitry Andric   if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) &&
36281ad6265SDimitry Andric       GV.getNumUses() == 0)
36381ad6265SDimitry Andric     IRB->CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);
36481ad6265SDimitry Andric }
36581ad6265SDimitry Andric 
36681ad6265SDimitry Andric void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) {
36781ad6265SDimitry Andric   Type *Ty = I->getType();
36881ad6265SDimitry Andric   if (!Ty->isVoidTy() && requireAssignType(I)) {
36981ad6265SDimitry Andric     setInsertPointSkippingPhis(*IRB, I->getNextNode());
37081ad6265SDimitry Andric     Type *TypeToAssign = Ty;
37181ad6265SDimitry Andric     if (auto *II = dyn_cast<IntrinsicInst>(I)) {
37281ad6265SDimitry Andric       if (II->getIntrinsicID() == Intrinsic::spv_const_composite) {
37381ad6265SDimitry Andric         auto t = AggrConsts.find(II);
37481ad6265SDimitry Andric         assert(t != AggrConsts.end());
37581ad6265SDimitry Andric         TypeToAssign = t->second->getType();
37681ad6265SDimitry Andric       }
37781ad6265SDimitry Andric     }
37881ad6265SDimitry Andric     Constant *Const = Constant::getNullValue(TypeToAssign);
37981ad6265SDimitry Andric     buildIntrWithMD(Intrinsic::spv_assign_type, {Ty}, Const, I);
38081ad6265SDimitry Andric   }
38181ad6265SDimitry Andric   for (const auto &Op : I->operands()) {
38281ad6265SDimitry Andric     if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
38381ad6265SDimitry Andric         // Check GetElementPtrConstantExpr case.
38481ad6265SDimitry Andric         (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) {
385*bdd1243dSDimitry Andric       setInsertPointSkippingPhis(*IRB, I);
386fcaf7f86SDimitry Andric       if (isa<UndefValue>(Op) && Op->getType()->isAggregateType())
387fcaf7f86SDimitry Andric         buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op,
388fcaf7f86SDimitry Andric                         UndefValue::get(IRB->getInt32Ty()));
389fcaf7f86SDimitry Andric       else
39081ad6265SDimitry Andric         buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op);
39181ad6265SDimitry Andric     }
39281ad6265SDimitry Andric   }
39381ad6265SDimitry Andric }
39481ad6265SDimitry Andric 
39581ad6265SDimitry Andric void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I) {
39681ad6265SDimitry Andric   auto *II = dyn_cast<IntrinsicInst>(I);
39781ad6265SDimitry Andric   if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
39881ad6265SDimitry Andric       TrackConstants) {
39981ad6265SDimitry Andric     IRB->SetInsertPoint(I->getNextNode());
40081ad6265SDimitry Andric     Type *Ty = IRB->getInt32Ty();
40181ad6265SDimitry Andric     auto t = AggrConsts.find(I);
40281ad6265SDimitry Andric     assert(t != AggrConsts.end());
40381ad6265SDimitry Andric     auto *NewOp =
40481ad6265SDimitry Andric         buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, t->second, I);
40581ad6265SDimitry Andric     I->replaceAllUsesWith(NewOp);
40681ad6265SDimitry Andric     NewOp->setArgOperand(0, I);
40781ad6265SDimitry Andric   }
40881ad6265SDimitry Andric   for (const auto &Op : I->operands()) {
40981ad6265SDimitry Andric     if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) ||
41081ad6265SDimitry Andric         isa<PHINode>(I) || isa<SwitchInst>(I))
41181ad6265SDimitry Andric       TrackConstants = false;
412fcaf7f86SDimitry Andric     if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) {
41381ad6265SDimitry Andric       unsigned OpNo = Op.getOperandNo();
41481ad6265SDimitry Andric       if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
41581ad6265SDimitry Andric                  (II->paramHasAttr(OpNo, Attribute::ImmArg))))
41681ad6265SDimitry Andric         continue;
41781ad6265SDimitry Andric       IRB->SetInsertPoint(I);
41881ad6265SDimitry Andric       auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
41981ad6265SDimitry Andric                                     {Op->getType(), Op->getType()}, Op, Op);
42081ad6265SDimitry Andric       I->setOperand(OpNo, NewOp);
42181ad6265SDimitry Andric     }
42281ad6265SDimitry Andric   }
42381ad6265SDimitry Andric   if (I->hasName()) {
42481ad6265SDimitry Andric     setInsertPointSkippingPhis(*IRB, I->getNextNode());
42581ad6265SDimitry Andric     std::vector<Value *> Args = {I};
42681ad6265SDimitry Andric     addStringImm(I->getName(), *IRB, Args);
42781ad6265SDimitry Andric     IRB->CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);
42881ad6265SDimitry Andric   }
42981ad6265SDimitry Andric }
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
43281ad6265SDimitry Andric   if (Func.isDeclaration())
43381ad6265SDimitry Andric     return false;
43481ad6265SDimitry Andric   F = &Func;
43581ad6265SDimitry Andric   IRB = new IRBuilder<>(Func.getContext());
43681ad6265SDimitry Andric   AggrConsts.clear();
43781ad6265SDimitry Andric   AggrStores.clear();
43881ad6265SDimitry Andric 
439fcaf7f86SDimitry Andric   // StoreInst's operand type can be changed during the next transformations,
440fcaf7f86SDimitry Andric   // so we need to store it in the set. Also store already transformed types.
441fcaf7f86SDimitry Andric   for (auto &I : instructions(Func)) {
442fcaf7f86SDimitry Andric     StoreInst *SI = dyn_cast<StoreInst>(&I);
443fcaf7f86SDimitry Andric     if (!SI)
444fcaf7f86SDimitry Andric       continue;
445fcaf7f86SDimitry Andric     Type *ElTy = SI->getValueOperand()->getType();
446fcaf7f86SDimitry Andric     PointerType *PTy = cast<PointerType>(SI->getOperand(1)->getType());
447fcaf7f86SDimitry Andric     if (ElTy->isAggregateType() || ElTy->isVectorTy() ||
448fcaf7f86SDimitry Andric         !PTy->isOpaqueOrPointeeTypeMatches(ElTy))
449fcaf7f86SDimitry Andric       AggrStores.insert(&I);
450fcaf7f86SDimitry Andric   }
45181ad6265SDimitry Andric 
452fcaf7f86SDimitry Andric   IRB->SetInsertPoint(&Func.getEntryBlock().front());
45381ad6265SDimitry Andric   for (auto &GV : Func.getParent()->globals())
45481ad6265SDimitry Andric     processGlobalValue(GV);
45581ad6265SDimitry Andric 
45681ad6265SDimitry Andric   preprocessCompositeConstants();
45781ad6265SDimitry Andric   SmallVector<Instruction *> Worklist;
45881ad6265SDimitry Andric   for (auto &I : instructions(Func))
45981ad6265SDimitry Andric     Worklist.push_back(&I);
46081ad6265SDimitry Andric 
46181ad6265SDimitry Andric   for (auto &I : Worklist)
46281ad6265SDimitry Andric     insertAssignTypeIntrs(I);
46381ad6265SDimitry Andric 
46481ad6265SDimitry Andric   for (auto *I : Worklist) {
46581ad6265SDimitry Andric     TrackConstants = true;
46681ad6265SDimitry Andric     if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
46781ad6265SDimitry Andric       IRB->SetInsertPoint(I->getNextNode());
46881ad6265SDimitry Andric     I = visit(*I);
46981ad6265SDimitry Andric     processInstrAfterVisit(I);
47081ad6265SDimitry Andric   }
47181ad6265SDimitry Andric   return true;
47281ad6265SDimitry Andric }
47381ad6265SDimitry Andric 
47481ad6265SDimitry Andric FunctionPass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) {
47581ad6265SDimitry Andric   return new SPIRVEmitIntrinsics(TM);
47681ad6265SDimitry Andric }
477