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"
15*0fca6ea1SDimitry Andric #include "SPIRVBuiltins.h"
16*0fca6ea1SDimitry Andric #include "SPIRVMetadata.h"
17*0fca6ea1SDimitry Andric #include "SPIRVSubtarget.h"
1881ad6265SDimitry Andric #include "SPIRVTargetMachine.h"
1981ad6265SDimitry Andric #include "SPIRVUtils.h"
2081ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h"
2181ad6265SDimitry Andric #include "llvm/IR/InstIterator.h"
2281ad6265SDimitry Andric #include "llvm/IR/InstVisitor.h"
2381ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h"
24*0fca6ea1SDimitry Andric #include "llvm/IR/TypedPointerType.h"
2581ad6265SDimitry Andric
2681ad6265SDimitry Andric #include <queue>
2781ad6265SDimitry Andric
2881ad6265SDimitry Andric // This pass performs the following transformation on LLVM IR level required
2981ad6265SDimitry Andric // for the following translation to SPIR-V:
3081ad6265SDimitry Andric // - replaces direct usages of aggregate constants with target-specific
3181ad6265SDimitry Andric // intrinsics;
3281ad6265SDimitry Andric // - replaces aggregates-related instructions (extract/insert, ld/st, etc)
3381ad6265SDimitry Andric // with a target-specific intrinsics;
3481ad6265SDimitry Andric // - emits intrinsics for the global variable initializers since IRTranslator
3581ad6265SDimitry Andric // doesn't handle them and it's not very convenient to translate them
3681ad6265SDimitry Andric // ourselves;
3781ad6265SDimitry Andric // - emits intrinsics to keep track of the string names assigned to the values;
3881ad6265SDimitry Andric // - emits intrinsics to keep track of constants (this is necessary to have an
3981ad6265SDimitry Andric // LLVM IR constant after the IRTranslation is completed) for their further
4081ad6265SDimitry Andric // deduplication;
4181ad6265SDimitry Andric // - emits intrinsics to keep track of original LLVM types of the values
4281ad6265SDimitry Andric // to be able to emit proper SPIR-V types eventually.
4381ad6265SDimitry Andric //
4481ad6265SDimitry Andric // TODO: consider removing spv.track.constant in favor of spv.assign.type.
4581ad6265SDimitry Andric
4681ad6265SDimitry Andric using namespace llvm;
4781ad6265SDimitry Andric
4881ad6265SDimitry Andric namespace llvm {
49*0fca6ea1SDimitry Andric namespace SPIRV {
50*0fca6ea1SDimitry Andric #define GET_BuiltinGroup_DECL
51*0fca6ea1SDimitry Andric #include "SPIRVGenTables.inc"
52*0fca6ea1SDimitry Andric } // namespace SPIRV
5381ad6265SDimitry Andric void initializeSPIRVEmitIntrinsicsPass(PassRegistry &);
5481ad6265SDimitry Andric } // namespace llvm
5581ad6265SDimitry Andric
5681ad6265SDimitry Andric namespace {
57*0fca6ea1SDimitry Andric
buildMD(Value * Arg)58*0fca6ea1SDimitry Andric inline MetadataAsValue *buildMD(Value *Arg) {
59*0fca6ea1SDimitry Andric LLVMContext &Ctx = Arg->getContext();
60*0fca6ea1SDimitry Andric return MetadataAsValue::get(
61*0fca6ea1SDimitry Andric Ctx, MDNode::get(Ctx, ValueAsMetadata::getConstant(Arg)));
62*0fca6ea1SDimitry Andric }
63*0fca6ea1SDimitry Andric
6481ad6265SDimitry Andric class SPIRVEmitIntrinsics
65*0fca6ea1SDimitry Andric : public ModulePass,
6681ad6265SDimitry Andric public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
6781ad6265SDimitry Andric SPIRVTargetMachine *TM = nullptr;
68*0fca6ea1SDimitry Andric SPIRVGlobalRegistry *GR = nullptr;
6981ad6265SDimitry Andric Function *F = nullptr;
7081ad6265SDimitry Andric bool TrackConstants = true;
7181ad6265SDimitry Andric DenseMap<Instruction *, Constant *> AggrConsts;
72*0fca6ea1SDimitry Andric DenseMap<Instruction *, Type *> AggrConstTypes;
7381ad6265SDimitry Andric DenseSet<Instruction *> AggrStores;
74*0fca6ea1SDimitry Andric SPIRV::InstructionSet::InstructionSet InstrSet;
75*0fca6ea1SDimitry Andric
76*0fca6ea1SDimitry Andric // a register of Instructions that don't have a complete type definition
77*0fca6ea1SDimitry Andric SmallPtrSet<Value *, 8> UncompleteTypeInfo;
78*0fca6ea1SDimitry Andric SmallVector<Instruction *> PostprocessWorklist;
79*0fca6ea1SDimitry Andric
80*0fca6ea1SDimitry Andric // well known result types of builtins
81*0fca6ea1SDimitry Andric enum WellKnownTypes { Event };
82*0fca6ea1SDimitry Andric
83*0fca6ea1SDimitry Andric // deduce element type of untyped pointers
84*0fca6ea1SDimitry Andric Type *deduceElementType(Value *I, bool UnknownElemTypeI8);
85*0fca6ea1SDimitry Andric Type *deduceElementTypeHelper(Value *I, bool UnknownElemTypeI8);
86*0fca6ea1SDimitry Andric Type *deduceElementTypeHelper(Value *I, std::unordered_set<Value *> &Visited,
87*0fca6ea1SDimitry Andric bool UnknownElemTypeI8);
88*0fca6ea1SDimitry Andric Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
89*0fca6ea1SDimitry Andric bool UnknownElemTypeI8);
90*0fca6ea1SDimitry Andric Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
91*0fca6ea1SDimitry Andric std::unordered_set<Value *> &Visited,
92*0fca6ea1SDimitry Andric bool UnknownElemTypeI8);
93*0fca6ea1SDimitry Andric Type *deduceElementTypeByUsersDeep(Value *Op,
94*0fca6ea1SDimitry Andric std::unordered_set<Value *> &Visited,
95*0fca6ea1SDimitry Andric bool UnknownElemTypeI8);
96*0fca6ea1SDimitry Andric void maybeAssignPtrType(Type *&Ty, Value *I, Type *RefTy,
97*0fca6ea1SDimitry Andric bool UnknownElemTypeI8);
98*0fca6ea1SDimitry Andric
99*0fca6ea1SDimitry Andric // deduce nested types of composites
100*0fca6ea1SDimitry Andric Type *deduceNestedTypeHelper(User *U, bool UnknownElemTypeI8);
101*0fca6ea1SDimitry Andric Type *deduceNestedTypeHelper(User *U, Type *Ty,
102*0fca6ea1SDimitry Andric std::unordered_set<Value *> &Visited,
103*0fca6ea1SDimitry Andric bool UnknownElemTypeI8);
104*0fca6ea1SDimitry Andric
105*0fca6ea1SDimitry Andric // deduce Types of operands of the Instruction if possible
106*0fca6ea1SDimitry Andric void deduceOperandElementType(Instruction *I, Instruction *AskOp = 0,
107*0fca6ea1SDimitry Andric Type *AskTy = 0, CallInst *AssignCI = 0);
108*0fca6ea1SDimitry Andric
109*0fca6ea1SDimitry Andric void preprocessCompositeConstants(IRBuilder<> &B);
110*0fca6ea1SDimitry Andric void preprocessUndefs(IRBuilder<> &B);
111*0fca6ea1SDimitry Andric
buildIntrWithMD(Intrinsic::ID IntrID,ArrayRef<Type * > Types,Value * Arg,Value * Arg2,ArrayRef<Constant * > Imms,IRBuilder<> & B)11281ad6265SDimitry Andric CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
113*0fca6ea1SDimitry Andric Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,
114*0fca6ea1SDimitry Andric IRBuilder<> &B) {
1155f757f3fSDimitry Andric SmallVector<Value *, 4> Args;
1165f757f3fSDimitry Andric Args.push_back(Arg2);
117*0fca6ea1SDimitry Andric Args.push_back(buildMD(Arg));
1185f757f3fSDimitry Andric for (auto *Imm : Imms)
1195f757f3fSDimitry Andric Args.push_back(Imm);
120*0fca6ea1SDimitry Andric return B.CreateIntrinsic(IntrID, {Types}, Args);
12181ad6265SDimitry Andric }
122*0fca6ea1SDimitry Andric
123*0fca6ea1SDimitry Andric void buildAssignType(IRBuilder<> &B, Type *ElemTy, Value *Arg);
124*0fca6ea1SDimitry Andric void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);
125*0fca6ea1SDimitry Andric void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType);
126*0fca6ea1SDimitry Andric
127*0fca6ea1SDimitry Andric void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
128*0fca6ea1SDimitry Andric void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);
129*0fca6ea1SDimitry Andric bool insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B,
130*0fca6ea1SDimitry Andric bool UnknownElemTypeI8);
131*0fca6ea1SDimitry Andric void insertAssignTypeIntrs(Instruction *I, IRBuilder<> &B);
132*0fca6ea1SDimitry Andric void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType, Value *V,
133*0fca6ea1SDimitry Andric IRBuilder<> &B);
134*0fca6ea1SDimitry Andric void replacePointerOperandWithPtrCast(Instruction *I, Value *Pointer,
135*0fca6ea1SDimitry Andric Type *ExpectedElementType,
136*0fca6ea1SDimitry Andric unsigned OperandToReplace,
137*0fca6ea1SDimitry Andric IRBuilder<> &B);
138*0fca6ea1SDimitry Andric void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
139*0fca6ea1SDimitry Andric void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);
140*0fca6ea1SDimitry Andric void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
141*0fca6ea1SDimitry Andric void processParamTypes(Function *F, IRBuilder<> &B);
142*0fca6ea1SDimitry Andric void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
143*0fca6ea1SDimitry Andric Type *deduceFunParamElementType(Function *F, unsigned OpIdx);
144*0fca6ea1SDimitry Andric Type *deduceFunParamElementType(Function *F, unsigned OpIdx,
145*0fca6ea1SDimitry Andric std::unordered_set<Function *> &FVisited);
14681ad6265SDimitry Andric
14781ad6265SDimitry Andric public:
14881ad6265SDimitry Andric static char ID;
SPIRVEmitIntrinsics()149*0fca6ea1SDimitry Andric SPIRVEmitIntrinsics() : ModulePass(ID) {
15081ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry());
15181ad6265SDimitry Andric }
SPIRVEmitIntrinsics(SPIRVTargetMachine * _TM)152*0fca6ea1SDimitry Andric SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : ModulePass(ID), TM(_TM) {
15381ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry());
15481ad6265SDimitry Andric }
visitInstruction(Instruction & I)15581ad6265SDimitry Andric Instruction *visitInstruction(Instruction &I) { return &I; }
15681ad6265SDimitry Andric Instruction *visitSwitchInst(SwitchInst &I);
15781ad6265SDimitry Andric Instruction *visitGetElementPtrInst(GetElementPtrInst &I);
15881ad6265SDimitry Andric Instruction *visitBitCastInst(BitCastInst &I);
15981ad6265SDimitry Andric Instruction *visitInsertElementInst(InsertElementInst &I);
16081ad6265SDimitry Andric Instruction *visitExtractElementInst(ExtractElementInst &I);
16181ad6265SDimitry Andric Instruction *visitInsertValueInst(InsertValueInst &I);
16281ad6265SDimitry Andric Instruction *visitExtractValueInst(ExtractValueInst &I);
16381ad6265SDimitry Andric Instruction *visitLoadInst(LoadInst &I);
16481ad6265SDimitry Andric Instruction *visitStoreInst(StoreInst &I);
16581ad6265SDimitry Andric Instruction *visitAllocaInst(AllocaInst &I);
166fcaf7f86SDimitry Andric Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
167bdd1243dSDimitry Andric Instruction *visitUnreachableInst(UnreachableInst &I);
168*0fca6ea1SDimitry Andric Instruction *visitCallInst(CallInst &I);
169*0fca6ea1SDimitry Andric
getPassName() const170*0fca6ea1SDimitry Andric StringRef getPassName() const override { return "SPIRV emit intrinsics"; }
171*0fca6ea1SDimitry Andric
172*0fca6ea1SDimitry Andric bool runOnModule(Module &M) override;
173*0fca6ea1SDimitry Andric bool runOnFunction(Function &F);
174*0fca6ea1SDimitry Andric bool postprocessTypes();
175*0fca6ea1SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const176*0fca6ea1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
177*0fca6ea1SDimitry Andric ModulePass::getAnalysisUsage(AU);
178*0fca6ea1SDimitry Andric }
17981ad6265SDimitry Andric };
180*0fca6ea1SDimitry Andric
isConvergenceIntrinsic(const Instruction * I)181*0fca6ea1SDimitry Andric bool isConvergenceIntrinsic(const Instruction *I) {
182*0fca6ea1SDimitry Andric const auto *II = dyn_cast<IntrinsicInst>(I);
183*0fca6ea1SDimitry Andric if (!II)
184*0fca6ea1SDimitry Andric return false;
185*0fca6ea1SDimitry Andric
186*0fca6ea1SDimitry Andric return II->getIntrinsicID() == Intrinsic::experimental_convergence_entry ||
187*0fca6ea1SDimitry Andric II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||
188*0fca6ea1SDimitry Andric II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor;
189*0fca6ea1SDimitry Andric }
19081ad6265SDimitry Andric } // namespace
19181ad6265SDimitry Andric
19281ad6265SDimitry Andric char SPIRVEmitIntrinsics::ID = 0;
19381ad6265SDimitry Andric
19481ad6265SDimitry Andric INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics",
19581ad6265SDimitry Andric false, false)
19681ad6265SDimitry Andric
isAssignTypeInstr(const Instruction * I)19781ad6265SDimitry Andric static inline bool isAssignTypeInstr(const Instruction *I) {
19881ad6265SDimitry Andric return isa<IntrinsicInst>(I) &&
19981ad6265SDimitry Andric cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type;
20081ad6265SDimitry Andric }
20181ad6265SDimitry Andric
isMemInstrToReplace(Instruction * I)20281ad6265SDimitry Andric static bool isMemInstrToReplace(Instruction *I) {
20381ad6265SDimitry Andric return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) ||
204fcaf7f86SDimitry Andric isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I);
20581ad6265SDimitry Andric }
20681ad6265SDimitry Andric
isAggrConstForceInt32(const Value * V)207*0fca6ea1SDimitry Andric static bool isAggrConstForceInt32(const Value *V) {
208*0fca6ea1SDimitry Andric return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||
209*0fca6ea1SDimitry Andric isa<ConstantDataArray>(V) ||
21081ad6265SDimitry Andric (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
21181ad6265SDimitry Andric }
21281ad6265SDimitry Andric
setInsertPointSkippingPhis(IRBuilder<> & B,Instruction * I)21381ad6265SDimitry Andric static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
21481ad6265SDimitry Andric if (isa<PHINode>(I))
215*0fca6ea1SDimitry Andric B.SetInsertPoint(I->getParent()->getFirstNonPHIOrDbgOrAlloca());
21681ad6265SDimitry Andric else
21781ad6265SDimitry Andric B.SetInsertPoint(I);
21881ad6265SDimitry Andric }
21981ad6265SDimitry Andric
setInsertPointAfterDef(IRBuilder<> & B,Instruction * I)220*0fca6ea1SDimitry Andric static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I) {
221*0fca6ea1SDimitry Andric B.SetCurrentDebugLocation(I->getDebugLoc());
222*0fca6ea1SDimitry Andric if (I->getType()->isVoidTy())
223*0fca6ea1SDimitry Andric B.SetInsertPoint(I->getNextNode());
224*0fca6ea1SDimitry Andric else
225*0fca6ea1SDimitry Andric B.SetInsertPoint(*I->getInsertionPointAfterDef());
2265f757f3fSDimitry Andric }
2275f757f3fSDimitry Andric
requireAssignType(Instruction * I)22881ad6265SDimitry Andric static bool requireAssignType(Instruction *I) {
22981ad6265SDimitry Andric IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I);
23081ad6265SDimitry Andric if (Intr) {
23181ad6265SDimitry Andric switch (Intr->getIntrinsicID()) {
23281ad6265SDimitry Andric case Intrinsic::invariant_start:
23381ad6265SDimitry Andric case Intrinsic::invariant_end:
23481ad6265SDimitry Andric return false;
23581ad6265SDimitry Andric }
23681ad6265SDimitry Andric }
23781ad6265SDimitry Andric return true;
23881ad6265SDimitry Andric }
23981ad6265SDimitry Andric
reportFatalOnTokenType(const Instruction * I)240*0fca6ea1SDimitry Andric static inline void reportFatalOnTokenType(const Instruction *I) {
241*0fca6ea1SDimitry Andric if (I->getType()->isTokenTy())
242*0fca6ea1SDimitry Andric report_fatal_error("A token is encountered but SPIR-V without extensions "
243*0fca6ea1SDimitry Andric "does not support token type",
244*0fca6ea1SDimitry Andric false);
245*0fca6ea1SDimitry Andric }
246*0fca6ea1SDimitry Andric
IsKernelArgInt8(Function * F,StoreInst * SI)247*0fca6ea1SDimitry Andric static bool IsKernelArgInt8(Function *F, StoreInst *SI) {
248*0fca6ea1SDimitry Andric return SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&
249*0fca6ea1SDimitry Andric isPointerTy(SI->getValueOperand()->getType()) &&
250*0fca6ea1SDimitry Andric isa<Argument>(SI->getValueOperand());
251*0fca6ea1SDimitry Andric }
252*0fca6ea1SDimitry Andric
253*0fca6ea1SDimitry Andric // Maybe restore original function return type.
restoreMutatedType(SPIRVGlobalRegistry * GR,Instruction * I,Type * Ty)254*0fca6ea1SDimitry Andric static inline Type *restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I,
255*0fca6ea1SDimitry Andric Type *Ty) {
256*0fca6ea1SDimitry Andric CallInst *CI = dyn_cast<CallInst>(I);
257*0fca6ea1SDimitry Andric if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||
258*0fca6ea1SDimitry Andric !CI->getCalledFunction() || CI->getCalledFunction()->isIntrinsic())
259*0fca6ea1SDimitry Andric return Ty;
260*0fca6ea1SDimitry Andric if (Type *OriginalTy = GR->findMutated(CI->getCalledFunction()))
261*0fca6ea1SDimitry Andric return OriginalTy;
262*0fca6ea1SDimitry Andric return Ty;
263*0fca6ea1SDimitry Andric }
264*0fca6ea1SDimitry Andric
265*0fca6ea1SDimitry Andric // Reconstruct type with nested element types according to deduced type info.
266*0fca6ea1SDimitry Andric // Return nullptr if no detailed type info is available.
reconstructType(SPIRVGlobalRegistry * GR,Value * Op)267*0fca6ea1SDimitry Andric static inline Type *reconstructType(SPIRVGlobalRegistry *GR, Value *Op) {
268*0fca6ea1SDimitry Andric Type *Ty = Op->getType();
269*0fca6ea1SDimitry Andric if (!isUntypedPointerTy(Ty))
270*0fca6ea1SDimitry Andric return Ty;
271*0fca6ea1SDimitry Andric // try to find the pointee type
272*0fca6ea1SDimitry Andric if (Type *NestedTy = GR->findDeducedElementType(Op))
273*0fca6ea1SDimitry Andric return getTypedPointerWrapper(NestedTy, getPointerAddressSpace(Ty));
274*0fca6ea1SDimitry Andric // not a pointer according to the type info (e.g., Event object)
275*0fca6ea1SDimitry Andric CallInst *CI = GR->findAssignPtrTypeInstr(Op);
276*0fca6ea1SDimitry Andric if (!CI)
277*0fca6ea1SDimitry Andric return nullptr;
278*0fca6ea1SDimitry Andric MetadataAsValue *MD = cast<MetadataAsValue>(CI->getArgOperand(1));
279*0fca6ea1SDimitry Andric return cast<ConstantAsMetadata>(MD->getMetadata())->getType();
280*0fca6ea1SDimitry Andric }
281*0fca6ea1SDimitry Andric
buildAssignType(IRBuilder<> & B,Type * Ty,Value * Arg)282*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::buildAssignType(IRBuilder<> &B, Type *Ty,
283*0fca6ea1SDimitry Andric Value *Arg) {
284*0fca6ea1SDimitry Andric Value *OfType = PoisonValue::get(Ty);
285*0fca6ea1SDimitry Andric CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,
286*0fca6ea1SDimitry Andric {Arg->getType()}, OfType, Arg, {}, B);
287*0fca6ea1SDimitry Andric GR->addAssignPtrTypeInstr(Arg, AssignCI);
288*0fca6ea1SDimitry Andric }
289*0fca6ea1SDimitry Andric
buildAssignPtr(IRBuilder<> & B,Type * ElemTy,Value * Arg)290*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::buildAssignPtr(IRBuilder<> &B, Type *ElemTy,
291*0fca6ea1SDimitry Andric Value *Arg) {
292*0fca6ea1SDimitry Andric Value *OfType = PoisonValue::get(ElemTy);
293*0fca6ea1SDimitry Andric CallInst *AssignPtrTyCI = GR->findAssignPtrTypeInstr(Arg);
294*0fca6ea1SDimitry Andric if (AssignPtrTyCI == nullptr ||
295*0fca6ea1SDimitry Andric AssignPtrTyCI->getParent()->getParent() != F) {
296*0fca6ea1SDimitry Andric AssignPtrTyCI = buildIntrWithMD(
297*0fca6ea1SDimitry Andric Intrinsic::spv_assign_ptr_type, {Arg->getType()}, OfType, Arg,
298*0fca6ea1SDimitry Andric {B.getInt32(getPointerAddressSpace(Arg->getType()))}, B);
299*0fca6ea1SDimitry Andric GR->addDeducedElementType(AssignPtrTyCI, ElemTy);
300*0fca6ea1SDimitry Andric GR->addDeducedElementType(Arg, ElemTy);
301*0fca6ea1SDimitry Andric GR->addAssignPtrTypeInstr(Arg, AssignPtrTyCI);
302*0fca6ea1SDimitry Andric } else {
303*0fca6ea1SDimitry Andric updateAssignType(AssignPtrTyCI, Arg, OfType);
304*0fca6ea1SDimitry Andric }
305*0fca6ea1SDimitry Andric }
306*0fca6ea1SDimitry Andric
updateAssignType(CallInst * AssignCI,Value * Arg,Value * OfType)307*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::updateAssignType(CallInst *AssignCI, Value *Arg,
308*0fca6ea1SDimitry Andric Value *OfType) {
309*0fca6ea1SDimitry Andric AssignCI->setArgOperand(1, buildMD(OfType));
310*0fca6ea1SDimitry Andric if (cast<IntrinsicInst>(AssignCI)->getIntrinsicID() !=
311*0fca6ea1SDimitry Andric Intrinsic::spv_assign_ptr_type)
312*0fca6ea1SDimitry Andric return;
313*0fca6ea1SDimitry Andric
314*0fca6ea1SDimitry Andric // update association with the pointee type
315*0fca6ea1SDimitry Andric Type *ElemTy = OfType->getType();
316*0fca6ea1SDimitry Andric GR->addDeducedElementType(AssignCI, ElemTy);
317*0fca6ea1SDimitry Andric GR->addDeducedElementType(Arg, ElemTy);
318*0fca6ea1SDimitry Andric }
319*0fca6ea1SDimitry Andric
320*0fca6ea1SDimitry Andric // Set element pointer type to the given value of ValueTy and tries to
321*0fca6ea1SDimitry Andric // specify this type further (recursively) by Operand value, if needed.
322*0fca6ea1SDimitry Andric Type *
deduceElementTypeByValueDeep(Type * ValueTy,Value * Operand,bool UnknownElemTypeI8)323*0fca6ea1SDimitry Andric SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
324*0fca6ea1SDimitry Andric bool UnknownElemTypeI8) {
325*0fca6ea1SDimitry Andric std::unordered_set<Value *> Visited;
326*0fca6ea1SDimitry Andric return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
327*0fca6ea1SDimitry Andric UnknownElemTypeI8);
328*0fca6ea1SDimitry Andric }
329*0fca6ea1SDimitry Andric
deduceElementTypeByValueDeep(Type * ValueTy,Value * Operand,std::unordered_set<Value * > & Visited,bool UnknownElemTypeI8)330*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
331*0fca6ea1SDimitry Andric Type *ValueTy, Value *Operand, std::unordered_set<Value *> &Visited,
332*0fca6ea1SDimitry Andric bool UnknownElemTypeI8) {
333*0fca6ea1SDimitry Andric Type *Ty = ValueTy;
334*0fca6ea1SDimitry Andric if (Operand) {
335*0fca6ea1SDimitry Andric if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
336*0fca6ea1SDimitry Andric if (Type *NestedTy =
337*0fca6ea1SDimitry Andric deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
338*0fca6ea1SDimitry Andric Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
339*0fca6ea1SDimitry Andric } else {
340*0fca6ea1SDimitry Andric Ty = deduceNestedTypeHelper(dyn_cast<User>(Operand), Ty, Visited,
341*0fca6ea1SDimitry Andric UnknownElemTypeI8);
342*0fca6ea1SDimitry Andric }
343*0fca6ea1SDimitry Andric }
344*0fca6ea1SDimitry Andric return Ty;
345*0fca6ea1SDimitry Andric }
346*0fca6ea1SDimitry Andric
347*0fca6ea1SDimitry Andric // Traverse User instructions to deduce an element pointer type of the operand.
deduceElementTypeByUsersDeep(Value * Op,std::unordered_set<Value * > & Visited,bool UnknownElemTypeI8)348*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
349*0fca6ea1SDimitry Andric Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {
350*0fca6ea1SDimitry Andric if (!Op || !isPointerTy(Op->getType()))
351*0fca6ea1SDimitry Andric return nullptr;
352*0fca6ea1SDimitry Andric
353*0fca6ea1SDimitry Andric if (auto ElemTy = getPointeeType(Op->getType()))
354*0fca6ea1SDimitry Andric return ElemTy;
355*0fca6ea1SDimitry Andric
356*0fca6ea1SDimitry Andric // maybe we already know operand's element type
357*0fca6ea1SDimitry Andric if (Type *KnownTy = GR->findDeducedElementType(Op))
358*0fca6ea1SDimitry Andric return KnownTy;
359*0fca6ea1SDimitry Andric
360*0fca6ea1SDimitry Andric for (User *OpU : Op->users()) {
361*0fca6ea1SDimitry Andric if (Instruction *Inst = dyn_cast<Instruction>(OpU)) {
362*0fca6ea1SDimitry Andric if (Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
363*0fca6ea1SDimitry Andric return Ty;
364*0fca6ea1SDimitry Andric }
365*0fca6ea1SDimitry Andric }
366*0fca6ea1SDimitry Andric return nullptr;
367*0fca6ea1SDimitry Andric }
368*0fca6ea1SDimitry Andric
369*0fca6ea1SDimitry Andric // Implements what we know in advance about intrinsics and builtin calls
370*0fca6ea1SDimitry Andric // TODO: consider feasibility of this particular case to be generalized by
371*0fca6ea1SDimitry Andric // encoding knowledge about intrinsics and builtin calls by corresponding
372*0fca6ea1SDimitry Andric // specification rules
getPointeeTypeByCallInst(StringRef DemangledName,Function * CalledF,unsigned OpIdx)373*0fca6ea1SDimitry Andric static Type *getPointeeTypeByCallInst(StringRef DemangledName,
374*0fca6ea1SDimitry Andric Function *CalledF, unsigned OpIdx) {
375*0fca6ea1SDimitry Andric if ((DemangledName.starts_with("__spirv_ocl_printf(") ||
376*0fca6ea1SDimitry Andric DemangledName.starts_with("printf(")) &&
377*0fca6ea1SDimitry Andric OpIdx == 0)
378*0fca6ea1SDimitry Andric return IntegerType::getInt8Ty(CalledF->getContext());
379*0fca6ea1SDimitry Andric return nullptr;
380*0fca6ea1SDimitry Andric }
381*0fca6ea1SDimitry Andric
382*0fca6ea1SDimitry Andric // Deduce and return a successfully deduced Type of the Instruction,
383*0fca6ea1SDimitry Andric // or nullptr otherwise.
deduceElementTypeHelper(Value * I,bool UnknownElemTypeI8)384*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
385*0fca6ea1SDimitry Andric bool UnknownElemTypeI8) {
386*0fca6ea1SDimitry Andric std::unordered_set<Value *> Visited;
387*0fca6ea1SDimitry Andric return deduceElementTypeHelper(I, Visited, UnknownElemTypeI8);
388*0fca6ea1SDimitry Andric }
389*0fca6ea1SDimitry Andric
maybeAssignPtrType(Type * & Ty,Value * Op,Type * RefTy,bool UnknownElemTypeI8)390*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,
391*0fca6ea1SDimitry Andric bool UnknownElemTypeI8) {
392*0fca6ea1SDimitry Andric if (isUntypedPointerTy(RefTy)) {
393*0fca6ea1SDimitry Andric if (!UnknownElemTypeI8)
394*0fca6ea1SDimitry Andric return;
395*0fca6ea1SDimitry Andric if (auto *I = dyn_cast<Instruction>(Op)) {
396*0fca6ea1SDimitry Andric UncompleteTypeInfo.insert(I);
397*0fca6ea1SDimitry Andric PostprocessWorklist.push_back(I);
398*0fca6ea1SDimitry Andric }
399*0fca6ea1SDimitry Andric }
400*0fca6ea1SDimitry Andric Ty = RefTy;
401*0fca6ea1SDimitry Andric }
402*0fca6ea1SDimitry Andric
deduceElementTypeHelper(Value * I,std::unordered_set<Value * > & Visited,bool UnknownElemTypeI8)403*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
404*0fca6ea1SDimitry Andric Value *I, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {
405*0fca6ea1SDimitry Andric // allow to pass nullptr as an argument
406*0fca6ea1SDimitry Andric if (!I)
407*0fca6ea1SDimitry Andric return nullptr;
408*0fca6ea1SDimitry Andric
409*0fca6ea1SDimitry Andric // maybe already known
410*0fca6ea1SDimitry Andric if (Type *KnownTy = GR->findDeducedElementType(I))
411*0fca6ea1SDimitry Andric return KnownTy;
412*0fca6ea1SDimitry Andric
413*0fca6ea1SDimitry Andric // maybe a cycle
414*0fca6ea1SDimitry Andric if (Visited.find(I) != Visited.end())
415*0fca6ea1SDimitry Andric return nullptr;
416*0fca6ea1SDimitry Andric Visited.insert(I);
417*0fca6ea1SDimitry Andric
418*0fca6ea1SDimitry Andric // fallback value in case when we fail to deduce a type
419*0fca6ea1SDimitry Andric Type *Ty = nullptr;
420*0fca6ea1SDimitry Andric // look for known basic patterns of type inference
421*0fca6ea1SDimitry Andric if (auto *Ref = dyn_cast<AllocaInst>(I)) {
422*0fca6ea1SDimitry Andric maybeAssignPtrType(Ty, I, Ref->getAllocatedType(), UnknownElemTypeI8);
423*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
424*0fca6ea1SDimitry Andric Ty = Ref->getResultElementType();
425*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<GlobalValue>(I)) {
426*0fca6ea1SDimitry Andric Ty = deduceElementTypeByValueDeep(
427*0fca6ea1SDimitry Andric Ref->getValueType(),
428*0fca6ea1SDimitry Andric Ref->getNumOperands() > 0 ? Ref->getOperand(0) : nullptr, Visited,
429*0fca6ea1SDimitry Andric UnknownElemTypeI8);
430*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {
431*0fca6ea1SDimitry Andric Type *RefTy = deduceElementTypeHelper(Ref->getPointerOperand(), Visited,
432*0fca6ea1SDimitry Andric UnknownElemTypeI8);
433*0fca6ea1SDimitry Andric maybeAssignPtrType(Ty, I, RefTy, UnknownElemTypeI8);
434*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {
435*0fca6ea1SDimitry Andric if (Type *Src = Ref->getSrcTy(), *Dest = Ref->getDestTy();
436*0fca6ea1SDimitry Andric isPointerTy(Src) && isPointerTy(Dest))
437*0fca6ea1SDimitry Andric Ty = deduceElementTypeHelper(Ref->getOperand(0), Visited,
438*0fca6ea1SDimitry Andric UnknownElemTypeI8);
439*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {
440*0fca6ea1SDimitry Andric Value *Op = Ref->getNewValOperand();
441*0fca6ea1SDimitry Andric if (isPointerTy(Op->getType()))
442*0fca6ea1SDimitry Andric Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
443*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {
444*0fca6ea1SDimitry Andric Value *Op = Ref->getValOperand();
445*0fca6ea1SDimitry Andric if (isPointerTy(Op->getType()))
446*0fca6ea1SDimitry Andric Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
447*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<PHINode>(I)) {
448*0fca6ea1SDimitry Andric for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {
449*0fca6ea1SDimitry Andric Ty = deduceElementTypeByUsersDeep(Ref->getIncomingValue(i), Visited,
450*0fca6ea1SDimitry Andric UnknownElemTypeI8);
451*0fca6ea1SDimitry Andric if (Ty)
452*0fca6ea1SDimitry Andric break;
453*0fca6ea1SDimitry Andric }
454*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
455*0fca6ea1SDimitry Andric for (Value *Op : {Ref->getTrueValue(), Ref->getFalseValue()}) {
456*0fca6ea1SDimitry Andric Ty = deduceElementTypeByUsersDeep(Op, Visited, UnknownElemTypeI8);
457*0fca6ea1SDimitry Andric if (Ty)
458*0fca6ea1SDimitry Andric break;
459*0fca6ea1SDimitry Andric }
460*0fca6ea1SDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(I)) {
461*0fca6ea1SDimitry Andric static StringMap<unsigned> ResTypeByArg = {
462*0fca6ea1SDimitry Andric {"to_global", 0},
463*0fca6ea1SDimitry Andric {"to_local", 0},
464*0fca6ea1SDimitry Andric {"to_private", 0},
465*0fca6ea1SDimitry Andric {"__spirv_GenericCastToPtr_ToGlobal", 0},
466*0fca6ea1SDimitry Andric {"__spirv_GenericCastToPtr_ToLocal", 0},
467*0fca6ea1SDimitry Andric {"__spirv_GenericCastToPtr_ToPrivate", 0},
468*0fca6ea1SDimitry Andric {"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
469*0fca6ea1SDimitry Andric {"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
470*0fca6ea1SDimitry Andric {"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
471*0fca6ea1SDimitry Andric // TODO: maybe improve performance by caching demangled names
472*0fca6ea1SDimitry Andric if (Function *CalledF = CI->getCalledFunction()) {
473*0fca6ea1SDimitry Andric std::string DemangledName =
474*0fca6ea1SDimitry Andric getOclOrSpirvBuiltinDemangledName(CalledF->getName());
475*0fca6ea1SDimitry Andric if (DemangledName.length() > 0)
476*0fca6ea1SDimitry Andric DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
477*0fca6ea1SDimitry Andric auto AsArgIt = ResTypeByArg.find(DemangledName);
478*0fca6ea1SDimitry Andric if (AsArgIt != ResTypeByArg.end()) {
479*0fca6ea1SDimitry Andric Ty = deduceElementTypeHelper(CI->getArgOperand(AsArgIt->second),
480*0fca6ea1SDimitry Andric Visited, UnknownElemTypeI8);
481*0fca6ea1SDimitry Andric }
482*0fca6ea1SDimitry Andric }
483*0fca6ea1SDimitry Andric }
484*0fca6ea1SDimitry Andric
485*0fca6ea1SDimitry Andric // remember the found relationship
486*0fca6ea1SDimitry Andric if (Ty) {
487*0fca6ea1SDimitry Andric // specify nested types if needed, otherwise return unchanged
488*0fca6ea1SDimitry Andric GR->addDeducedElementType(I, Ty);
489*0fca6ea1SDimitry Andric }
490*0fca6ea1SDimitry Andric
491*0fca6ea1SDimitry Andric return Ty;
492*0fca6ea1SDimitry Andric }
493*0fca6ea1SDimitry Andric
494*0fca6ea1SDimitry Andric // Re-create a type of the value if it has untyped pointer fields, also nested.
495*0fca6ea1SDimitry Andric // Return the original value type if no corrections of untyped pointer
496*0fca6ea1SDimitry Andric // information is found or needed.
deduceNestedTypeHelper(User * U,bool UnknownElemTypeI8)497*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
498*0fca6ea1SDimitry Andric bool UnknownElemTypeI8) {
499*0fca6ea1SDimitry Andric std::unordered_set<Value *> Visited;
500*0fca6ea1SDimitry Andric return deduceNestedTypeHelper(U, U->getType(), Visited, UnknownElemTypeI8);
501*0fca6ea1SDimitry Andric }
502*0fca6ea1SDimitry Andric
deduceNestedTypeHelper(User * U,Type * OrigTy,std::unordered_set<Value * > & Visited,bool UnknownElemTypeI8)503*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
504*0fca6ea1SDimitry Andric User *U, Type *OrigTy, std::unordered_set<Value *> &Visited,
505*0fca6ea1SDimitry Andric bool UnknownElemTypeI8) {
506*0fca6ea1SDimitry Andric if (!U)
507*0fca6ea1SDimitry Andric return OrigTy;
508*0fca6ea1SDimitry Andric
509*0fca6ea1SDimitry Andric // maybe already known
510*0fca6ea1SDimitry Andric if (Type *KnownTy = GR->findDeducedCompositeType(U))
511*0fca6ea1SDimitry Andric return KnownTy;
512*0fca6ea1SDimitry Andric
513*0fca6ea1SDimitry Andric // maybe a cycle
514*0fca6ea1SDimitry Andric if (Visited.find(U) != Visited.end())
515*0fca6ea1SDimitry Andric return OrigTy;
516*0fca6ea1SDimitry Andric Visited.insert(U);
517*0fca6ea1SDimitry Andric
518*0fca6ea1SDimitry Andric if (dyn_cast<StructType>(OrigTy)) {
519*0fca6ea1SDimitry Andric SmallVector<Type *> Tys;
520*0fca6ea1SDimitry Andric bool Change = false;
521*0fca6ea1SDimitry Andric for (unsigned i = 0; i < U->getNumOperands(); ++i) {
522*0fca6ea1SDimitry Andric Value *Op = U->getOperand(i);
523*0fca6ea1SDimitry Andric Type *OpTy = Op->getType();
524*0fca6ea1SDimitry Andric Type *Ty = OpTy;
525*0fca6ea1SDimitry Andric if (Op) {
526*0fca6ea1SDimitry Andric if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
527*0fca6ea1SDimitry Andric if (Type *NestedTy =
528*0fca6ea1SDimitry Andric deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
529*0fca6ea1SDimitry Andric Ty = TypedPointerType::get(NestedTy, PtrTy->getAddressSpace());
530*0fca6ea1SDimitry Andric } else {
531*0fca6ea1SDimitry Andric Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
532*0fca6ea1SDimitry Andric UnknownElemTypeI8);
533*0fca6ea1SDimitry Andric }
534*0fca6ea1SDimitry Andric }
535*0fca6ea1SDimitry Andric Tys.push_back(Ty);
536*0fca6ea1SDimitry Andric Change |= Ty != OpTy;
537*0fca6ea1SDimitry Andric }
538*0fca6ea1SDimitry Andric if (Change) {
539*0fca6ea1SDimitry Andric Type *NewTy = StructType::create(Tys);
540*0fca6ea1SDimitry Andric GR->addDeducedCompositeType(U, NewTy);
541*0fca6ea1SDimitry Andric return NewTy;
542*0fca6ea1SDimitry Andric }
543*0fca6ea1SDimitry Andric } else if (auto *ArrTy = dyn_cast<ArrayType>(OrigTy)) {
544*0fca6ea1SDimitry Andric if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {
545*0fca6ea1SDimitry Andric Type *OpTy = ArrTy->getElementType();
546*0fca6ea1SDimitry Andric Type *Ty = OpTy;
547*0fca6ea1SDimitry Andric if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
548*0fca6ea1SDimitry Andric if (Type *NestedTy =
549*0fca6ea1SDimitry Andric deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
550*0fca6ea1SDimitry Andric Ty = TypedPointerType::get(NestedTy, PtrTy->getAddressSpace());
551*0fca6ea1SDimitry Andric } else {
552*0fca6ea1SDimitry Andric Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
553*0fca6ea1SDimitry Andric UnknownElemTypeI8);
554*0fca6ea1SDimitry Andric }
555*0fca6ea1SDimitry Andric if (Ty != OpTy) {
556*0fca6ea1SDimitry Andric Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
557*0fca6ea1SDimitry Andric GR->addDeducedCompositeType(U, NewTy);
558*0fca6ea1SDimitry Andric return NewTy;
559*0fca6ea1SDimitry Andric }
560*0fca6ea1SDimitry Andric }
561*0fca6ea1SDimitry Andric } else if (auto *VecTy = dyn_cast<VectorType>(OrigTy)) {
562*0fca6ea1SDimitry Andric if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {
563*0fca6ea1SDimitry Andric Type *OpTy = VecTy->getElementType();
564*0fca6ea1SDimitry Andric Type *Ty = OpTy;
565*0fca6ea1SDimitry Andric if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
566*0fca6ea1SDimitry Andric if (Type *NestedTy =
567*0fca6ea1SDimitry Andric deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
568*0fca6ea1SDimitry Andric Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
569*0fca6ea1SDimitry Andric } else {
570*0fca6ea1SDimitry Andric Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
571*0fca6ea1SDimitry Andric UnknownElemTypeI8);
572*0fca6ea1SDimitry Andric }
573*0fca6ea1SDimitry Andric if (Ty != OpTy) {
574*0fca6ea1SDimitry Andric Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
575*0fca6ea1SDimitry Andric GR->addDeducedCompositeType(U, NewTy);
576*0fca6ea1SDimitry Andric return NewTy;
577*0fca6ea1SDimitry Andric }
578*0fca6ea1SDimitry Andric }
579*0fca6ea1SDimitry Andric }
580*0fca6ea1SDimitry Andric
581*0fca6ea1SDimitry Andric return OrigTy;
582*0fca6ea1SDimitry Andric }
583*0fca6ea1SDimitry Andric
deduceElementType(Value * I,bool UnknownElemTypeI8)584*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceElementType(Value *I, bool UnknownElemTypeI8) {
585*0fca6ea1SDimitry Andric if (Type *Ty = deduceElementTypeHelper(I, UnknownElemTypeI8))
586*0fca6ea1SDimitry Andric return Ty;
587*0fca6ea1SDimitry Andric if (!UnknownElemTypeI8)
588*0fca6ea1SDimitry Andric return nullptr;
589*0fca6ea1SDimitry Andric if (auto *Instr = dyn_cast<Instruction>(I)) {
590*0fca6ea1SDimitry Andric UncompleteTypeInfo.insert(Instr);
591*0fca6ea1SDimitry Andric PostprocessWorklist.push_back(Instr);
592*0fca6ea1SDimitry Andric }
593*0fca6ea1SDimitry Andric return IntegerType::getInt8Ty(I->getContext());
594*0fca6ea1SDimitry Andric }
595*0fca6ea1SDimitry Andric
getAtomicElemTy(SPIRVGlobalRegistry * GR,Instruction * I,Value * PointerOperand)596*0fca6ea1SDimitry Andric static inline Type *getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I,
597*0fca6ea1SDimitry Andric Value *PointerOperand) {
598*0fca6ea1SDimitry Andric Type *PointeeTy = GR->findDeducedElementType(PointerOperand);
599*0fca6ea1SDimitry Andric if (PointeeTy && !isUntypedPointerTy(PointeeTy))
600*0fca6ea1SDimitry Andric return nullptr;
601*0fca6ea1SDimitry Andric auto *PtrTy = dyn_cast<PointerType>(I->getType());
602*0fca6ea1SDimitry Andric if (!PtrTy)
603*0fca6ea1SDimitry Andric return I->getType();
604*0fca6ea1SDimitry Andric if (Type *NestedTy = GR->findDeducedElementType(I))
605*0fca6ea1SDimitry Andric return getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
606*0fca6ea1SDimitry Andric return nullptr;
607*0fca6ea1SDimitry Andric }
608*0fca6ea1SDimitry Andric
609*0fca6ea1SDimitry Andric // If the Instruction has Pointer operands with unresolved types, this function
610*0fca6ea1SDimitry Andric // tries to deduce them. If the Instruction has Pointer operands with known
611*0fca6ea1SDimitry Andric // types which differ from expected, this function tries to insert a bitcast to
612*0fca6ea1SDimitry Andric // resolve the issue.
deduceOperandElementType(Instruction * I,Instruction * AskOp,Type * AskTy,CallInst * AskCI)613*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I,
614*0fca6ea1SDimitry Andric Instruction *AskOp,
615*0fca6ea1SDimitry Andric Type *AskTy,
616*0fca6ea1SDimitry Andric CallInst *AskCI) {
617*0fca6ea1SDimitry Andric SmallVector<std::pair<Value *, unsigned>> Ops;
618*0fca6ea1SDimitry Andric Type *KnownElemTy = nullptr;
619*0fca6ea1SDimitry Andric // look for known basic patterns of type inference
620*0fca6ea1SDimitry Andric if (auto *Ref = dyn_cast<PHINode>(I)) {
621*0fca6ea1SDimitry Andric if (!isPointerTy(I->getType()) ||
622*0fca6ea1SDimitry Andric !(KnownElemTy = GR->findDeducedElementType(I)))
623*0fca6ea1SDimitry Andric return;
624*0fca6ea1SDimitry Andric for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {
625*0fca6ea1SDimitry Andric Value *Op = Ref->getIncomingValue(i);
626*0fca6ea1SDimitry Andric if (isPointerTy(Op->getType()))
627*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Op, i));
628*0fca6ea1SDimitry Andric }
629*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {
630*0fca6ea1SDimitry Andric KnownElemTy = GR->findDeducedElementType(I);
631*0fca6ea1SDimitry Andric if (!KnownElemTy)
632*0fca6ea1SDimitry Andric return;
633*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Ref->getPointerOperand(), 0));
634*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
635*0fca6ea1SDimitry Andric KnownElemTy = Ref->getSourceElementType();
636*0fca6ea1SDimitry Andric if (isUntypedPointerTy(KnownElemTy))
637*0fca6ea1SDimitry Andric return;
638*0fca6ea1SDimitry Andric Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
639*0fca6ea1SDimitry Andric if (PointeeTy && !isUntypedPointerTy(PointeeTy))
640*0fca6ea1SDimitry Andric return;
641*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Ref->getPointerOperand(),
642*0fca6ea1SDimitry Andric GetElementPtrInst::getPointerOperandIndex()));
643*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<LoadInst>(I)) {
644*0fca6ea1SDimitry Andric KnownElemTy = I->getType();
645*0fca6ea1SDimitry Andric if (isUntypedPointerTy(KnownElemTy))
646*0fca6ea1SDimitry Andric return;
647*0fca6ea1SDimitry Andric Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
648*0fca6ea1SDimitry Andric if (PointeeTy && !isUntypedPointerTy(PointeeTy))
649*0fca6ea1SDimitry Andric return;
650*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Ref->getPointerOperand(),
651*0fca6ea1SDimitry Andric LoadInst::getPointerOperandIndex()));
652*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<StoreInst>(I)) {
653*0fca6ea1SDimitry Andric if (IsKernelArgInt8(Ref->getParent()->getParent(), Ref))
654*0fca6ea1SDimitry Andric return;
655*0fca6ea1SDimitry Andric if (!(KnownElemTy = reconstructType(GR, Ref->getValueOperand())))
656*0fca6ea1SDimitry Andric return;
657*0fca6ea1SDimitry Andric Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
658*0fca6ea1SDimitry Andric if (PointeeTy && !isUntypedPointerTy(PointeeTy))
659*0fca6ea1SDimitry Andric return;
660*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Ref->getPointerOperand(),
661*0fca6ea1SDimitry Andric StoreInst::getPointerOperandIndex()));
662*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {
663*0fca6ea1SDimitry Andric KnownElemTy = getAtomicElemTy(GR, I, Ref->getPointerOperand());
664*0fca6ea1SDimitry Andric if (!KnownElemTy)
665*0fca6ea1SDimitry Andric return;
666*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Ref->getPointerOperand(),
667*0fca6ea1SDimitry Andric AtomicCmpXchgInst::getPointerOperandIndex()));
668*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {
669*0fca6ea1SDimitry Andric KnownElemTy = getAtomicElemTy(GR, I, Ref->getPointerOperand());
670*0fca6ea1SDimitry Andric if (!KnownElemTy)
671*0fca6ea1SDimitry Andric return;
672*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Ref->getPointerOperand(),
673*0fca6ea1SDimitry Andric AtomicRMWInst::getPointerOperandIndex()));
674*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
675*0fca6ea1SDimitry Andric if (!isPointerTy(I->getType()) ||
676*0fca6ea1SDimitry Andric !(KnownElemTy = GR->findDeducedElementType(I)))
677*0fca6ea1SDimitry Andric return;
678*0fca6ea1SDimitry Andric for (unsigned i = 0; i < Ref->getNumOperands(); i++) {
679*0fca6ea1SDimitry Andric Value *Op = Ref->getOperand(i);
680*0fca6ea1SDimitry Andric if (isPointerTy(Op->getType()))
681*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Op, i));
682*0fca6ea1SDimitry Andric }
683*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<ReturnInst>(I)) {
684*0fca6ea1SDimitry Andric Type *RetTy = F->getReturnType();
685*0fca6ea1SDimitry Andric if (!isPointerTy(RetTy))
686*0fca6ea1SDimitry Andric return;
687*0fca6ea1SDimitry Andric Value *Op = Ref->getReturnValue();
688*0fca6ea1SDimitry Andric if (!Op)
689*0fca6ea1SDimitry Andric return;
690*0fca6ea1SDimitry Andric if (!(KnownElemTy = GR->findDeducedElementType(F))) {
691*0fca6ea1SDimitry Andric if (Type *OpElemTy = GR->findDeducedElementType(Op)) {
692*0fca6ea1SDimitry Andric GR->addDeducedElementType(F, OpElemTy);
693*0fca6ea1SDimitry Andric TypedPointerType *DerivedTy =
694*0fca6ea1SDimitry Andric TypedPointerType::get(OpElemTy, getPointerAddressSpace(RetTy));
695*0fca6ea1SDimitry Andric GR->addReturnType(F, DerivedTy);
696*0fca6ea1SDimitry Andric }
697*0fca6ea1SDimitry Andric return;
698*0fca6ea1SDimitry Andric }
699*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Op, 0));
700*0fca6ea1SDimitry Andric } else if (auto *Ref = dyn_cast<ICmpInst>(I)) {
701*0fca6ea1SDimitry Andric if (!isPointerTy(Ref->getOperand(0)->getType()))
702*0fca6ea1SDimitry Andric return;
703*0fca6ea1SDimitry Andric Value *Op0 = Ref->getOperand(0);
704*0fca6ea1SDimitry Andric Value *Op1 = Ref->getOperand(1);
705*0fca6ea1SDimitry Andric Type *ElemTy0 = GR->findDeducedElementType(Op0);
706*0fca6ea1SDimitry Andric Type *ElemTy1 = GR->findDeducedElementType(Op1);
707*0fca6ea1SDimitry Andric if (ElemTy0) {
708*0fca6ea1SDimitry Andric KnownElemTy = ElemTy0;
709*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Op1, 1));
710*0fca6ea1SDimitry Andric } else if (ElemTy1) {
711*0fca6ea1SDimitry Andric KnownElemTy = ElemTy1;
712*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Op0, 0));
713*0fca6ea1SDimitry Andric }
714*0fca6ea1SDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(I)) {
715*0fca6ea1SDimitry Andric if (Function *CalledF = CI->getCalledFunction()) {
716*0fca6ea1SDimitry Andric std::string DemangledName =
717*0fca6ea1SDimitry Andric getOclOrSpirvBuiltinDemangledName(CalledF->getName());
718*0fca6ea1SDimitry Andric if (DemangledName.length() > 0 &&
719*0fca6ea1SDimitry Andric !StringRef(DemangledName).starts_with("llvm.")) {
720*0fca6ea1SDimitry Andric auto [Grp, Opcode, ExtNo] =
721*0fca6ea1SDimitry Andric SPIRV::mapBuiltinToOpcode(DemangledName, InstrSet);
722*0fca6ea1SDimitry Andric if (Opcode == SPIRV::OpGroupAsyncCopy) {
723*0fca6ea1SDimitry Andric for (unsigned i = 0, PtrCnt = 0; i < CI->arg_size() && PtrCnt < 2;
724*0fca6ea1SDimitry Andric ++i) {
725*0fca6ea1SDimitry Andric Value *Op = CI->getArgOperand(i);
726*0fca6ea1SDimitry Andric if (!isPointerTy(Op->getType()))
727*0fca6ea1SDimitry Andric continue;
728*0fca6ea1SDimitry Andric ++PtrCnt;
729*0fca6ea1SDimitry Andric if (Type *ElemTy = GR->findDeducedElementType(Op))
730*0fca6ea1SDimitry Andric KnownElemTy = ElemTy; // src will rewrite dest if both are defined
731*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Op, i));
732*0fca6ea1SDimitry Andric }
733*0fca6ea1SDimitry Andric } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
734*0fca6ea1SDimitry Andric if (CI->arg_size() < 2)
735*0fca6ea1SDimitry Andric return;
736*0fca6ea1SDimitry Andric Value *Op = CI->getArgOperand(0);
737*0fca6ea1SDimitry Andric if (!isPointerTy(Op->getType()))
738*0fca6ea1SDimitry Andric return;
739*0fca6ea1SDimitry Andric switch (Opcode) {
740*0fca6ea1SDimitry Andric case SPIRV::OpAtomicLoad:
741*0fca6ea1SDimitry Andric case SPIRV::OpAtomicCompareExchangeWeak:
742*0fca6ea1SDimitry Andric case SPIRV::OpAtomicCompareExchange:
743*0fca6ea1SDimitry Andric case SPIRV::OpAtomicExchange:
744*0fca6ea1SDimitry Andric case SPIRV::OpAtomicIAdd:
745*0fca6ea1SDimitry Andric case SPIRV::OpAtomicISub:
746*0fca6ea1SDimitry Andric case SPIRV::OpAtomicOr:
747*0fca6ea1SDimitry Andric case SPIRV::OpAtomicXor:
748*0fca6ea1SDimitry Andric case SPIRV::OpAtomicAnd:
749*0fca6ea1SDimitry Andric case SPIRV::OpAtomicUMin:
750*0fca6ea1SDimitry Andric case SPIRV::OpAtomicUMax:
751*0fca6ea1SDimitry Andric case SPIRV::OpAtomicSMin:
752*0fca6ea1SDimitry Andric case SPIRV::OpAtomicSMax: {
753*0fca6ea1SDimitry Andric KnownElemTy = getAtomicElemTy(GR, I, Op);
754*0fca6ea1SDimitry Andric if (!KnownElemTy)
755*0fca6ea1SDimitry Andric return;
756*0fca6ea1SDimitry Andric Ops.push_back(std::make_pair(Op, 0));
757*0fca6ea1SDimitry Andric } break;
758*0fca6ea1SDimitry Andric }
759*0fca6ea1SDimitry Andric }
760*0fca6ea1SDimitry Andric }
761*0fca6ea1SDimitry Andric }
762*0fca6ea1SDimitry Andric }
763*0fca6ea1SDimitry Andric
764*0fca6ea1SDimitry Andric // There is no enough info to deduce types or all is valid.
765*0fca6ea1SDimitry Andric if (!KnownElemTy || Ops.size() == 0)
766*0fca6ea1SDimitry Andric return;
767*0fca6ea1SDimitry Andric
768*0fca6ea1SDimitry Andric LLVMContext &Ctx = F->getContext();
769*0fca6ea1SDimitry Andric IRBuilder<> B(Ctx);
770*0fca6ea1SDimitry Andric for (auto &OpIt : Ops) {
771*0fca6ea1SDimitry Andric Value *Op = OpIt.first;
772*0fca6ea1SDimitry Andric if (Op->use_empty() || (AskOp && Op != AskOp))
773*0fca6ea1SDimitry Andric continue;
774*0fca6ea1SDimitry Andric Type *Ty = AskOp ? AskTy : GR->findDeducedElementType(Op);
775*0fca6ea1SDimitry Andric if (Ty == KnownElemTy)
776*0fca6ea1SDimitry Andric continue;
777*0fca6ea1SDimitry Andric Value *OpTyVal = PoisonValue::get(KnownElemTy);
778*0fca6ea1SDimitry Andric Type *OpTy = Op->getType();
779*0fca6ea1SDimitry Andric if (!Ty || AskTy || isUntypedPointerTy(Ty) ||
780*0fca6ea1SDimitry Andric UncompleteTypeInfo.contains(Op)) {
781*0fca6ea1SDimitry Andric GR->addDeducedElementType(Op, KnownElemTy);
782*0fca6ea1SDimitry Andric // check if there is existing Intrinsic::spv_assign_ptr_type instruction
783*0fca6ea1SDimitry Andric CallInst *AssignCI = AskCI ? AskCI : GR->findAssignPtrTypeInstr(Op);
784*0fca6ea1SDimitry Andric if (AssignCI == nullptr) {
785*0fca6ea1SDimitry Andric Instruction *User = dyn_cast<Instruction>(Op->use_begin()->get());
786*0fca6ea1SDimitry Andric setInsertPointSkippingPhis(B, User ? User->getNextNode() : I);
787*0fca6ea1SDimitry Andric CallInst *CI =
788*0fca6ea1SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,
789*0fca6ea1SDimitry Andric {B.getInt32(getPointerAddressSpace(OpTy))}, B);
790*0fca6ea1SDimitry Andric GR->addAssignPtrTypeInstr(Op, CI);
791*0fca6ea1SDimitry Andric } else {
792*0fca6ea1SDimitry Andric updateAssignType(AssignCI, Op, OpTyVal);
793*0fca6ea1SDimitry Andric }
794*0fca6ea1SDimitry Andric } else {
795*0fca6ea1SDimitry Andric if (auto *OpI = dyn_cast<Instruction>(Op)) {
796*0fca6ea1SDimitry Andric // spv_ptrcast's argument Op denotes an instruction that generates
797*0fca6ea1SDimitry Andric // a value, and we may use getInsertionPointAfterDef()
798*0fca6ea1SDimitry Andric B.SetInsertPoint(*OpI->getInsertionPointAfterDef());
799*0fca6ea1SDimitry Andric B.SetCurrentDebugLocation(OpI->getDebugLoc());
800*0fca6ea1SDimitry Andric } else if (auto *OpA = dyn_cast<Argument>(Op)) {
801*0fca6ea1SDimitry Andric B.SetInsertPointPastAllocas(OpA->getParent());
802*0fca6ea1SDimitry Andric B.SetCurrentDebugLocation(DebugLoc());
803*0fca6ea1SDimitry Andric } else {
804*0fca6ea1SDimitry Andric B.SetInsertPoint(F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
805*0fca6ea1SDimitry Andric }
806*0fca6ea1SDimitry Andric SmallVector<Type *, 2> Types = {OpTy, OpTy};
807*0fca6ea1SDimitry Andric SmallVector<Value *, 2> Args = {Op, buildMD(OpTyVal),
808*0fca6ea1SDimitry Andric B.getInt32(getPointerAddressSpace(OpTy))};
809*0fca6ea1SDimitry Andric CallInst *PtrCastI =
810*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
811*0fca6ea1SDimitry Andric I->setOperand(OpIt.second, PtrCastI);
812*0fca6ea1SDimitry Andric }
813*0fca6ea1SDimitry Andric }
814*0fca6ea1SDimitry Andric }
815*0fca6ea1SDimitry Andric
replaceMemInstrUses(Instruction * Old,Instruction * New,IRBuilder<> & B)81681ad6265SDimitry Andric void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
817*0fca6ea1SDimitry Andric Instruction *New,
818*0fca6ea1SDimitry Andric IRBuilder<> &B) {
81981ad6265SDimitry Andric while (!Old->user_empty()) {
82081ad6265SDimitry Andric auto *U = Old->user_back();
821fcaf7f86SDimitry Andric if (isAssignTypeInstr(U)) {
822*0fca6ea1SDimitry Andric B.SetInsertPoint(U);
82381ad6265SDimitry Andric SmallVector<Value *, 2> Args = {New, U->getOperand(1)};
824*0fca6ea1SDimitry Andric CallInst *AssignCI =
825*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);
826*0fca6ea1SDimitry Andric GR->addAssignPtrTypeInstr(New, AssignCI);
82781ad6265SDimitry Andric U->eraseFromParent();
828fcaf7f86SDimitry Andric } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||
829fcaf7f86SDimitry Andric isa<CallInst>(U)) {
830fcaf7f86SDimitry Andric U->replaceUsesOfWith(Old, New);
83181ad6265SDimitry Andric } else {
83281ad6265SDimitry Andric llvm_unreachable("illegal aggregate intrinsic user");
83381ad6265SDimitry Andric }
83481ad6265SDimitry Andric }
83581ad6265SDimitry Andric Old->eraseFromParent();
83681ad6265SDimitry Andric }
83781ad6265SDimitry Andric
preprocessUndefs(IRBuilder<> & B)838*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::preprocessUndefs(IRBuilder<> &B) {
83906c3fb27SDimitry Andric std::queue<Instruction *> Worklist;
84006c3fb27SDimitry Andric for (auto &I : instructions(F))
84106c3fb27SDimitry Andric Worklist.push(&I);
84206c3fb27SDimitry Andric
84306c3fb27SDimitry Andric while (!Worklist.empty()) {
84406c3fb27SDimitry Andric Instruction *I = Worklist.front();
845*0fca6ea1SDimitry Andric bool BPrepared = false;
84606c3fb27SDimitry Andric Worklist.pop();
84706c3fb27SDimitry Andric
84806c3fb27SDimitry Andric for (auto &Op : I->operands()) {
84906c3fb27SDimitry Andric auto *AggrUndef = dyn_cast<UndefValue>(Op);
85006c3fb27SDimitry Andric if (!AggrUndef || !Op->getType()->isAggregateType())
85106c3fb27SDimitry Andric continue;
85206c3fb27SDimitry Andric
853*0fca6ea1SDimitry Andric if (!BPrepared) {
854*0fca6ea1SDimitry Andric setInsertPointSkippingPhis(B, I);
855*0fca6ea1SDimitry Andric BPrepared = true;
856*0fca6ea1SDimitry Andric }
857*0fca6ea1SDimitry Andric auto *IntrUndef = B.CreateIntrinsic(Intrinsic::spv_undef, {}, {});
85806c3fb27SDimitry Andric Worklist.push(IntrUndef);
85906c3fb27SDimitry Andric I->replaceUsesOfWith(Op, IntrUndef);
86006c3fb27SDimitry Andric AggrConsts[IntrUndef] = AggrUndef;
861*0fca6ea1SDimitry Andric AggrConstTypes[IntrUndef] = AggrUndef->getType();
86206c3fb27SDimitry Andric }
86306c3fb27SDimitry Andric }
86406c3fb27SDimitry Andric }
86506c3fb27SDimitry Andric
preprocessCompositeConstants(IRBuilder<> & B)866*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
86781ad6265SDimitry Andric std::queue<Instruction *> Worklist;
86881ad6265SDimitry Andric for (auto &I : instructions(F))
86981ad6265SDimitry Andric Worklist.push(&I);
87081ad6265SDimitry Andric
87181ad6265SDimitry Andric while (!Worklist.empty()) {
87281ad6265SDimitry Andric auto *I = Worklist.front();
873*0fca6ea1SDimitry Andric bool IsPhi = isa<PHINode>(I), BPrepared = false;
87481ad6265SDimitry Andric assert(I);
87581ad6265SDimitry Andric bool KeepInst = false;
87681ad6265SDimitry Andric for (const auto &Op : I->operands()) {
877*0fca6ea1SDimitry Andric Constant *AggrConst = nullptr;
878*0fca6ea1SDimitry Andric Type *ResTy = nullptr;
879*0fca6ea1SDimitry Andric if (auto *COp = dyn_cast<ConstantVector>(Op)) {
880*0fca6ea1SDimitry Andric AggrConst = cast<Constant>(COp);
881*0fca6ea1SDimitry Andric ResTy = COp->getType();
882*0fca6ea1SDimitry Andric } else if (auto *COp = dyn_cast<ConstantArray>(Op)) {
883*0fca6ea1SDimitry Andric AggrConst = cast<Constant>(COp);
884*0fca6ea1SDimitry Andric ResTy = B.getInt32Ty();
885*0fca6ea1SDimitry Andric } else if (auto *COp = dyn_cast<ConstantStruct>(Op)) {
886*0fca6ea1SDimitry Andric AggrConst = cast<Constant>(COp);
887*0fca6ea1SDimitry Andric ResTy = B.getInt32Ty();
888*0fca6ea1SDimitry Andric } else if (auto *COp = dyn_cast<ConstantDataArray>(Op)) {
889*0fca6ea1SDimitry Andric AggrConst = cast<Constant>(COp);
890*0fca6ea1SDimitry Andric ResTy = B.getInt32Ty();
891*0fca6ea1SDimitry Andric } else if (auto *COp = dyn_cast<ConstantAggregateZero>(Op)) {
892*0fca6ea1SDimitry Andric AggrConst = cast<Constant>(COp);
893*0fca6ea1SDimitry Andric ResTy = Op->getType()->isVectorTy() ? COp->getType() : B.getInt32Ty();
894*0fca6ea1SDimitry Andric }
895*0fca6ea1SDimitry Andric if (AggrConst) {
89681ad6265SDimitry Andric SmallVector<Value *> Args;
897*0fca6ea1SDimitry Andric if (auto *COp = dyn_cast<ConstantDataSequential>(Op))
898*0fca6ea1SDimitry Andric for (unsigned i = 0; i < COp->getNumElements(); ++i)
899*0fca6ea1SDimitry Andric Args.push_back(COp->getElementAsConstant(i));
900*0fca6ea1SDimitry Andric else
901*0fca6ea1SDimitry Andric for (auto &COp : AggrConst->operands())
902*0fca6ea1SDimitry Andric Args.push_back(COp);
903*0fca6ea1SDimitry Andric if (!BPrepared) {
904*0fca6ea1SDimitry Andric IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
905*0fca6ea1SDimitry Andric : B.SetInsertPoint(I);
906*0fca6ea1SDimitry Andric BPrepared = true;
907*0fca6ea1SDimitry Andric }
908*0fca6ea1SDimitry Andric auto *CI =
909*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {Args});
910*0fca6ea1SDimitry Andric Worklist.push(CI);
911*0fca6ea1SDimitry Andric I->replaceUsesOfWith(Op, CI);
912*0fca6ea1SDimitry Andric KeepInst = true;
913*0fca6ea1SDimitry Andric AggrConsts[CI] = AggrConst;
914*0fca6ea1SDimitry Andric AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst, false);
91581ad6265SDimitry Andric }
91681ad6265SDimitry Andric }
91781ad6265SDimitry Andric if (!KeepInst)
91881ad6265SDimitry Andric Worklist.pop();
91981ad6265SDimitry Andric }
92081ad6265SDimitry Andric }
92181ad6265SDimitry Andric
visitCallInst(CallInst & Call)922*0fca6ea1SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
923*0fca6ea1SDimitry Andric if (!Call.isInlineAsm())
924*0fca6ea1SDimitry Andric return &Call;
925*0fca6ea1SDimitry Andric
926*0fca6ea1SDimitry Andric const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
927*0fca6ea1SDimitry Andric LLVMContext &Ctx = F->getContext();
928*0fca6ea1SDimitry Andric
929*0fca6ea1SDimitry Andric Constant *TyC = UndefValue::get(IA->getFunctionType());
930*0fca6ea1SDimitry Andric MDString *ConstraintString = MDString::get(Ctx, IA->getConstraintString());
931*0fca6ea1SDimitry Andric SmallVector<Value *> Args = {
932*0fca6ea1SDimitry Andric buildMD(TyC),
933*0fca6ea1SDimitry Andric MetadataAsValue::get(Ctx, MDNode::get(Ctx, ConstraintString))};
934*0fca6ea1SDimitry Andric for (unsigned OpIdx = 0; OpIdx < Call.arg_size(); OpIdx++)
935*0fca6ea1SDimitry Andric Args.push_back(Call.getArgOperand(OpIdx));
936*0fca6ea1SDimitry Andric
937*0fca6ea1SDimitry Andric IRBuilder<> B(Call.getParent());
938*0fca6ea1SDimitry Andric B.SetInsertPoint(&Call);
939*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_inline_asm, {}, {Args});
940*0fca6ea1SDimitry Andric return &Call;
941*0fca6ea1SDimitry Andric }
942*0fca6ea1SDimitry Andric
visitSwitchInst(SwitchInst & I)94381ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
944*0fca6ea1SDimitry Andric BasicBlock *ParentBB = I.getParent();
945*0fca6ea1SDimitry Andric IRBuilder<> B(ParentBB);
946*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
94781ad6265SDimitry Andric SmallVector<Value *, 4> Args;
948*0fca6ea1SDimitry Andric SmallVector<BasicBlock *> BBCases;
949*0fca6ea1SDimitry Andric for (auto &Op : I.operands()) {
950*0fca6ea1SDimitry Andric if (Op.get()->getType()->isSized()) {
95181ad6265SDimitry Andric Args.push_back(Op);
952*0fca6ea1SDimitry Andric } else if (BasicBlock *BB = dyn_cast<BasicBlock>(Op.get())) {
953*0fca6ea1SDimitry Andric BBCases.push_back(BB);
954*0fca6ea1SDimitry Andric Args.push_back(BlockAddress::get(BB->getParent(), BB));
955*0fca6ea1SDimitry Andric } else {
956*0fca6ea1SDimitry Andric report_fatal_error("Unexpected switch operand");
957*0fca6ea1SDimitry Andric }
958*0fca6ea1SDimitry Andric }
959*0fca6ea1SDimitry Andric CallInst *NewI = B.CreateIntrinsic(Intrinsic::spv_switch,
960*0fca6ea1SDimitry Andric {I.getOperand(0)->getType()}, {Args});
961*0fca6ea1SDimitry Andric // remove switch to avoid its unneeded and undesirable unwrap into branches
962*0fca6ea1SDimitry Andric // and conditions
963*0fca6ea1SDimitry Andric I.replaceAllUsesWith(NewI);
964*0fca6ea1SDimitry Andric I.eraseFromParent();
965*0fca6ea1SDimitry Andric // insert artificial and temporary instruction to preserve valid CFG,
966*0fca6ea1SDimitry Andric // it will be removed after IR translation pass
967*0fca6ea1SDimitry Andric B.SetInsertPoint(ParentBB);
968*0fca6ea1SDimitry Andric IndirectBrInst *BrI = B.CreateIndirectBr(
969*0fca6ea1SDimitry Andric Constant::getNullValue(PointerType::getUnqual(ParentBB->getContext())),
970*0fca6ea1SDimitry Andric BBCases.size());
971*0fca6ea1SDimitry Andric for (BasicBlock *BBCase : BBCases)
972*0fca6ea1SDimitry Andric BrI->addDestination(BBCase);
973*0fca6ea1SDimitry Andric return BrI;
97481ad6265SDimitry Andric }
97581ad6265SDimitry Andric
visitGetElementPtrInst(GetElementPtrInst & I)97681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
977*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
978*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
97981ad6265SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
98081ad6265SDimitry Andric SmallVector<Value *, 4> Args;
981*0fca6ea1SDimitry Andric Args.push_back(B.getInt1(I.isInBounds()));
98281ad6265SDimitry Andric for (auto &Op : I.operands())
98381ad6265SDimitry Andric Args.push_back(Op);
984*0fca6ea1SDimitry Andric auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
98581ad6265SDimitry Andric I.replaceAllUsesWith(NewI);
98681ad6265SDimitry Andric I.eraseFromParent();
98781ad6265SDimitry Andric return NewI;
98881ad6265SDimitry Andric }
98981ad6265SDimitry Andric
visitBitCastInst(BitCastInst & I)99081ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
991*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
992*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
9931db9f3b2SDimitry Andric Value *Source = I.getOperand(0);
9941db9f3b2SDimitry Andric
9951db9f3b2SDimitry Andric // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of
9961db9f3b2SDimitry Andric // varying element types. In case of IR coming from older versions of LLVM
9971db9f3b2SDimitry Andric // such bitcasts do not provide sufficient information, should be just skipped
998*0fca6ea1SDimitry Andric // here, and handled in insertPtrCastOrAssignTypeInstr.
999*0fca6ea1SDimitry Andric if (isPointerTy(I.getType())) {
10001db9f3b2SDimitry Andric I.replaceAllUsesWith(Source);
10011db9f3b2SDimitry Andric I.eraseFromParent();
10021db9f3b2SDimitry Andric return nullptr;
10031db9f3b2SDimitry Andric }
10041db9f3b2SDimitry Andric
10051db9f3b2SDimitry Andric SmallVector<Type *, 2> Types = {I.getType(), Source->getType()};
100681ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end());
1007*0fca6ea1SDimitry Andric auto *NewI = B.CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});
100881ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : "";
100981ad6265SDimitry Andric I.replaceAllUsesWith(NewI);
101081ad6265SDimitry Andric I.eraseFromParent();
101181ad6265SDimitry Andric NewI->setName(InstName);
101281ad6265SDimitry Andric return NewI;
101381ad6265SDimitry Andric }
101481ad6265SDimitry Andric
insertAssignPtrTypeTargetExt(TargetExtType * AssignedType,Value * V,IRBuilder<> & B)1015*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
1016*0fca6ea1SDimitry Andric TargetExtType *AssignedType, Value *V, IRBuilder<> &B) {
1017*0fca6ea1SDimitry Andric Type *VTy = V->getType();
1018*0fca6ea1SDimitry Andric
1019*0fca6ea1SDimitry Andric // A couple of sanity checks.
1020*0fca6ea1SDimitry Andric assert(isPointerTy(VTy) && "Expect a pointer type!");
1021*0fca6ea1SDimitry Andric if (auto PType = dyn_cast<TypedPointerType>(VTy))
1022*0fca6ea1SDimitry Andric if (PType->getElementType() != AssignedType)
1023*0fca6ea1SDimitry Andric report_fatal_error("Unexpected pointer element type!");
1024*0fca6ea1SDimitry Andric
1025*0fca6ea1SDimitry Andric CallInst *AssignCI = GR->findAssignPtrTypeInstr(V);
1026*0fca6ea1SDimitry Andric if (!AssignCI) {
1027*0fca6ea1SDimitry Andric buildAssignType(B, AssignedType, V);
10281db9f3b2SDimitry Andric return;
10291db9f3b2SDimitry Andric }
10301db9f3b2SDimitry Andric
1031*0fca6ea1SDimitry Andric Type *CurrentType =
1032*0fca6ea1SDimitry Andric dyn_cast<ConstantAsMetadata>(
1033*0fca6ea1SDimitry Andric cast<MetadataAsValue>(AssignCI->getOperand(1))->getMetadata())
1034*0fca6ea1SDimitry Andric ->getType();
1035*0fca6ea1SDimitry Andric if (CurrentType == AssignedType)
1036*0fca6ea1SDimitry Andric return;
1037*0fca6ea1SDimitry Andric
1038*0fca6ea1SDimitry Andric // Builtin types cannot be redeclared or casted.
1039*0fca6ea1SDimitry Andric if (CurrentType->isTargetExtTy())
1040*0fca6ea1SDimitry Andric report_fatal_error("Type mismatch " + CurrentType->getTargetExtName() +
1041*0fca6ea1SDimitry Andric "/" + AssignedType->getTargetExtName() +
1042*0fca6ea1SDimitry Andric " for value " + V->getName(),
1043*0fca6ea1SDimitry Andric false);
1044*0fca6ea1SDimitry Andric
1045*0fca6ea1SDimitry Andric // Our previous guess about the type seems to be wrong, let's update
1046*0fca6ea1SDimitry Andric // inferred type according to a new, more precise type information.
1047*0fca6ea1SDimitry Andric updateAssignType(AssignCI, V, PoisonValue::get(AssignedType));
1048*0fca6ea1SDimitry Andric }
1049*0fca6ea1SDimitry Andric
replacePointerOperandWithPtrCast(Instruction * I,Value * Pointer,Type * ExpectedElementType,unsigned OperandToReplace,IRBuilder<> & B)1050*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
1051*0fca6ea1SDimitry Andric Instruction *I, Value *Pointer, Type *ExpectedElementType,
1052*0fca6ea1SDimitry Andric unsigned OperandToReplace, IRBuilder<> &B) {
10531db9f3b2SDimitry Andric // If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source
10541db9f3b2SDimitry Andric // pointer instead. The BitCastInst should be later removed when visited.
10551db9f3b2SDimitry Andric while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))
10561db9f3b2SDimitry Andric Pointer = BC->getOperand(0);
10571db9f3b2SDimitry Andric
1058*0fca6ea1SDimitry Andric // Do not emit spv_ptrcast if Pointer's element type is ExpectedElementType
1059*0fca6ea1SDimitry Andric Type *PointerElemTy = deduceElementTypeHelper(Pointer, false);
1060*0fca6ea1SDimitry Andric if (PointerElemTy == ExpectedElementType ||
1061*0fca6ea1SDimitry Andric isEquivalentTypes(PointerElemTy, ExpectedElementType))
10621db9f3b2SDimitry Andric return;
10631db9f3b2SDimitry Andric
1064*0fca6ea1SDimitry Andric setInsertPointSkippingPhis(B, I);
1065*0fca6ea1SDimitry Andric MetadataAsValue *VMD = buildMD(PoisonValue::get(ExpectedElementType));
1066*0fca6ea1SDimitry Andric unsigned AddressSpace = getPointerAddressSpace(Pointer->getType());
10671db9f3b2SDimitry Andric bool FirstPtrCastOrAssignPtrType = true;
10681db9f3b2SDimitry Andric
10691db9f3b2SDimitry Andric // Do not emit new spv_ptrcast if equivalent one already exists or when
10701db9f3b2SDimitry Andric // spv_assign_ptr_type already targets this pointer with the same element
10711db9f3b2SDimitry Andric // type.
10721db9f3b2SDimitry Andric for (auto User : Pointer->users()) {
10731db9f3b2SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(User);
10741db9f3b2SDimitry Andric if (!II ||
10751db9f3b2SDimitry Andric (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
10761db9f3b2SDimitry Andric II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
10771db9f3b2SDimitry Andric II->getOperand(0) != Pointer)
10781db9f3b2SDimitry Andric continue;
10791db9f3b2SDimitry Andric
10801db9f3b2SDimitry Andric // There is some spv_ptrcast/spv_assign_ptr_type already targeting this
10811db9f3b2SDimitry Andric // pointer.
10821db9f3b2SDimitry Andric FirstPtrCastOrAssignPtrType = false;
10831db9f3b2SDimitry Andric if (II->getOperand(1) != VMD ||
10841db9f3b2SDimitry Andric dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=
10851db9f3b2SDimitry Andric AddressSpace)
10861db9f3b2SDimitry Andric continue;
10871db9f3b2SDimitry Andric
10881db9f3b2SDimitry Andric // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the same
10891db9f3b2SDimitry Andric // element type and address space.
10901db9f3b2SDimitry Andric if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)
10911db9f3b2SDimitry Andric return;
10921db9f3b2SDimitry Andric
10931db9f3b2SDimitry Andric // This must be a spv_ptrcast, do not emit new if this one has the same BB
10941db9f3b2SDimitry Andric // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.
10951db9f3b2SDimitry Andric if (II->getParent() != I->getParent())
10961db9f3b2SDimitry Andric continue;
10971db9f3b2SDimitry Andric
10981db9f3b2SDimitry Andric I->setOperand(OperandToReplace, II);
10991db9f3b2SDimitry Andric return;
11001db9f3b2SDimitry Andric }
11011db9f3b2SDimitry Andric
1102*0fca6ea1SDimitry Andric // // Do not emit spv_ptrcast if it would cast to the default pointer element
1103*0fca6ea1SDimitry Andric // // type (i8) of the same address space.
1104*0fca6ea1SDimitry Andric // if (ExpectedElementType->isIntegerTy(8))
1105*0fca6ea1SDimitry Andric // return;
1106*0fca6ea1SDimitry Andric
1107*0fca6ea1SDimitry Andric // If this would be the first spv_ptrcast, do not emit spv_ptrcast and emit
1108*0fca6ea1SDimitry Andric // spv_assign_ptr_type instead.
1109*0fca6ea1SDimitry Andric if (FirstPtrCastOrAssignPtrType &&
1110*0fca6ea1SDimitry Andric (isa<Instruction>(Pointer) || isa<Argument>(Pointer))) {
1111*0fca6ea1SDimitry Andric buildAssignPtr(B, ExpectedElementType, Pointer);
1112*0fca6ea1SDimitry Andric return;
1113*0fca6ea1SDimitry Andric }
1114*0fca6ea1SDimitry Andric
1115*0fca6ea1SDimitry Andric // Emit spv_ptrcast
1116*0fca6ea1SDimitry Andric SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};
1117*0fca6ea1SDimitry Andric SmallVector<Value *, 2> Args = {Pointer, VMD, B.getInt32(AddressSpace)};
1118*0fca6ea1SDimitry Andric auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
1119*0fca6ea1SDimitry Andric I->setOperand(OperandToReplace, PtrCastI);
1120*0fca6ea1SDimitry Andric }
1121*0fca6ea1SDimitry Andric
insertPtrCastOrAssignTypeInstr(Instruction * I,IRBuilder<> & B)1122*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
1123*0fca6ea1SDimitry Andric IRBuilder<> &B) {
1124*0fca6ea1SDimitry Andric // Handle basic instructions:
1125*0fca6ea1SDimitry Andric StoreInst *SI = dyn_cast<StoreInst>(I);
1126*0fca6ea1SDimitry Andric if (IsKernelArgInt8(F, SI)) {
1127*0fca6ea1SDimitry Andric return replacePointerOperandWithPtrCast(
1128*0fca6ea1SDimitry Andric I, SI->getValueOperand(), IntegerType::getInt8Ty(F->getContext()), 0,
1129*0fca6ea1SDimitry Andric B);
1130*0fca6ea1SDimitry Andric } else if (SI) {
1131*0fca6ea1SDimitry Andric Value *Op = SI->getValueOperand();
1132*0fca6ea1SDimitry Andric Type *OpTy = Op->getType();
1133*0fca6ea1SDimitry Andric if (auto *OpI = dyn_cast<Instruction>(Op))
1134*0fca6ea1SDimitry Andric OpTy = restoreMutatedType(GR, OpI, OpTy);
1135*0fca6ea1SDimitry Andric if (OpTy == Op->getType())
1136*0fca6ea1SDimitry Andric OpTy = deduceElementTypeByValueDeep(OpTy, Op, false);
1137*0fca6ea1SDimitry Andric return replacePointerOperandWithPtrCast(I, SI->getPointerOperand(), OpTy, 1,
1138*0fca6ea1SDimitry Andric B);
1139*0fca6ea1SDimitry Andric } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
1140*0fca6ea1SDimitry Andric return replacePointerOperandWithPtrCast(I, LI->getPointerOperand(),
1141*0fca6ea1SDimitry Andric LI->getType(), 0, B);
1142*0fca6ea1SDimitry Andric } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
1143*0fca6ea1SDimitry Andric return replacePointerOperandWithPtrCast(I, GEPI->getPointerOperand(),
1144*0fca6ea1SDimitry Andric GEPI->getSourceElementType(), 0, B);
1145*0fca6ea1SDimitry Andric }
1146*0fca6ea1SDimitry Andric
1147*0fca6ea1SDimitry Andric // Handle calls to builtins (non-intrinsics):
1148*0fca6ea1SDimitry Andric CallInst *CI = dyn_cast<CallInst>(I);
1149*0fca6ea1SDimitry Andric if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||
1150*0fca6ea1SDimitry Andric !CI->getCalledFunction() || CI->getCalledFunction()->isIntrinsic())
11511db9f3b2SDimitry Andric return;
11521db9f3b2SDimitry Andric
1153*0fca6ea1SDimitry Andric // collect information about formal parameter types
1154*0fca6ea1SDimitry Andric std::string DemangledName =
1155*0fca6ea1SDimitry Andric getOclOrSpirvBuiltinDemangledName(CI->getCalledFunction()->getName());
1156*0fca6ea1SDimitry Andric Function *CalledF = CI->getCalledFunction();
1157*0fca6ea1SDimitry Andric SmallVector<Type *, 4> CalledArgTys;
1158*0fca6ea1SDimitry Andric bool HaveTypes = false;
1159*0fca6ea1SDimitry Andric for (unsigned OpIdx = 0; OpIdx < CalledF->arg_size(); ++OpIdx) {
1160*0fca6ea1SDimitry Andric Argument *CalledArg = CalledF->getArg(OpIdx);
1161*0fca6ea1SDimitry Andric Type *ArgType = CalledArg->getType();
1162*0fca6ea1SDimitry Andric if (!isPointerTy(ArgType)) {
1163*0fca6ea1SDimitry Andric CalledArgTys.push_back(nullptr);
1164*0fca6ea1SDimitry Andric } else if (isTypedPointerTy(ArgType)) {
1165*0fca6ea1SDimitry Andric CalledArgTys.push_back(cast<TypedPointerType>(ArgType)->getElementType());
1166*0fca6ea1SDimitry Andric HaveTypes = true;
11671db9f3b2SDimitry Andric } else {
1168*0fca6ea1SDimitry Andric Type *ElemTy = GR->findDeducedElementType(CalledArg);
1169*0fca6ea1SDimitry Andric if (!ElemTy && hasPointeeTypeAttr(CalledArg))
1170*0fca6ea1SDimitry Andric ElemTy = getPointeeTypeByAttr(CalledArg);
1171*0fca6ea1SDimitry Andric if (!ElemTy) {
1172*0fca6ea1SDimitry Andric ElemTy = getPointeeTypeByCallInst(DemangledName, CalledF, OpIdx);
1173*0fca6ea1SDimitry Andric if (ElemTy) {
1174*0fca6ea1SDimitry Andric GR->addDeducedElementType(CalledArg, ElemTy);
1175*0fca6ea1SDimitry Andric } else {
1176*0fca6ea1SDimitry Andric for (User *U : CalledArg->users()) {
1177*0fca6ea1SDimitry Andric if (Instruction *Inst = dyn_cast<Instruction>(U)) {
1178*0fca6ea1SDimitry Andric if ((ElemTy = deduceElementTypeHelper(Inst, false)) != nullptr)
1179*0fca6ea1SDimitry Andric break;
1180*0fca6ea1SDimitry Andric }
1181*0fca6ea1SDimitry Andric }
1182*0fca6ea1SDimitry Andric }
1183*0fca6ea1SDimitry Andric }
1184*0fca6ea1SDimitry Andric HaveTypes |= ElemTy != nullptr;
1185*0fca6ea1SDimitry Andric CalledArgTys.push_back(ElemTy);
1186*0fca6ea1SDimitry Andric }
1187*0fca6ea1SDimitry Andric }
1188*0fca6ea1SDimitry Andric
1189*0fca6ea1SDimitry Andric if (DemangledName.empty() && !HaveTypes)
11901db9f3b2SDimitry Andric return;
1191*0fca6ea1SDimitry Andric
1192*0fca6ea1SDimitry Andric for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) {
1193*0fca6ea1SDimitry Andric Value *ArgOperand = CI->getArgOperand(OpIdx);
1194*0fca6ea1SDimitry Andric if (!isPointerTy(ArgOperand->getType()))
1195*0fca6ea1SDimitry Andric continue;
1196*0fca6ea1SDimitry Andric
1197*0fca6ea1SDimitry Andric // Constants (nulls/undefs) are handled in insertAssignPtrTypeIntrs()
1198*0fca6ea1SDimitry Andric if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand)) {
1199*0fca6ea1SDimitry Andric // However, we may have assumptions about the formal argument's type and
1200*0fca6ea1SDimitry Andric // may have a need to insert a ptr cast for the actual parameter of this
1201*0fca6ea1SDimitry Andric // call.
1202*0fca6ea1SDimitry Andric Argument *CalledArg = CalledF->getArg(OpIdx);
1203*0fca6ea1SDimitry Andric if (!GR->findDeducedElementType(CalledArg))
1204*0fca6ea1SDimitry Andric continue;
1205*0fca6ea1SDimitry Andric }
1206*0fca6ea1SDimitry Andric
1207*0fca6ea1SDimitry Andric Type *ExpectedType =
1208*0fca6ea1SDimitry Andric OpIdx < CalledArgTys.size() ? CalledArgTys[OpIdx] : nullptr;
1209*0fca6ea1SDimitry Andric if (!ExpectedType && !DemangledName.empty())
1210*0fca6ea1SDimitry Andric ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
1211*0fca6ea1SDimitry Andric DemangledName, OpIdx, I->getContext());
1212*0fca6ea1SDimitry Andric if (!ExpectedType || ExpectedType->isVoidTy())
1213*0fca6ea1SDimitry Andric continue;
1214*0fca6ea1SDimitry Andric
1215*0fca6ea1SDimitry Andric if (ExpectedType->isTargetExtTy())
1216*0fca6ea1SDimitry Andric insertAssignPtrTypeTargetExt(cast<TargetExtType>(ExpectedType),
1217*0fca6ea1SDimitry Andric ArgOperand, B);
1218*0fca6ea1SDimitry Andric else
1219*0fca6ea1SDimitry Andric replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx, B);
12201db9f3b2SDimitry Andric }
12211db9f3b2SDimitry Andric }
12221db9f3b2SDimitry Andric
visitInsertElementInst(InsertElementInst & I)122381ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {
122481ad6265SDimitry Andric SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),
122581ad6265SDimitry Andric I.getOperand(1)->getType(),
122681ad6265SDimitry Andric I.getOperand(2)->getType()};
1227*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1228*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
122981ad6265SDimitry Andric SmallVector<Value *> Args(I.op_begin(), I.op_end());
1230*0fca6ea1SDimitry Andric auto *NewI = B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
123181ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : "";
123281ad6265SDimitry Andric I.replaceAllUsesWith(NewI);
123381ad6265SDimitry Andric I.eraseFromParent();
123481ad6265SDimitry Andric NewI->setName(InstName);
123581ad6265SDimitry Andric return NewI;
123681ad6265SDimitry Andric }
123781ad6265SDimitry Andric
123881ad6265SDimitry Andric Instruction *
visitExtractElementInst(ExtractElementInst & I)123981ad6265SDimitry Andric SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {
1240*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1241*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
124281ad6265SDimitry Andric SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(),
124381ad6265SDimitry Andric I.getIndexOperand()->getType()};
124481ad6265SDimitry Andric SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};
1245*0fca6ea1SDimitry Andric auto *NewI = B.CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});
124681ad6265SDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : "";
124781ad6265SDimitry Andric I.replaceAllUsesWith(NewI);
124881ad6265SDimitry Andric I.eraseFromParent();
124981ad6265SDimitry Andric NewI->setName(InstName);
125081ad6265SDimitry Andric return NewI;
125181ad6265SDimitry Andric }
125281ad6265SDimitry Andric
visitInsertValueInst(InsertValueInst & I)125381ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {
1254*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1255*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
125681ad6265SDimitry Andric SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()};
125781ad6265SDimitry Andric SmallVector<Value *> Args;
125881ad6265SDimitry Andric for (auto &Op : I.operands())
125981ad6265SDimitry Andric if (isa<UndefValue>(Op))
1260*0fca6ea1SDimitry Andric Args.push_back(UndefValue::get(B.getInt32Ty()));
126181ad6265SDimitry Andric else
126281ad6265SDimitry Andric Args.push_back(Op);
126381ad6265SDimitry Andric for (auto &Op : I.indices())
1264*0fca6ea1SDimitry Andric Args.push_back(B.getInt32(Op));
126581ad6265SDimitry Andric Instruction *NewI =
1266*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args});
1267*0fca6ea1SDimitry Andric replaceMemInstrUses(&I, NewI, B);
126881ad6265SDimitry Andric return NewI;
126981ad6265SDimitry Andric }
127081ad6265SDimitry Andric
visitExtractValueInst(ExtractValueInst & I)127181ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
1272*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1273*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
127481ad6265SDimitry Andric SmallVector<Value *> Args;
127581ad6265SDimitry Andric for (auto &Op : I.operands())
127681ad6265SDimitry Andric Args.push_back(Op);
127781ad6265SDimitry Andric for (auto &Op : I.indices())
1278*0fca6ea1SDimitry Andric Args.push_back(B.getInt32(Op));
127981ad6265SDimitry Andric auto *NewI =
1280*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});
128181ad6265SDimitry Andric I.replaceAllUsesWith(NewI);
128281ad6265SDimitry Andric I.eraseFromParent();
128381ad6265SDimitry Andric return NewI;
128481ad6265SDimitry Andric }
128581ad6265SDimitry Andric
visitLoadInst(LoadInst & I)128681ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) {
128781ad6265SDimitry Andric if (!I.getType()->isAggregateType())
128881ad6265SDimitry Andric return &I;
1289*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1290*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
129181ad6265SDimitry Andric TrackConstants = false;
129281ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
129381ad6265SDimitry Andric MachineMemOperand::Flags Flags =
1294*0fca6ea1SDimitry Andric TLI->getLoadMemOperandFlags(I, F->getDataLayout());
129581ad6265SDimitry Andric auto *NewI =
1296*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()},
1297*0fca6ea1SDimitry Andric {I.getPointerOperand(), B.getInt16(Flags),
1298*0fca6ea1SDimitry Andric B.getInt8(I.getAlign().value())});
1299*0fca6ea1SDimitry Andric replaceMemInstrUses(&I, NewI, B);
130081ad6265SDimitry Andric return NewI;
130181ad6265SDimitry Andric }
130281ad6265SDimitry Andric
visitStoreInst(StoreInst & I)130381ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {
130481ad6265SDimitry Andric if (!AggrStores.contains(&I))
130581ad6265SDimitry Andric return &I;
1306*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1307*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
130881ad6265SDimitry Andric TrackConstants = false;
130981ad6265SDimitry Andric const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
131081ad6265SDimitry Andric MachineMemOperand::Flags Flags =
1311*0fca6ea1SDimitry Andric TLI->getStoreMemOperandFlags(I, F->getDataLayout());
131281ad6265SDimitry Andric auto *PtrOp = I.getPointerOperand();
1313*0fca6ea1SDimitry Andric auto *NewI = B.CreateIntrinsic(
1314fcaf7f86SDimitry Andric Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()},
1315*0fca6ea1SDimitry Andric {I.getValueOperand(), PtrOp, B.getInt16(Flags),
1316*0fca6ea1SDimitry Andric B.getInt8(I.getAlign().value())});
131781ad6265SDimitry Andric I.eraseFromParent();
131881ad6265SDimitry Andric return NewI;
131981ad6265SDimitry Andric }
132081ad6265SDimitry Andric
visitAllocaInst(AllocaInst & I)132181ad6265SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {
1322*0fca6ea1SDimitry Andric Value *ArraySize = nullptr;
1323*0fca6ea1SDimitry Andric if (I.isArrayAllocation()) {
1324*0fca6ea1SDimitry Andric const SPIRVSubtarget *STI = TM->getSubtargetImpl(*I.getFunction());
1325*0fca6ea1SDimitry Andric if (!STI->canUseExtension(
1326*0fca6ea1SDimitry Andric SPIRV::Extension::SPV_INTEL_variable_length_array))
1327*0fca6ea1SDimitry Andric report_fatal_error(
1328*0fca6ea1SDimitry Andric "array allocation: this instruction requires the following "
1329*0fca6ea1SDimitry Andric "SPIR-V extension: SPV_INTEL_variable_length_array",
1330*0fca6ea1SDimitry Andric false);
1331*0fca6ea1SDimitry Andric ArraySize = I.getArraySize();
1332*0fca6ea1SDimitry Andric }
1333*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1334*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
133581ad6265SDimitry Andric TrackConstants = false;
1336bdd1243dSDimitry Andric Type *PtrTy = I.getType();
1337*0fca6ea1SDimitry Andric auto *NewI =
1338*0fca6ea1SDimitry Andric ArraySize ? B.CreateIntrinsic(Intrinsic::spv_alloca_array,
1339*0fca6ea1SDimitry Andric {PtrTy, ArraySize->getType()}, {ArraySize})
1340*0fca6ea1SDimitry Andric : B.CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {});
1341bdd1243dSDimitry Andric std::string InstName = I.hasName() ? I.getName().str() : "";
1342bdd1243dSDimitry Andric I.replaceAllUsesWith(NewI);
1343bdd1243dSDimitry Andric I.eraseFromParent();
1344bdd1243dSDimitry Andric NewI->setName(InstName);
1345bdd1243dSDimitry Andric return NewI;
134681ad6265SDimitry Andric }
134781ad6265SDimitry Andric
visitAtomicCmpXchgInst(AtomicCmpXchgInst & I)1348fcaf7f86SDimitry Andric Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
1349fcaf7f86SDimitry Andric assert(I.getType()->isAggregateType() && "Aggregate result is expected");
1350*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1351*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
1352fcaf7f86SDimitry Andric SmallVector<Value *> Args;
1353fcaf7f86SDimitry Andric for (auto &Op : I.operands())
1354fcaf7f86SDimitry Andric Args.push_back(Op);
1355*0fca6ea1SDimitry Andric Args.push_back(B.getInt32(I.getSyncScopeID()));
1356*0fca6ea1SDimitry Andric Args.push_back(B.getInt32(
1357fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering()))));
1358*0fca6ea1SDimitry Andric Args.push_back(B.getInt32(
1359fcaf7f86SDimitry Andric static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering()))));
1360*0fca6ea1SDimitry Andric auto *NewI = B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
1361fcaf7f86SDimitry Andric {I.getPointerOperand()->getType()}, {Args});
1362*0fca6ea1SDimitry Andric replaceMemInstrUses(&I, NewI, B);
1363fcaf7f86SDimitry Andric return NewI;
1364fcaf7f86SDimitry Andric }
1365fcaf7f86SDimitry Andric
visitUnreachableInst(UnreachableInst & I)1366bdd1243dSDimitry Andric Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) {
1367*0fca6ea1SDimitry Andric IRBuilder<> B(I.getParent());
1368*0fca6ea1SDimitry Andric B.SetInsertPoint(&I);
1369*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_unreachable, {}, {});
1370bdd1243dSDimitry Andric return &I;
1371bdd1243dSDimitry Andric }
1372bdd1243dSDimitry Andric
processGlobalValue(GlobalVariable & GV,IRBuilder<> & B)1373*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
1374*0fca6ea1SDimitry Andric IRBuilder<> &B) {
137581ad6265SDimitry Andric // Skip special artifical variable llvm.global.annotations.
137681ad6265SDimitry Andric if (GV.getName() == "llvm.global.annotations")
137781ad6265SDimitry Andric return;
137881ad6265SDimitry Andric if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) {
1379*0fca6ea1SDimitry Andric // Deduce element type and store results in Global Registry.
1380*0fca6ea1SDimitry Andric // Result is ignored, because TypedPointerType is not supported
1381*0fca6ea1SDimitry Andric // by llvm IR general logic.
1382*0fca6ea1SDimitry Andric deduceElementTypeHelper(&GV, false);
138381ad6265SDimitry Andric Constant *Init = GV.getInitializer();
1384*0fca6ea1SDimitry Andric Type *Ty = isAggrConstForceInt32(Init) ? B.getInt32Ty() : Init->getType();
1385*0fca6ea1SDimitry Andric Constant *Const = isAggrConstForceInt32(Init) ? B.getInt32(1) : Init;
1386*0fca6ea1SDimitry Andric auto *InitInst = B.CreateIntrinsic(Intrinsic::spv_init_global,
138781ad6265SDimitry Andric {GV.getType(), Ty}, {&GV, Const});
138881ad6265SDimitry Andric InitInst->setArgOperand(1, Init);
138981ad6265SDimitry Andric }
139081ad6265SDimitry Andric if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) &&
139181ad6265SDimitry Andric GV.getNumUses() == 0)
1392*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);
139381ad6265SDimitry Andric }
139481ad6265SDimitry Andric
1395*0fca6ea1SDimitry Andric // Return true, if we can't decide what is the pointee type now and will get
1396*0fca6ea1SDimitry Andric // back to the question later. Return false is spv_assign_ptr_type is not needed
1397*0fca6ea1SDimitry Andric // or can be inserted immediately.
insertAssignPtrTypeIntrs(Instruction * I,IRBuilder<> & B,bool UnknownElemTypeI8)1398*0fca6ea1SDimitry Andric bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
1399*0fca6ea1SDimitry Andric IRBuilder<> &B,
1400*0fca6ea1SDimitry Andric bool UnknownElemTypeI8) {
1401*0fca6ea1SDimitry Andric reportFatalOnTokenType(I);
1402*0fca6ea1SDimitry Andric if (!isPointerTy(I->getType()) || !requireAssignType(I) ||
1403*0fca6ea1SDimitry Andric isa<BitCastInst>(I))
1404*0fca6ea1SDimitry Andric return false;
14055f757f3fSDimitry Andric
1406*0fca6ea1SDimitry Andric setInsertPointAfterDef(B, I);
1407*0fca6ea1SDimitry Andric if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {
1408*0fca6ea1SDimitry Andric buildAssignPtr(B, ElemTy, I);
1409*0fca6ea1SDimitry Andric return false;
1410*0fca6ea1SDimitry Andric }
1411*0fca6ea1SDimitry Andric return true;
14125f757f3fSDimitry Andric }
14135f757f3fSDimitry Andric
insertAssignTypeIntrs(Instruction * I,IRBuilder<> & B)1414*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
1415*0fca6ea1SDimitry Andric IRBuilder<> &B) {
1416*0fca6ea1SDimitry Andric // TODO: extend the list of functions with known result types
1417*0fca6ea1SDimitry Andric static StringMap<unsigned> ResTypeWellKnown = {
1418*0fca6ea1SDimitry Andric {"async_work_group_copy", WellKnownTypes::Event},
1419*0fca6ea1SDimitry Andric {"async_work_group_strided_copy", WellKnownTypes::Event},
1420*0fca6ea1SDimitry Andric {"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
1421*0fca6ea1SDimitry Andric
1422*0fca6ea1SDimitry Andric reportFatalOnTokenType(I);
1423*0fca6ea1SDimitry Andric
1424*0fca6ea1SDimitry Andric bool IsKnown = false;
1425*0fca6ea1SDimitry Andric if (auto *CI = dyn_cast<CallInst>(I)) {
1426*0fca6ea1SDimitry Andric if (!CI->isIndirectCall() && !CI->isInlineAsm() &&
1427*0fca6ea1SDimitry Andric CI->getCalledFunction() && !CI->getCalledFunction()->isIntrinsic()) {
1428*0fca6ea1SDimitry Andric Function *CalledF = CI->getCalledFunction();
1429*0fca6ea1SDimitry Andric std::string DemangledName =
1430*0fca6ea1SDimitry Andric getOclOrSpirvBuiltinDemangledName(CalledF->getName());
1431*0fca6ea1SDimitry Andric if (DemangledName.length() > 0)
1432*0fca6ea1SDimitry Andric DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1433*0fca6ea1SDimitry Andric auto ResIt = ResTypeWellKnown.find(DemangledName);
1434*0fca6ea1SDimitry Andric if (ResIt != ResTypeWellKnown.end()) {
1435*0fca6ea1SDimitry Andric IsKnown = true;
1436*0fca6ea1SDimitry Andric setInsertPointAfterDef(B, I);
1437*0fca6ea1SDimitry Andric switch (ResIt->second) {
1438*0fca6ea1SDimitry Andric case WellKnownTypes::Event:
1439*0fca6ea1SDimitry Andric buildAssignType(B, TargetExtType::get(I->getContext(), "spirv.Event"),
1440*0fca6ea1SDimitry Andric I);
1441*0fca6ea1SDimitry Andric break;
1442*0fca6ea1SDimitry Andric }
1443*0fca6ea1SDimitry Andric }
1444*0fca6ea1SDimitry Andric }
14455f757f3fSDimitry Andric }
14465f757f3fSDimitry Andric
144781ad6265SDimitry Andric Type *Ty = I->getType();
1448*0fca6ea1SDimitry Andric if (!IsKnown && !Ty->isVoidTy() && !isPointerTy(Ty) && requireAssignType(I)) {
1449*0fca6ea1SDimitry Andric setInsertPointAfterDef(B, I);
145081ad6265SDimitry Andric Type *TypeToAssign = Ty;
145181ad6265SDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(I)) {
145206c3fb27SDimitry Andric if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
145306c3fb27SDimitry Andric II->getIntrinsicID() == Intrinsic::spv_undef) {
1454*0fca6ea1SDimitry Andric auto It = AggrConstTypes.find(II);
1455*0fca6ea1SDimitry Andric if (It == AggrConstTypes.end())
1456*0fca6ea1SDimitry Andric report_fatal_error("Unknown composite intrinsic type");
1457*0fca6ea1SDimitry Andric TypeToAssign = It->second;
145881ad6265SDimitry Andric }
145981ad6265SDimitry Andric }
1460*0fca6ea1SDimitry Andric TypeToAssign = restoreMutatedType(GR, I, TypeToAssign);
1461*0fca6ea1SDimitry Andric buildAssignType(B, TypeToAssign, I);
146281ad6265SDimitry Andric }
146381ad6265SDimitry Andric for (const auto &Op : I->operands()) {
146481ad6265SDimitry Andric if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
146581ad6265SDimitry Andric // Check GetElementPtrConstantExpr case.
146681ad6265SDimitry Andric (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) {
1467*0fca6ea1SDimitry Andric setInsertPointSkippingPhis(B, I);
1468*0fca6ea1SDimitry Andric Type *OpTy = Op->getType();
1469*0fca6ea1SDimitry Andric if (isa<UndefValue>(Op) && OpTy->isAggregateType()) {
1470*0fca6ea1SDimitry Andric CallInst *AssignCI =
1471*0fca6ea1SDimitry Andric buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,
1472*0fca6ea1SDimitry Andric UndefValue::get(B.getInt32Ty()), {}, B);
1473*0fca6ea1SDimitry Andric GR->addAssignPtrTypeInstr(Op, AssignCI);
1474*0fca6ea1SDimitry Andric } else if (!isa<Instruction>(Op)) {
1475*0fca6ea1SDimitry Andric Type *OpTy = Op->getType();
1476*0fca6ea1SDimitry Andric if (auto PType = dyn_cast<TypedPointerType>(OpTy)) {
1477*0fca6ea1SDimitry Andric buildAssignPtr(B, PType->getElementType(), Op);
1478*0fca6ea1SDimitry Andric } else if (isPointerTy(OpTy)) {
1479*0fca6ea1SDimitry Andric Type *ElemTy = GR->findDeducedElementType(Op);
1480*0fca6ea1SDimitry Andric buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true), Op);
1481*0fca6ea1SDimitry Andric } else {
1482*0fca6ea1SDimitry Andric CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,
1483*0fca6ea1SDimitry Andric {OpTy}, Op, Op, {}, B);
1484*0fca6ea1SDimitry Andric GR->addAssignPtrTypeInstr(Op, AssignCI);
1485*0fca6ea1SDimitry Andric }
1486*0fca6ea1SDimitry Andric }
148781ad6265SDimitry Andric }
148881ad6265SDimitry Andric }
148981ad6265SDimitry Andric }
149081ad6265SDimitry Andric
insertSpirvDecorations(Instruction * I,IRBuilder<> & B)1491*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
1492*0fca6ea1SDimitry Andric IRBuilder<> &B) {
1493*0fca6ea1SDimitry Andric if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
1494*0fca6ea1SDimitry Andric setInsertPointAfterDef(B, I);
1495*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
1496*0fca6ea1SDimitry Andric {I, MetadataAsValue::get(I->getContext(), MD)});
1497*0fca6ea1SDimitry Andric }
1498*0fca6ea1SDimitry Andric }
1499*0fca6ea1SDimitry Andric
processInstrAfterVisit(Instruction * I,IRBuilder<> & B)1500*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
1501*0fca6ea1SDimitry Andric IRBuilder<> &B) {
150281ad6265SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(I);
150381ad6265SDimitry Andric if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
150481ad6265SDimitry Andric TrackConstants) {
1505*0fca6ea1SDimitry Andric setInsertPointAfterDef(B, I);
150681ad6265SDimitry Andric auto t = AggrConsts.find(I);
150781ad6265SDimitry Andric assert(t != AggrConsts.end());
1508*0fca6ea1SDimitry Andric auto *NewOp =
1509*0fca6ea1SDimitry Andric buildIntrWithMD(Intrinsic::spv_track_constant,
1510*0fca6ea1SDimitry Andric {II->getType(), II->getType()}, t->second, I, {}, B);
151181ad6265SDimitry Andric I->replaceAllUsesWith(NewOp);
151281ad6265SDimitry Andric NewOp->setArgOperand(0, I);
151381ad6265SDimitry Andric }
1514*0fca6ea1SDimitry Andric bool IsPhi = isa<PHINode>(I), BPrepared = false;
151581ad6265SDimitry Andric for (const auto &Op : I->operands()) {
1516*0fca6ea1SDimitry Andric if (isa<PHINode>(I) || isa<SwitchInst>(I))
151781ad6265SDimitry Andric TrackConstants = false;
1518fcaf7f86SDimitry Andric if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) {
151981ad6265SDimitry Andric unsigned OpNo = Op.getOperandNo();
152081ad6265SDimitry Andric if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
152181ad6265SDimitry Andric (II->paramHasAttr(OpNo, Attribute::ImmArg))))
152281ad6265SDimitry Andric continue;
1523*0fca6ea1SDimitry Andric if (!BPrepared) {
1524*0fca6ea1SDimitry Andric IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
1525*0fca6ea1SDimitry Andric : B.SetInsertPoint(I);
1526*0fca6ea1SDimitry Andric BPrepared = true;
1527*0fca6ea1SDimitry Andric }
1528*0fca6ea1SDimitry Andric Value *OpTyVal = Op;
1529*0fca6ea1SDimitry Andric if (Op->getType()->isTargetExtTy())
1530*0fca6ea1SDimitry Andric OpTyVal = PoisonValue::get(Op->getType());
153181ad6265SDimitry Andric auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
1532*0fca6ea1SDimitry Andric {Op->getType(), OpTyVal->getType()}, Op,
1533*0fca6ea1SDimitry Andric OpTyVal, {}, B);
153481ad6265SDimitry Andric I->setOperand(OpNo, NewOp);
153581ad6265SDimitry Andric }
153681ad6265SDimitry Andric }
153781ad6265SDimitry Andric if (I->hasName()) {
1538*0fca6ea1SDimitry Andric reportFatalOnTokenType(I);
1539*0fca6ea1SDimitry Andric setInsertPointAfterDef(B, I);
154081ad6265SDimitry Andric std::vector<Value *> Args = {I};
1541*0fca6ea1SDimitry Andric addStringImm(I->getName(), B, Args);
1542*0fca6ea1SDimitry Andric B.CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);
1543*0fca6ea1SDimitry Andric }
1544*0fca6ea1SDimitry Andric }
1545*0fca6ea1SDimitry Andric
deduceFunParamElementType(Function * F,unsigned OpIdx)1546*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F,
1547*0fca6ea1SDimitry Andric unsigned OpIdx) {
1548*0fca6ea1SDimitry Andric std::unordered_set<Function *> FVisited;
1549*0fca6ea1SDimitry Andric return deduceFunParamElementType(F, OpIdx, FVisited);
1550*0fca6ea1SDimitry Andric }
1551*0fca6ea1SDimitry Andric
deduceFunParamElementType(Function * F,unsigned OpIdx,std::unordered_set<Function * > & FVisited)1552*0fca6ea1SDimitry Andric Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
1553*0fca6ea1SDimitry Andric Function *F, unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
1554*0fca6ea1SDimitry Andric // maybe a cycle
1555*0fca6ea1SDimitry Andric if (FVisited.find(F) != FVisited.end())
1556*0fca6ea1SDimitry Andric return nullptr;
1557*0fca6ea1SDimitry Andric FVisited.insert(F);
1558*0fca6ea1SDimitry Andric
1559*0fca6ea1SDimitry Andric std::unordered_set<Value *> Visited;
1560*0fca6ea1SDimitry Andric SmallVector<std::pair<Function *, unsigned>> Lookup;
1561*0fca6ea1SDimitry Andric // search in function's call sites
1562*0fca6ea1SDimitry Andric for (User *U : F->users()) {
1563*0fca6ea1SDimitry Andric CallInst *CI = dyn_cast<CallInst>(U);
1564*0fca6ea1SDimitry Andric if (!CI || OpIdx >= CI->arg_size())
1565*0fca6ea1SDimitry Andric continue;
1566*0fca6ea1SDimitry Andric Value *OpArg = CI->getArgOperand(OpIdx);
1567*0fca6ea1SDimitry Andric if (!isPointerTy(OpArg->getType()))
1568*0fca6ea1SDimitry Andric continue;
1569*0fca6ea1SDimitry Andric // maybe we already know operand's element type
1570*0fca6ea1SDimitry Andric if (Type *KnownTy = GR->findDeducedElementType(OpArg))
1571*0fca6ea1SDimitry Andric return KnownTy;
1572*0fca6ea1SDimitry Andric // try to deduce from the operand itself
1573*0fca6ea1SDimitry Andric Visited.clear();
1574*0fca6ea1SDimitry Andric if (Type *Ty = deduceElementTypeHelper(OpArg, Visited, false))
1575*0fca6ea1SDimitry Andric return Ty;
1576*0fca6ea1SDimitry Andric // search in actual parameter's users
1577*0fca6ea1SDimitry Andric for (User *OpU : OpArg->users()) {
1578*0fca6ea1SDimitry Andric Instruction *Inst = dyn_cast<Instruction>(OpU);
1579*0fca6ea1SDimitry Andric if (!Inst || Inst == CI)
1580*0fca6ea1SDimitry Andric continue;
1581*0fca6ea1SDimitry Andric Visited.clear();
1582*0fca6ea1SDimitry Andric if (Type *Ty = deduceElementTypeHelper(Inst, Visited, false))
1583*0fca6ea1SDimitry Andric return Ty;
1584*0fca6ea1SDimitry Andric }
1585*0fca6ea1SDimitry Andric // check if it's a formal parameter of the outer function
1586*0fca6ea1SDimitry Andric if (!CI->getParent() || !CI->getParent()->getParent())
1587*0fca6ea1SDimitry Andric continue;
1588*0fca6ea1SDimitry Andric Function *OuterF = CI->getParent()->getParent();
1589*0fca6ea1SDimitry Andric if (FVisited.find(OuterF) != FVisited.end())
1590*0fca6ea1SDimitry Andric continue;
1591*0fca6ea1SDimitry Andric for (unsigned i = 0; i < OuterF->arg_size(); ++i) {
1592*0fca6ea1SDimitry Andric if (OuterF->getArg(i) == OpArg) {
1593*0fca6ea1SDimitry Andric Lookup.push_back(std::make_pair(OuterF, i));
1594*0fca6ea1SDimitry Andric break;
1595*0fca6ea1SDimitry Andric }
1596*0fca6ea1SDimitry Andric }
1597*0fca6ea1SDimitry Andric }
1598*0fca6ea1SDimitry Andric
1599*0fca6ea1SDimitry Andric // search in function parameters
1600*0fca6ea1SDimitry Andric for (auto &Pair : Lookup) {
1601*0fca6ea1SDimitry Andric if (Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
1602*0fca6ea1SDimitry Andric return Ty;
1603*0fca6ea1SDimitry Andric }
1604*0fca6ea1SDimitry Andric
1605*0fca6ea1SDimitry Andric return nullptr;
1606*0fca6ea1SDimitry Andric }
1607*0fca6ea1SDimitry Andric
processParamTypesByFunHeader(Function * F,IRBuilder<> & B)1608*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
1609*0fca6ea1SDimitry Andric IRBuilder<> &B) {
1610*0fca6ea1SDimitry Andric B.SetInsertPointPastAllocas(F);
1611*0fca6ea1SDimitry Andric for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
1612*0fca6ea1SDimitry Andric Argument *Arg = F->getArg(OpIdx);
1613*0fca6ea1SDimitry Andric if (!isUntypedPointerTy(Arg->getType()))
1614*0fca6ea1SDimitry Andric continue;
1615*0fca6ea1SDimitry Andric Type *ElemTy = GR->findDeducedElementType(Arg);
1616*0fca6ea1SDimitry Andric if (!ElemTy && hasPointeeTypeAttr(Arg) &&
1617*0fca6ea1SDimitry Andric (ElemTy = getPointeeTypeByAttr(Arg)) != nullptr)
1618*0fca6ea1SDimitry Andric buildAssignPtr(B, ElemTy, Arg);
1619*0fca6ea1SDimitry Andric }
1620*0fca6ea1SDimitry Andric }
1621*0fca6ea1SDimitry Andric
processParamTypes(Function * F,IRBuilder<> & B)1622*0fca6ea1SDimitry Andric void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
1623*0fca6ea1SDimitry Andric B.SetInsertPointPastAllocas(F);
1624*0fca6ea1SDimitry Andric for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
1625*0fca6ea1SDimitry Andric Argument *Arg = F->getArg(OpIdx);
1626*0fca6ea1SDimitry Andric if (!isUntypedPointerTy(Arg->getType()))
1627*0fca6ea1SDimitry Andric continue;
1628*0fca6ea1SDimitry Andric Type *ElemTy = GR->findDeducedElementType(Arg);
1629*0fca6ea1SDimitry Andric if (!ElemTy && (ElemTy = deduceFunParamElementType(F, OpIdx)) != nullptr)
1630*0fca6ea1SDimitry Andric buildAssignPtr(B, ElemTy, Arg);
163181ad6265SDimitry Andric }
163281ad6265SDimitry Andric }
163381ad6265SDimitry Andric
runOnFunction(Function & Func)163481ad6265SDimitry Andric bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
163581ad6265SDimitry Andric if (Func.isDeclaration())
163681ad6265SDimitry Andric return false;
1637*0fca6ea1SDimitry Andric
1638*0fca6ea1SDimitry Andric const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(Func);
1639*0fca6ea1SDimitry Andric GR = ST.getSPIRVGlobalRegistry();
1640*0fca6ea1SDimitry Andric InstrSet = ST.isOpenCLEnv() ? SPIRV::InstructionSet::OpenCL_std
1641*0fca6ea1SDimitry Andric : SPIRV::InstructionSet::GLSL_std_450;
1642*0fca6ea1SDimitry Andric
164381ad6265SDimitry Andric F = &Func;
1644*0fca6ea1SDimitry Andric IRBuilder<> B(Func.getContext());
164581ad6265SDimitry Andric AggrConsts.clear();
1646*0fca6ea1SDimitry Andric AggrConstTypes.clear();
164781ad6265SDimitry Andric AggrStores.clear();
164881ad6265SDimitry Andric
1649*0fca6ea1SDimitry Andric processParamTypesByFunHeader(F, B);
1650*0fca6ea1SDimitry Andric
1651fcaf7f86SDimitry Andric // StoreInst's operand type can be changed during the next transformations,
1652fcaf7f86SDimitry Andric // so we need to store it in the set. Also store already transformed types.
1653fcaf7f86SDimitry Andric for (auto &I : instructions(Func)) {
1654fcaf7f86SDimitry Andric StoreInst *SI = dyn_cast<StoreInst>(&I);
1655fcaf7f86SDimitry Andric if (!SI)
1656fcaf7f86SDimitry Andric continue;
1657fcaf7f86SDimitry Andric Type *ElTy = SI->getValueOperand()->getType();
16585f757f3fSDimitry Andric if (ElTy->isAggregateType() || ElTy->isVectorTy())
1659fcaf7f86SDimitry Andric AggrStores.insert(&I);
1660fcaf7f86SDimitry Andric }
166181ad6265SDimitry Andric
1662*0fca6ea1SDimitry Andric B.SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin());
166381ad6265SDimitry Andric for (auto &GV : Func.getParent()->globals())
1664*0fca6ea1SDimitry Andric processGlobalValue(GV, B);
166581ad6265SDimitry Andric
1666*0fca6ea1SDimitry Andric preprocessUndefs(B);
1667*0fca6ea1SDimitry Andric preprocessCompositeConstants(B);
166881ad6265SDimitry Andric SmallVector<Instruction *> Worklist;
166981ad6265SDimitry Andric for (auto &I : instructions(Func))
167081ad6265SDimitry Andric Worklist.push_back(&I);
167181ad6265SDimitry Andric
16725f757f3fSDimitry Andric for (auto &I : Worklist) {
1673*0fca6ea1SDimitry Andric // Don't emit intrinsincs for convergence intrinsics.
1674*0fca6ea1SDimitry Andric if (isConvergenceIntrinsic(I))
1675*0fca6ea1SDimitry Andric continue;
1676*0fca6ea1SDimitry Andric
1677*0fca6ea1SDimitry Andric bool Postpone = insertAssignPtrTypeIntrs(I, B, false);
1678*0fca6ea1SDimitry Andric // if Postpone is true, we can't decide on pointee type yet
1679*0fca6ea1SDimitry Andric insertAssignTypeIntrs(I, B);
1680*0fca6ea1SDimitry Andric insertPtrCastOrAssignTypeInstr(I, B);
1681*0fca6ea1SDimitry Andric insertSpirvDecorations(I, B);
1682*0fca6ea1SDimitry Andric // if instruction requires a pointee type set, let's check if we know it
1683*0fca6ea1SDimitry Andric // already, and force it to be i8 if not
1684*0fca6ea1SDimitry Andric if (Postpone && !GR->findAssignPtrTypeInstr(I))
1685*0fca6ea1SDimitry Andric insertAssignPtrTypeIntrs(I, B, true);
16865f757f3fSDimitry Andric }
168781ad6265SDimitry Andric
1688*0fca6ea1SDimitry Andric for (auto &I : instructions(Func))
1689*0fca6ea1SDimitry Andric deduceOperandElementType(&I);
1690*0fca6ea1SDimitry Andric
169181ad6265SDimitry Andric for (auto *I : Worklist) {
169281ad6265SDimitry Andric TrackConstants = true;
169381ad6265SDimitry Andric if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
1694*0fca6ea1SDimitry Andric setInsertPointAfterDef(B, I);
16951db9f3b2SDimitry Andric // Visitors return either the original/newly created instruction for further
16961db9f3b2SDimitry Andric // processing, nullptr otherwise.
169781ad6265SDimitry Andric I = visit(*I);
16981db9f3b2SDimitry Andric if (!I)
16991db9f3b2SDimitry Andric continue;
1700*0fca6ea1SDimitry Andric
1701*0fca6ea1SDimitry Andric // Don't emit intrinsics for convergence operations.
1702*0fca6ea1SDimitry Andric if (isConvergenceIntrinsic(I))
1703*0fca6ea1SDimitry Andric continue;
1704*0fca6ea1SDimitry Andric
1705*0fca6ea1SDimitry Andric processInstrAfterVisit(I, B);
170681ad6265SDimitry Andric }
1707*0fca6ea1SDimitry Andric
170881ad6265SDimitry Andric return true;
170981ad6265SDimitry Andric }
171081ad6265SDimitry Andric
1711*0fca6ea1SDimitry Andric // Try to deduce a better type for pointers to untyped ptr.
postprocessTypes()1712*0fca6ea1SDimitry Andric bool SPIRVEmitIntrinsics::postprocessTypes() {
1713*0fca6ea1SDimitry Andric bool Changed = false;
1714*0fca6ea1SDimitry Andric if (!GR)
1715*0fca6ea1SDimitry Andric return Changed;
1716*0fca6ea1SDimitry Andric for (auto IB = PostprocessWorklist.rbegin(), IE = PostprocessWorklist.rend();
1717*0fca6ea1SDimitry Andric IB != IE; ++IB) {
1718*0fca6ea1SDimitry Andric CallInst *AssignCI = GR->findAssignPtrTypeInstr(*IB);
1719*0fca6ea1SDimitry Andric Type *KnownTy = GR->findDeducedElementType(*IB);
1720*0fca6ea1SDimitry Andric if (!KnownTy || !AssignCI || !isa<Instruction>(AssignCI->getArgOperand(0)))
1721*0fca6ea1SDimitry Andric continue;
1722*0fca6ea1SDimitry Andric Instruction *I = cast<Instruction>(AssignCI->getArgOperand(0));
1723*0fca6ea1SDimitry Andric for (User *U : I->users()) {
1724*0fca6ea1SDimitry Andric Instruction *Inst = dyn_cast<Instruction>(U);
1725*0fca6ea1SDimitry Andric if (!Inst || isa<IntrinsicInst>(Inst))
1726*0fca6ea1SDimitry Andric continue;
1727*0fca6ea1SDimitry Andric deduceOperandElementType(Inst, I, KnownTy, AssignCI);
1728*0fca6ea1SDimitry Andric if (KnownTy != GR->findDeducedElementType(I)) {
1729*0fca6ea1SDimitry Andric Changed = true;
1730*0fca6ea1SDimitry Andric break;
1731*0fca6ea1SDimitry Andric }
1732*0fca6ea1SDimitry Andric }
1733*0fca6ea1SDimitry Andric }
1734*0fca6ea1SDimitry Andric return Changed;
1735*0fca6ea1SDimitry Andric }
1736*0fca6ea1SDimitry Andric
runOnModule(Module & M)1737*0fca6ea1SDimitry Andric bool SPIRVEmitIntrinsics::runOnModule(Module &M) {
1738*0fca6ea1SDimitry Andric bool Changed = false;
1739*0fca6ea1SDimitry Andric
1740*0fca6ea1SDimitry Andric UncompleteTypeInfo.clear();
1741*0fca6ea1SDimitry Andric PostprocessWorklist.clear();
1742*0fca6ea1SDimitry Andric for (auto &F : M)
1743*0fca6ea1SDimitry Andric Changed |= runOnFunction(F);
1744*0fca6ea1SDimitry Andric
1745*0fca6ea1SDimitry Andric for (auto &F : M) {
1746*0fca6ea1SDimitry Andric // check if function parameter types are set
1747*0fca6ea1SDimitry Andric if (!F.isDeclaration() && !F.isIntrinsic()) {
1748*0fca6ea1SDimitry Andric const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(F);
1749*0fca6ea1SDimitry Andric GR = ST.getSPIRVGlobalRegistry();
1750*0fca6ea1SDimitry Andric IRBuilder<> B(F.getContext());
1751*0fca6ea1SDimitry Andric processParamTypes(&F, B);
1752*0fca6ea1SDimitry Andric }
1753*0fca6ea1SDimitry Andric }
1754*0fca6ea1SDimitry Andric
1755*0fca6ea1SDimitry Andric Changed |= postprocessTypes();
1756*0fca6ea1SDimitry Andric
1757*0fca6ea1SDimitry Andric return Changed;
1758*0fca6ea1SDimitry Andric }
1759*0fca6ea1SDimitry Andric
createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine * TM)1760*0fca6ea1SDimitry Andric ModulePass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) {
176181ad6265SDimitry Andric return new SPIRVEmitIntrinsics(TM);
176281ad6265SDimitry Andric }
1763