Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
35266 views
//===-- SPIRVEmitIntrinsics.cpp - emit SPIRV intrinsics ---------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// The pass emits SPIRV intrinsics keeping essential high-level information for9// the translation of LLVM IR to SPIR-V.10//11//===----------------------------------------------------------------------===//1213#include "SPIRV.h"14#include "SPIRVBuiltins.h"15#include "SPIRVMetadata.h"16#include "SPIRVSubtarget.h"17#include "SPIRVTargetMachine.h"18#include "SPIRVUtils.h"19#include "llvm/IR/IRBuilder.h"20#include "llvm/IR/InstIterator.h"21#include "llvm/IR/InstVisitor.h"22#include "llvm/IR/IntrinsicsSPIRV.h"23#include "llvm/IR/TypedPointerType.h"2425#include <queue>2627// This pass performs the following transformation on LLVM IR level required28// for the following translation to SPIR-V:29// - replaces direct usages of aggregate constants with target-specific30// intrinsics;31// - replaces aggregates-related instructions (extract/insert, ld/st, etc)32// with a target-specific intrinsics;33// - emits intrinsics for the global variable initializers since IRTranslator34// doesn't handle them and it's not very convenient to translate them35// ourselves;36// - emits intrinsics to keep track of the string names assigned to the values;37// - emits intrinsics to keep track of constants (this is necessary to have an38// LLVM IR constant after the IRTranslation is completed) for their further39// deduplication;40// - emits intrinsics to keep track of original LLVM types of the values41// to be able to emit proper SPIR-V types eventually.42//43// TODO: consider removing spv.track.constant in favor of spv.assign.type.4445using namespace llvm;4647namespace llvm {48namespace SPIRV {49#define GET_BuiltinGroup_DECL50#include "SPIRVGenTables.inc"51} // namespace SPIRV52void initializeSPIRVEmitIntrinsicsPass(PassRegistry &);53} // namespace llvm5455namespace {5657inline MetadataAsValue *buildMD(Value *Arg) {58LLVMContext &Ctx = Arg->getContext();59return MetadataAsValue::get(60Ctx, MDNode::get(Ctx, ValueAsMetadata::getConstant(Arg)));61}6263class SPIRVEmitIntrinsics64: public ModulePass,65public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {66SPIRVTargetMachine *TM = nullptr;67SPIRVGlobalRegistry *GR = nullptr;68Function *F = nullptr;69bool TrackConstants = true;70DenseMap<Instruction *, Constant *> AggrConsts;71DenseMap<Instruction *, Type *> AggrConstTypes;72DenseSet<Instruction *> AggrStores;73SPIRV::InstructionSet::InstructionSet InstrSet;7475// a register of Instructions that don't have a complete type definition76SmallPtrSet<Value *, 8> UncompleteTypeInfo;77SmallVector<Instruction *> PostprocessWorklist;7879// well known result types of builtins80enum WellKnownTypes { Event };8182// deduce element type of untyped pointers83Type *deduceElementType(Value *I, bool UnknownElemTypeI8);84Type *deduceElementTypeHelper(Value *I, bool UnknownElemTypeI8);85Type *deduceElementTypeHelper(Value *I, std::unordered_set<Value *> &Visited,86bool UnknownElemTypeI8);87Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,88bool UnknownElemTypeI8);89Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,90std::unordered_set<Value *> &Visited,91bool UnknownElemTypeI8);92Type *deduceElementTypeByUsersDeep(Value *Op,93std::unordered_set<Value *> &Visited,94bool UnknownElemTypeI8);95void maybeAssignPtrType(Type *&Ty, Value *I, Type *RefTy,96bool UnknownElemTypeI8);9798// deduce nested types of composites99Type *deduceNestedTypeHelper(User *U, bool UnknownElemTypeI8);100Type *deduceNestedTypeHelper(User *U, Type *Ty,101std::unordered_set<Value *> &Visited,102bool UnknownElemTypeI8);103104// deduce Types of operands of the Instruction if possible105void deduceOperandElementType(Instruction *I, Instruction *AskOp = 0,106Type *AskTy = 0, CallInst *AssignCI = 0);107108void preprocessCompositeConstants(IRBuilder<> &B);109void preprocessUndefs(IRBuilder<> &B);110111CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,112Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,113IRBuilder<> &B) {114SmallVector<Value *, 4> Args;115Args.push_back(Arg2);116Args.push_back(buildMD(Arg));117for (auto *Imm : Imms)118Args.push_back(Imm);119return B.CreateIntrinsic(IntrID, {Types}, Args);120}121122void buildAssignType(IRBuilder<> &B, Type *ElemTy, Value *Arg);123void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);124void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType);125126void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);127void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);128bool insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B,129bool UnknownElemTypeI8);130void insertAssignTypeIntrs(Instruction *I, IRBuilder<> &B);131void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType, Value *V,132IRBuilder<> &B);133void replacePointerOperandWithPtrCast(Instruction *I, Value *Pointer,134Type *ExpectedElementType,135unsigned OperandToReplace,136IRBuilder<> &B);137void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);138void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);139void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);140void processParamTypes(Function *F, IRBuilder<> &B);141void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);142Type *deduceFunParamElementType(Function *F, unsigned OpIdx);143Type *deduceFunParamElementType(Function *F, unsigned OpIdx,144std::unordered_set<Function *> &FVisited);145146public:147static char ID;148SPIRVEmitIntrinsics() : ModulePass(ID) {149initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry());150}151SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : ModulePass(ID), TM(_TM) {152initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry());153}154Instruction *visitInstruction(Instruction &I) { return &I; }155Instruction *visitSwitchInst(SwitchInst &I);156Instruction *visitGetElementPtrInst(GetElementPtrInst &I);157Instruction *visitBitCastInst(BitCastInst &I);158Instruction *visitInsertElementInst(InsertElementInst &I);159Instruction *visitExtractElementInst(ExtractElementInst &I);160Instruction *visitInsertValueInst(InsertValueInst &I);161Instruction *visitExtractValueInst(ExtractValueInst &I);162Instruction *visitLoadInst(LoadInst &I);163Instruction *visitStoreInst(StoreInst &I);164Instruction *visitAllocaInst(AllocaInst &I);165Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);166Instruction *visitUnreachableInst(UnreachableInst &I);167Instruction *visitCallInst(CallInst &I);168169StringRef getPassName() const override { return "SPIRV emit intrinsics"; }170171bool runOnModule(Module &M) override;172bool runOnFunction(Function &F);173bool postprocessTypes();174175void getAnalysisUsage(AnalysisUsage &AU) const override {176ModulePass::getAnalysisUsage(AU);177}178};179180bool isConvergenceIntrinsic(const Instruction *I) {181const auto *II = dyn_cast<IntrinsicInst>(I);182if (!II)183return false;184185return II->getIntrinsicID() == Intrinsic::experimental_convergence_entry ||186II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||187II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor;188}189} // namespace190191char SPIRVEmitIntrinsics::ID = 0;192193INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics",194false, false)195196static inline bool isAssignTypeInstr(const Instruction *I) {197return isa<IntrinsicInst>(I) &&198cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type;199}200201static bool isMemInstrToReplace(Instruction *I) {202return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) ||203isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I);204}205206static bool isAggrConstForceInt32(const Value *V) {207return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||208isa<ConstantDataArray>(V) ||209(isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());210}211212static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {213if (isa<PHINode>(I))214B.SetInsertPoint(I->getParent()->getFirstNonPHIOrDbgOrAlloca());215else216B.SetInsertPoint(I);217}218219static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I) {220B.SetCurrentDebugLocation(I->getDebugLoc());221if (I->getType()->isVoidTy())222B.SetInsertPoint(I->getNextNode());223else224B.SetInsertPoint(*I->getInsertionPointAfterDef());225}226227static bool requireAssignType(Instruction *I) {228IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I);229if (Intr) {230switch (Intr->getIntrinsicID()) {231case Intrinsic::invariant_start:232case Intrinsic::invariant_end:233return false;234}235}236return true;237}238239static inline void reportFatalOnTokenType(const Instruction *I) {240if (I->getType()->isTokenTy())241report_fatal_error("A token is encountered but SPIR-V without extensions "242"does not support token type",243false);244}245246static bool IsKernelArgInt8(Function *F, StoreInst *SI) {247return SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&248isPointerTy(SI->getValueOperand()->getType()) &&249isa<Argument>(SI->getValueOperand());250}251252// Maybe restore original function return type.253static inline Type *restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I,254Type *Ty) {255CallInst *CI = dyn_cast<CallInst>(I);256if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||257!CI->getCalledFunction() || CI->getCalledFunction()->isIntrinsic())258return Ty;259if (Type *OriginalTy = GR->findMutated(CI->getCalledFunction()))260return OriginalTy;261return Ty;262}263264// Reconstruct type with nested element types according to deduced type info.265// Return nullptr if no detailed type info is available.266static inline Type *reconstructType(SPIRVGlobalRegistry *GR, Value *Op) {267Type *Ty = Op->getType();268if (!isUntypedPointerTy(Ty))269return Ty;270// try to find the pointee type271if (Type *NestedTy = GR->findDeducedElementType(Op))272return getTypedPointerWrapper(NestedTy, getPointerAddressSpace(Ty));273// not a pointer according to the type info (e.g., Event object)274CallInst *CI = GR->findAssignPtrTypeInstr(Op);275if (!CI)276return nullptr;277MetadataAsValue *MD = cast<MetadataAsValue>(CI->getArgOperand(1));278return cast<ConstantAsMetadata>(MD->getMetadata())->getType();279}280281void SPIRVEmitIntrinsics::buildAssignType(IRBuilder<> &B, Type *Ty,282Value *Arg) {283Value *OfType = PoisonValue::get(Ty);284CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,285{Arg->getType()}, OfType, Arg, {}, B);286GR->addAssignPtrTypeInstr(Arg, AssignCI);287}288289void SPIRVEmitIntrinsics::buildAssignPtr(IRBuilder<> &B, Type *ElemTy,290Value *Arg) {291Value *OfType = PoisonValue::get(ElemTy);292CallInst *AssignPtrTyCI = GR->findAssignPtrTypeInstr(Arg);293if (AssignPtrTyCI == nullptr ||294AssignPtrTyCI->getParent()->getParent() != F) {295AssignPtrTyCI = buildIntrWithMD(296Intrinsic::spv_assign_ptr_type, {Arg->getType()}, OfType, Arg,297{B.getInt32(getPointerAddressSpace(Arg->getType()))}, B);298GR->addDeducedElementType(AssignPtrTyCI, ElemTy);299GR->addDeducedElementType(Arg, ElemTy);300GR->addAssignPtrTypeInstr(Arg, AssignPtrTyCI);301} else {302updateAssignType(AssignPtrTyCI, Arg, OfType);303}304}305306void SPIRVEmitIntrinsics::updateAssignType(CallInst *AssignCI, Value *Arg,307Value *OfType) {308AssignCI->setArgOperand(1, buildMD(OfType));309if (cast<IntrinsicInst>(AssignCI)->getIntrinsicID() !=310Intrinsic::spv_assign_ptr_type)311return;312313// update association with the pointee type314Type *ElemTy = OfType->getType();315GR->addDeducedElementType(AssignCI, ElemTy);316GR->addDeducedElementType(Arg, ElemTy);317}318319// Set element pointer type to the given value of ValueTy and tries to320// specify this type further (recursively) by Operand value, if needed.321Type *322SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,323bool UnknownElemTypeI8) {324std::unordered_set<Value *> Visited;325return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,326UnknownElemTypeI8);327}328329Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(330Type *ValueTy, Value *Operand, std::unordered_set<Value *> &Visited,331bool UnknownElemTypeI8) {332Type *Ty = ValueTy;333if (Operand) {334if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {335if (Type *NestedTy =336deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))337Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());338} else {339Ty = deduceNestedTypeHelper(dyn_cast<User>(Operand), Ty, Visited,340UnknownElemTypeI8);341}342}343return Ty;344}345346// Traverse User instructions to deduce an element pointer type of the operand.347Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(348Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {349if (!Op || !isPointerTy(Op->getType()))350return nullptr;351352if (auto ElemTy = getPointeeType(Op->getType()))353return ElemTy;354355// maybe we already know operand's element type356if (Type *KnownTy = GR->findDeducedElementType(Op))357return KnownTy;358359for (User *OpU : Op->users()) {360if (Instruction *Inst = dyn_cast<Instruction>(OpU)) {361if (Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))362return Ty;363}364}365return nullptr;366}367368// Implements what we know in advance about intrinsics and builtin calls369// TODO: consider feasibility of this particular case to be generalized by370// encoding knowledge about intrinsics and builtin calls by corresponding371// specification rules372static Type *getPointeeTypeByCallInst(StringRef DemangledName,373Function *CalledF, unsigned OpIdx) {374if ((DemangledName.starts_with("__spirv_ocl_printf(") ||375DemangledName.starts_with("printf(")) &&376OpIdx == 0)377return IntegerType::getInt8Ty(CalledF->getContext());378return nullptr;379}380381// Deduce and return a successfully deduced Type of the Instruction,382// or nullptr otherwise.383Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,384bool UnknownElemTypeI8) {385std::unordered_set<Value *> Visited;386return deduceElementTypeHelper(I, Visited, UnknownElemTypeI8);387}388389void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,390bool UnknownElemTypeI8) {391if (isUntypedPointerTy(RefTy)) {392if (!UnknownElemTypeI8)393return;394if (auto *I = dyn_cast<Instruction>(Op)) {395UncompleteTypeInfo.insert(I);396PostprocessWorklist.push_back(I);397}398}399Ty = RefTy;400}401402Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(403Value *I, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {404// allow to pass nullptr as an argument405if (!I)406return nullptr;407408// maybe already known409if (Type *KnownTy = GR->findDeducedElementType(I))410return KnownTy;411412// maybe a cycle413if (Visited.find(I) != Visited.end())414return nullptr;415Visited.insert(I);416417// fallback value in case when we fail to deduce a type418Type *Ty = nullptr;419// look for known basic patterns of type inference420if (auto *Ref = dyn_cast<AllocaInst>(I)) {421maybeAssignPtrType(Ty, I, Ref->getAllocatedType(), UnknownElemTypeI8);422} else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {423Ty = Ref->getResultElementType();424} else if (auto *Ref = dyn_cast<GlobalValue>(I)) {425Ty = deduceElementTypeByValueDeep(426Ref->getValueType(),427Ref->getNumOperands() > 0 ? Ref->getOperand(0) : nullptr, Visited,428UnknownElemTypeI8);429} else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {430Type *RefTy = deduceElementTypeHelper(Ref->getPointerOperand(), Visited,431UnknownElemTypeI8);432maybeAssignPtrType(Ty, I, RefTy, UnknownElemTypeI8);433} else if (auto *Ref = dyn_cast<BitCastInst>(I)) {434if (Type *Src = Ref->getSrcTy(), *Dest = Ref->getDestTy();435isPointerTy(Src) && isPointerTy(Dest))436Ty = deduceElementTypeHelper(Ref->getOperand(0), Visited,437UnknownElemTypeI8);438} else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {439Value *Op = Ref->getNewValOperand();440if (isPointerTy(Op->getType()))441Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);442} else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {443Value *Op = Ref->getValOperand();444if (isPointerTy(Op->getType()))445Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);446} else if (auto *Ref = dyn_cast<PHINode>(I)) {447for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {448Ty = deduceElementTypeByUsersDeep(Ref->getIncomingValue(i), Visited,449UnknownElemTypeI8);450if (Ty)451break;452}453} else if (auto *Ref = dyn_cast<SelectInst>(I)) {454for (Value *Op : {Ref->getTrueValue(), Ref->getFalseValue()}) {455Ty = deduceElementTypeByUsersDeep(Op, Visited, UnknownElemTypeI8);456if (Ty)457break;458}459} else if (auto *CI = dyn_cast<CallInst>(I)) {460static StringMap<unsigned> ResTypeByArg = {461{"to_global", 0},462{"to_local", 0},463{"to_private", 0},464{"__spirv_GenericCastToPtr_ToGlobal", 0},465{"__spirv_GenericCastToPtr_ToLocal", 0},466{"__spirv_GenericCastToPtr_ToPrivate", 0},467{"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},468{"__spirv_GenericCastToPtrExplicit_ToLocal", 0},469{"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};470// TODO: maybe improve performance by caching demangled names471if (Function *CalledF = CI->getCalledFunction()) {472std::string DemangledName =473getOclOrSpirvBuiltinDemangledName(CalledF->getName());474if (DemangledName.length() > 0)475DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);476auto AsArgIt = ResTypeByArg.find(DemangledName);477if (AsArgIt != ResTypeByArg.end()) {478Ty = deduceElementTypeHelper(CI->getArgOperand(AsArgIt->second),479Visited, UnknownElemTypeI8);480}481}482}483484// remember the found relationship485if (Ty) {486// specify nested types if needed, otherwise return unchanged487GR->addDeducedElementType(I, Ty);488}489490return Ty;491}492493// Re-create a type of the value if it has untyped pointer fields, also nested.494// Return the original value type if no corrections of untyped pointer495// information is found or needed.496Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,497bool UnknownElemTypeI8) {498std::unordered_set<Value *> Visited;499return deduceNestedTypeHelper(U, U->getType(), Visited, UnknownElemTypeI8);500}501502Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(503User *U, Type *OrigTy, std::unordered_set<Value *> &Visited,504bool UnknownElemTypeI8) {505if (!U)506return OrigTy;507508// maybe already known509if (Type *KnownTy = GR->findDeducedCompositeType(U))510return KnownTy;511512// maybe a cycle513if (Visited.find(U) != Visited.end())514return OrigTy;515Visited.insert(U);516517if (dyn_cast<StructType>(OrigTy)) {518SmallVector<Type *> Tys;519bool Change = false;520for (unsigned i = 0; i < U->getNumOperands(); ++i) {521Value *Op = U->getOperand(i);522Type *OpTy = Op->getType();523Type *Ty = OpTy;524if (Op) {525if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {526if (Type *NestedTy =527deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))528Ty = TypedPointerType::get(NestedTy, PtrTy->getAddressSpace());529} else {530Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,531UnknownElemTypeI8);532}533}534Tys.push_back(Ty);535Change |= Ty != OpTy;536}537if (Change) {538Type *NewTy = StructType::create(Tys);539GR->addDeducedCompositeType(U, NewTy);540return NewTy;541}542} else if (auto *ArrTy = dyn_cast<ArrayType>(OrigTy)) {543if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {544Type *OpTy = ArrTy->getElementType();545Type *Ty = OpTy;546if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {547if (Type *NestedTy =548deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))549Ty = TypedPointerType::get(NestedTy, PtrTy->getAddressSpace());550} else {551Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,552UnknownElemTypeI8);553}554if (Ty != OpTy) {555Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());556GR->addDeducedCompositeType(U, NewTy);557return NewTy;558}559}560} else if (auto *VecTy = dyn_cast<VectorType>(OrigTy)) {561if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {562Type *OpTy = VecTy->getElementType();563Type *Ty = OpTy;564if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {565if (Type *NestedTy =566deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))567Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());568} else {569Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,570UnknownElemTypeI8);571}572if (Ty != OpTy) {573Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());574GR->addDeducedCompositeType(U, NewTy);575return NewTy;576}577}578}579580return OrigTy;581}582583Type *SPIRVEmitIntrinsics::deduceElementType(Value *I, bool UnknownElemTypeI8) {584if (Type *Ty = deduceElementTypeHelper(I, UnknownElemTypeI8))585return Ty;586if (!UnknownElemTypeI8)587return nullptr;588if (auto *Instr = dyn_cast<Instruction>(I)) {589UncompleteTypeInfo.insert(Instr);590PostprocessWorklist.push_back(Instr);591}592return IntegerType::getInt8Ty(I->getContext());593}594595static inline Type *getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I,596Value *PointerOperand) {597Type *PointeeTy = GR->findDeducedElementType(PointerOperand);598if (PointeeTy && !isUntypedPointerTy(PointeeTy))599return nullptr;600auto *PtrTy = dyn_cast<PointerType>(I->getType());601if (!PtrTy)602return I->getType();603if (Type *NestedTy = GR->findDeducedElementType(I))604return getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());605return nullptr;606}607608// If the Instruction has Pointer operands with unresolved types, this function609// tries to deduce them. If the Instruction has Pointer operands with known610// types which differ from expected, this function tries to insert a bitcast to611// resolve the issue.612void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I,613Instruction *AskOp,614Type *AskTy,615CallInst *AskCI) {616SmallVector<std::pair<Value *, unsigned>> Ops;617Type *KnownElemTy = nullptr;618// look for known basic patterns of type inference619if (auto *Ref = dyn_cast<PHINode>(I)) {620if (!isPointerTy(I->getType()) ||621!(KnownElemTy = GR->findDeducedElementType(I)))622return;623for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {624Value *Op = Ref->getIncomingValue(i);625if (isPointerTy(Op->getType()))626Ops.push_back(std::make_pair(Op, i));627}628} else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {629KnownElemTy = GR->findDeducedElementType(I);630if (!KnownElemTy)631return;632Ops.push_back(std::make_pair(Ref->getPointerOperand(), 0));633} else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {634KnownElemTy = Ref->getSourceElementType();635if (isUntypedPointerTy(KnownElemTy))636return;637Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());638if (PointeeTy && !isUntypedPointerTy(PointeeTy))639return;640Ops.push_back(std::make_pair(Ref->getPointerOperand(),641GetElementPtrInst::getPointerOperandIndex()));642} else if (auto *Ref = dyn_cast<LoadInst>(I)) {643KnownElemTy = I->getType();644if (isUntypedPointerTy(KnownElemTy))645return;646Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());647if (PointeeTy && !isUntypedPointerTy(PointeeTy))648return;649Ops.push_back(std::make_pair(Ref->getPointerOperand(),650LoadInst::getPointerOperandIndex()));651} else if (auto *Ref = dyn_cast<StoreInst>(I)) {652if (IsKernelArgInt8(Ref->getParent()->getParent(), Ref))653return;654if (!(KnownElemTy = reconstructType(GR, Ref->getValueOperand())))655return;656Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());657if (PointeeTy && !isUntypedPointerTy(PointeeTy))658return;659Ops.push_back(std::make_pair(Ref->getPointerOperand(),660StoreInst::getPointerOperandIndex()));661} else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {662KnownElemTy = getAtomicElemTy(GR, I, Ref->getPointerOperand());663if (!KnownElemTy)664return;665Ops.push_back(std::make_pair(Ref->getPointerOperand(),666AtomicCmpXchgInst::getPointerOperandIndex()));667} else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {668KnownElemTy = getAtomicElemTy(GR, I, Ref->getPointerOperand());669if (!KnownElemTy)670return;671Ops.push_back(std::make_pair(Ref->getPointerOperand(),672AtomicRMWInst::getPointerOperandIndex()));673} else if (auto *Ref = dyn_cast<SelectInst>(I)) {674if (!isPointerTy(I->getType()) ||675!(KnownElemTy = GR->findDeducedElementType(I)))676return;677for (unsigned i = 0; i < Ref->getNumOperands(); i++) {678Value *Op = Ref->getOperand(i);679if (isPointerTy(Op->getType()))680Ops.push_back(std::make_pair(Op, i));681}682} else if (auto *Ref = dyn_cast<ReturnInst>(I)) {683Type *RetTy = F->getReturnType();684if (!isPointerTy(RetTy))685return;686Value *Op = Ref->getReturnValue();687if (!Op)688return;689if (!(KnownElemTy = GR->findDeducedElementType(F))) {690if (Type *OpElemTy = GR->findDeducedElementType(Op)) {691GR->addDeducedElementType(F, OpElemTy);692TypedPointerType *DerivedTy =693TypedPointerType::get(OpElemTy, getPointerAddressSpace(RetTy));694GR->addReturnType(F, DerivedTy);695}696return;697}698Ops.push_back(std::make_pair(Op, 0));699} else if (auto *Ref = dyn_cast<ICmpInst>(I)) {700if (!isPointerTy(Ref->getOperand(0)->getType()))701return;702Value *Op0 = Ref->getOperand(0);703Value *Op1 = Ref->getOperand(1);704Type *ElemTy0 = GR->findDeducedElementType(Op0);705Type *ElemTy1 = GR->findDeducedElementType(Op1);706if (ElemTy0) {707KnownElemTy = ElemTy0;708Ops.push_back(std::make_pair(Op1, 1));709} else if (ElemTy1) {710KnownElemTy = ElemTy1;711Ops.push_back(std::make_pair(Op0, 0));712}713} else if (auto *CI = dyn_cast<CallInst>(I)) {714if (Function *CalledF = CI->getCalledFunction()) {715std::string DemangledName =716getOclOrSpirvBuiltinDemangledName(CalledF->getName());717if (DemangledName.length() > 0 &&718!StringRef(DemangledName).starts_with("llvm.")) {719auto [Grp, Opcode, ExtNo] =720SPIRV::mapBuiltinToOpcode(DemangledName, InstrSet);721if (Opcode == SPIRV::OpGroupAsyncCopy) {722for (unsigned i = 0, PtrCnt = 0; i < CI->arg_size() && PtrCnt < 2;723++i) {724Value *Op = CI->getArgOperand(i);725if (!isPointerTy(Op->getType()))726continue;727++PtrCnt;728if (Type *ElemTy = GR->findDeducedElementType(Op))729KnownElemTy = ElemTy; // src will rewrite dest if both are defined730Ops.push_back(std::make_pair(Op, i));731}732} else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {733if (CI->arg_size() < 2)734return;735Value *Op = CI->getArgOperand(0);736if (!isPointerTy(Op->getType()))737return;738switch (Opcode) {739case SPIRV::OpAtomicLoad:740case SPIRV::OpAtomicCompareExchangeWeak:741case SPIRV::OpAtomicCompareExchange:742case SPIRV::OpAtomicExchange:743case SPIRV::OpAtomicIAdd:744case SPIRV::OpAtomicISub:745case SPIRV::OpAtomicOr:746case SPIRV::OpAtomicXor:747case SPIRV::OpAtomicAnd:748case SPIRV::OpAtomicUMin:749case SPIRV::OpAtomicUMax:750case SPIRV::OpAtomicSMin:751case SPIRV::OpAtomicSMax: {752KnownElemTy = getAtomicElemTy(GR, I, Op);753if (!KnownElemTy)754return;755Ops.push_back(std::make_pair(Op, 0));756} break;757}758}759}760}761}762763// There is no enough info to deduce types or all is valid.764if (!KnownElemTy || Ops.size() == 0)765return;766767LLVMContext &Ctx = F->getContext();768IRBuilder<> B(Ctx);769for (auto &OpIt : Ops) {770Value *Op = OpIt.first;771if (Op->use_empty() || (AskOp && Op != AskOp))772continue;773Type *Ty = AskOp ? AskTy : GR->findDeducedElementType(Op);774if (Ty == KnownElemTy)775continue;776Value *OpTyVal = PoisonValue::get(KnownElemTy);777Type *OpTy = Op->getType();778if (!Ty || AskTy || isUntypedPointerTy(Ty) ||779UncompleteTypeInfo.contains(Op)) {780GR->addDeducedElementType(Op, KnownElemTy);781// check if there is existing Intrinsic::spv_assign_ptr_type instruction782CallInst *AssignCI = AskCI ? AskCI : GR->findAssignPtrTypeInstr(Op);783if (AssignCI == nullptr) {784Instruction *User = dyn_cast<Instruction>(Op->use_begin()->get());785setInsertPointSkippingPhis(B, User ? User->getNextNode() : I);786CallInst *CI =787buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,788{B.getInt32(getPointerAddressSpace(OpTy))}, B);789GR->addAssignPtrTypeInstr(Op, CI);790} else {791updateAssignType(AssignCI, Op, OpTyVal);792}793} else {794if (auto *OpI = dyn_cast<Instruction>(Op)) {795// spv_ptrcast's argument Op denotes an instruction that generates796// a value, and we may use getInsertionPointAfterDef()797B.SetInsertPoint(*OpI->getInsertionPointAfterDef());798B.SetCurrentDebugLocation(OpI->getDebugLoc());799} else if (auto *OpA = dyn_cast<Argument>(Op)) {800B.SetInsertPointPastAllocas(OpA->getParent());801B.SetCurrentDebugLocation(DebugLoc());802} else {803B.SetInsertPoint(F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());804}805SmallVector<Type *, 2> Types = {OpTy, OpTy};806SmallVector<Value *, 2> Args = {Op, buildMD(OpTyVal),807B.getInt32(getPointerAddressSpace(OpTy))};808CallInst *PtrCastI =809B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);810I->setOperand(OpIt.second, PtrCastI);811}812}813}814815void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,816Instruction *New,817IRBuilder<> &B) {818while (!Old->user_empty()) {819auto *U = Old->user_back();820if (isAssignTypeInstr(U)) {821B.SetInsertPoint(U);822SmallVector<Value *, 2> Args = {New, U->getOperand(1)};823CallInst *AssignCI =824B.CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);825GR->addAssignPtrTypeInstr(New, AssignCI);826U->eraseFromParent();827} else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||828isa<CallInst>(U)) {829U->replaceUsesOfWith(Old, New);830} else {831llvm_unreachable("illegal aggregate intrinsic user");832}833}834Old->eraseFromParent();835}836837void SPIRVEmitIntrinsics::preprocessUndefs(IRBuilder<> &B) {838std::queue<Instruction *> Worklist;839for (auto &I : instructions(F))840Worklist.push(&I);841842while (!Worklist.empty()) {843Instruction *I = Worklist.front();844bool BPrepared = false;845Worklist.pop();846847for (auto &Op : I->operands()) {848auto *AggrUndef = dyn_cast<UndefValue>(Op);849if (!AggrUndef || !Op->getType()->isAggregateType())850continue;851852if (!BPrepared) {853setInsertPointSkippingPhis(B, I);854BPrepared = true;855}856auto *IntrUndef = B.CreateIntrinsic(Intrinsic::spv_undef, {}, {});857Worklist.push(IntrUndef);858I->replaceUsesOfWith(Op, IntrUndef);859AggrConsts[IntrUndef] = AggrUndef;860AggrConstTypes[IntrUndef] = AggrUndef->getType();861}862}863}864865void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {866std::queue<Instruction *> Worklist;867for (auto &I : instructions(F))868Worklist.push(&I);869870while (!Worklist.empty()) {871auto *I = Worklist.front();872bool IsPhi = isa<PHINode>(I), BPrepared = false;873assert(I);874bool KeepInst = false;875for (const auto &Op : I->operands()) {876Constant *AggrConst = nullptr;877Type *ResTy = nullptr;878if (auto *COp = dyn_cast<ConstantVector>(Op)) {879AggrConst = cast<Constant>(COp);880ResTy = COp->getType();881} else if (auto *COp = dyn_cast<ConstantArray>(Op)) {882AggrConst = cast<Constant>(COp);883ResTy = B.getInt32Ty();884} else if (auto *COp = dyn_cast<ConstantStruct>(Op)) {885AggrConst = cast<Constant>(COp);886ResTy = B.getInt32Ty();887} else if (auto *COp = dyn_cast<ConstantDataArray>(Op)) {888AggrConst = cast<Constant>(COp);889ResTy = B.getInt32Ty();890} else if (auto *COp = dyn_cast<ConstantAggregateZero>(Op)) {891AggrConst = cast<Constant>(COp);892ResTy = Op->getType()->isVectorTy() ? COp->getType() : B.getInt32Ty();893}894if (AggrConst) {895SmallVector<Value *> Args;896if (auto *COp = dyn_cast<ConstantDataSequential>(Op))897for (unsigned i = 0; i < COp->getNumElements(); ++i)898Args.push_back(COp->getElementAsConstant(i));899else900for (auto &COp : AggrConst->operands())901Args.push_back(COp);902if (!BPrepared) {903IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())904: B.SetInsertPoint(I);905BPrepared = true;906}907auto *CI =908B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {Args});909Worklist.push(CI);910I->replaceUsesOfWith(Op, CI);911KeepInst = true;912AggrConsts[CI] = AggrConst;913AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst, false);914}915}916if (!KeepInst)917Worklist.pop();918}919}920921Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {922if (!Call.isInlineAsm())923return &Call;924925const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());926LLVMContext &Ctx = F->getContext();927928Constant *TyC = UndefValue::get(IA->getFunctionType());929MDString *ConstraintString = MDString::get(Ctx, IA->getConstraintString());930SmallVector<Value *> Args = {931buildMD(TyC),932MetadataAsValue::get(Ctx, MDNode::get(Ctx, ConstraintString))};933for (unsigned OpIdx = 0; OpIdx < Call.arg_size(); OpIdx++)934Args.push_back(Call.getArgOperand(OpIdx));935936IRBuilder<> B(Call.getParent());937B.SetInsertPoint(&Call);938B.CreateIntrinsic(Intrinsic::spv_inline_asm, {}, {Args});939return &Call;940}941942Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {943BasicBlock *ParentBB = I.getParent();944IRBuilder<> B(ParentBB);945B.SetInsertPoint(&I);946SmallVector<Value *, 4> Args;947SmallVector<BasicBlock *> BBCases;948for (auto &Op : I.operands()) {949if (Op.get()->getType()->isSized()) {950Args.push_back(Op);951} else if (BasicBlock *BB = dyn_cast<BasicBlock>(Op.get())) {952BBCases.push_back(BB);953Args.push_back(BlockAddress::get(BB->getParent(), BB));954} else {955report_fatal_error("Unexpected switch operand");956}957}958CallInst *NewI = B.CreateIntrinsic(Intrinsic::spv_switch,959{I.getOperand(0)->getType()}, {Args});960// remove switch to avoid its unneeded and undesirable unwrap into branches961// and conditions962I.replaceAllUsesWith(NewI);963I.eraseFromParent();964// insert artificial and temporary instruction to preserve valid CFG,965// it will be removed after IR translation pass966B.SetInsertPoint(ParentBB);967IndirectBrInst *BrI = B.CreateIndirectBr(968Constant::getNullValue(PointerType::getUnqual(ParentBB->getContext())),969BBCases.size());970for (BasicBlock *BBCase : BBCases)971BrI->addDestination(BBCase);972return BrI;973}974975Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {976IRBuilder<> B(I.getParent());977B.SetInsertPoint(&I);978SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};979SmallVector<Value *, 4> Args;980Args.push_back(B.getInt1(I.isInBounds()));981for (auto &Op : I.operands())982Args.push_back(Op);983auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});984I.replaceAllUsesWith(NewI);985I.eraseFromParent();986return NewI;987}988989Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {990IRBuilder<> B(I.getParent());991B.SetInsertPoint(&I);992Value *Source = I.getOperand(0);993994// SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of995// varying element types. In case of IR coming from older versions of LLVM996// such bitcasts do not provide sufficient information, should be just skipped997// here, and handled in insertPtrCastOrAssignTypeInstr.998if (isPointerTy(I.getType())) {999I.replaceAllUsesWith(Source);1000I.eraseFromParent();1001return nullptr;1002}10031004SmallVector<Type *, 2> Types = {I.getType(), Source->getType()};1005SmallVector<Value *> Args(I.op_begin(), I.op_end());1006auto *NewI = B.CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});1007std::string InstName = I.hasName() ? I.getName().str() : "";1008I.replaceAllUsesWith(NewI);1009I.eraseFromParent();1010NewI->setName(InstName);1011return NewI;1012}10131014void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(1015TargetExtType *AssignedType, Value *V, IRBuilder<> &B) {1016Type *VTy = V->getType();10171018// A couple of sanity checks.1019assert(isPointerTy(VTy) && "Expect a pointer type!");1020if (auto PType = dyn_cast<TypedPointerType>(VTy))1021if (PType->getElementType() != AssignedType)1022report_fatal_error("Unexpected pointer element type!");10231024CallInst *AssignCI = GR->findAssignPtrTypeInstr(V);1025if (!AssignCI) {1026buildAssignType(B, AssignedType, V);1027return;1028}10291030Type *CurrentType =1031dyn_cast<ConstantAsMetadata>(1032cast<MetadataAsValue>(AssignCI->getOperand(1))->getMetadata())1033->getType();1034if (CurrentType == AssignedType)1035return;10361037// Builtin types cannot be redeclared or casted.1038if (CurrentType->isTargetExtTy())1039report_fatal_error("Type mismatch " + CurrentType->getTargetExtName() +1040"/" + AssignedType->getTargetExtName() +1041" for value " + V->getName(),1042false);10431044// Our previous guess about the type seems to be wrong, let's update1045// inferred type according to a new, more precise type information.1046updateAssignType(AssignCI, V, PoisonValue::get(AssignedType));1047}10481049void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(1050Instruction *I, Value *Pointer, Type *ExpectedElementType,1051unsigned OperandToReplace, IRBuilder<> &B) {1052// If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source1053// pointer instead. The BitCastInst should be later removed when visited.1054while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))1055Pointer = BC->getOperand(0);10561057// Do not emit spv_ptrcast if Pointer's element type is ExpectedElementType1058Type *PointerElemTy = deduceElementTypeHelper(Pointer, false);1059if (PointerElemTy == ExpectedElementType ||1060isEquivalentTypes(PointerElemTy, ExpectedElementType))1061return;10621063setInsertPointSkippingPhis(B, I);1064MetadataAsValue *VMD = buildMD(PoisonValue::get(ExpectedElementType));1065unsigned AddressSpace = getPointerAddressSpace(Pointer->getType());1066bool FirstPtrCastOrAssignPtrType = true;10671068// Do not emit new spv_ptrcast if equivalent one already exists or when1069// spv_assign_ptr_type already targets this pointer with the same element1070// type.1071for (auto User : Pointer->users()) {1072auto *II = dyn_cast<IntrinsicInst>(User);1073if (!II ||1074(II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&1075II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||1076II->getOperand(0) != Pointer)1077continue;10781079// There is some spv_ptrcast/spv_assign_ptr_type already targeting this1080// pointer.1081FirstPtrCastOrAssignPtrType = false;1082if (II->getOperand(1) != VMD ||1083dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=1084AddressSpace)1085continue;10861087// The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the same1088// element type and address space.1089if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)1090return;10911092// This must be a spv_ptrcast, do not emit new if this one has the same BB1093// as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.1094if (II->getParent() != I->getParent())1095continue;10961097I->setOperand(OperandToReplace, II);1098return;1099}11001101// // Do not emit spv_ptrcast if it would cast to the default pointer element1102// // type (i8) of the same address space.1103// if (ExpectedElementType->isIntegerTy(8))1104// return;11051106// If this would be the first spv_ptrcast, do not emit spv_ptrcast and emit1107// spv_assign_ptr_type instead.1108if (FirstPtrCastOrAssignPtrType &&1109(isa<Instruction>(Pointer) || isa<Argument>(Pointer))) {1110buildAssignPtr(B, ExpectedElementType, Pointer);1111return;1112}11131114// Emit spv_ptrcast1115SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};1116SmallVector<Value *, 2> Args = {Pointer, VMD, B.getInt32(AddressSpace)};1117auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);1118I->setOperand(OperandToReplace, PtrCastI);1119}11201121void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,1122IRBuilder<> &B) {1123// Handle basic instructions:1124StoreInst *SI = dyn_cast<StoreInst>(I);1125if (IsKernelArgInt8(F, SI)) {1126return replacePointerOperandWithPtrCast(1127I, SI->getValueOperand(), IntegerType::getInt8Ty(F->getContext()), 0,1128B);1129} else if (SI) {1130Value *Op = SI->getValueOperand();1131Type *OpTy = Op->getType();1132if (auto *OpI = dyn_cast<Instruction>(Op))1133OpTy = restoreMutatedType(GR, OpI, OpTy);1134if (OpTy == Op->getType())1135OpTy = deduceElementTypeByValueDeep(OpTy, Op, false);1136return replacePointerOperandWithPtrCast(I, SI->getPointerOperand(), OpTy, 1,1137B);1138} else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {1139return replacePointerOperandWithPtrCast(I, LI->getPointerOperand(),1140LI->getType(), 0, B);1141} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {1142return replacePointerOperandWithPtrCast(I, GEPI->getPointerOperand(),1143GEPI->getSourceElementType(), 0, B);1144}11451146// Handle calls to builtins (non-intrinsics):1147CallInst *CI = dyn_cast<CallInst>(I);1148if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||1149!CI->getCalledFunction() || CI->getCalledFunction()->isIntrinsic())1150return;11511152// collect information about formal parameter types1153std::string DemangledName =1154getOclOrSpirvBuiltinDemangledName(CI->getCalledFunction()->getName());1155Function *CalledF = CI->getCalledFunction();1156SmallVector<Type *, 4> CalledArgTys;1157bool HaveTypes = false;1158for (unsigned OpIdx = 0; OpIdx < CalledF->arg_size(); ++OpIdx) {1159Argument *CalledArg = CalledF->getArg(OpIdx);1160Type *ArgType = CalledArg->getType();1161if (!isPointerTy(ArgType)) {1162CalledArgTys.push_back(nullptr);1163} else if (isTypedPointerTy(ArgType)) {1164CalledArgTys.push_back(cast<TypedPointerType>(ArgType)->getElementType());1165HaveTypes = true;1166} else {1167Type *ElemTy = GR->findDeducedElementType(CalledArg);1168if (!ElemTy && hasPointeeTypeAttr(CalledArg))1169ElemTy = getPointeeTypeByAttr(CalledArg);1170if (!ElemTy) {1171ElemTy = getPointeeTypeByCallInst(DemangledName, CalledF, OpIdx);1172if (ElemTy) {1173GR->addDeducedElementType(CalledArg, ElemTy);1174} else {1175for (User *U : CalledArg->users()) {1176if (Instruction *Inst = dyn_cast<Instruction>(U)) {1177if ((ElemTy = deduceElementTypeHelper(Inst, false)) != nullptr)1178break;1179}1180}1181}1182}1183HaveTypes |= ElemTy != nullptr;1184CalledArgTys.push_back(ElemTy);1185}1186}11871188if (DemangledName.empty() && !HaveTypes)1189return;11901191for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) {1192Value *ArgOperand = CI->getArgOperand(OpIdx);1193if (!isPointerTy(ArgOperand->getType()))1194continue;11951196// Constants (nulls/undefs) are handled in insertAssignPtrTypeIntrs()1197if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand)) {1198// However, we may have assumptions about the formal argument's type and1199// may have a need to insert a ptr cast for the actual parameter of this1200// call.1201Argument *CalledArg = CalledF->getArg(OpIdx);1202if (!GR->findDeducedElementType(CalledArg))1203continue;1204}12051206Type *ExpectedType =1207OpIdx < CalledArgTys.size() ? CalledArgTys[OpIdx] : nullptr;1208if (!ExpectedType && !DemangledName.empty())1209ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(1210DemangledName, OpIdx, I->getContext());1211if (!ExpectedType || ExpectedType->isVoidTy())1212continue;12131214if (ExpectedType->isTargetExtTy())1215insertAssignPtrTypeTargetExt(cast<TargetExtType>(ExpectedType),1216ArgOperand, B);1217else1218replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx, B);1219}1220}12211222Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {1223SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),1224I.getOperand(1)->getType(),1225I.getOperand(2)->getType()};1226IRBuilder<> B(I.getParent());1227B.SetInsertPoint(&I);1228SmallVector<Value *> Args(I.op_begin(), I.op_end());1229auto *NewI = B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});1230std::string InstName = I.hasName() ? I.getName().str() : "";1231I.replaceAllUsesWith(NewI);1232I.eraseFromParent();1233NewI->setName(InstName);1234return NewI;1235}12361237Instruction *1238SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {1239IRBuilder<> B(I.getParent());1240B.SetInsertPoint(&I);1241SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(),1242I.getIndexOperand()->getType()};1243SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};1244auto *NewI = B.CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});1245std::string InstName = I.hasName() ? I.getName().str() : "";1246I.replaceAllUsesWith(NewI);1247I.eraseFromParent();1248NewI->setName(InstName);1249return NewI;1250}12511252Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {1253IRBuilder<> B(I.getParent());1254B.SetInsertPoint(&I);1255SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()};1256SmallVector<Value *> Args;1257for (auto &Op : I.operands())1258if (isa<UndefValue>(Op))1259Args.push_back(UndefValue::get(B.getInt32Ty()));1260else1261Args.push_back(Op);1262for (auto &Op : I.indices())1263Args.push_back(B.getInt32(Op));1264Instruction *NewI =1265B.CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args});1266replaceMemInstrUses(&I, NewI, B);1267return NewI;1268}12691270Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {1271IRBuilder<> B(I.getParent());1272B.SetInsertPoint(&I);1273SmallVector<Value *> Args;1274for (auto &Op : I.operands())1275Args.push_back(Op);1276for (auto &Op : I.indices())1277Args.push_back(B.getInt32(Op));1278auto *NewI =1279B.CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});1280I.replaceAllUsesWith(NewI);1281I.eraseFromParent();1282return NewI;1283}12841285Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) {1286if (!I.getType()->isAggregateType())1287return &I;1288IRBuilder<> B(I.getParent());1289B.SetInsertPoint(&I);1290TrackConstants = false;1291const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();1292MachineMemOperand::Flags Flags =1293TLI->getLoadMemOperandFlags(I, F->getDataLayout());1294auto *NewI =1295B.CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()},1296{I.getPointerOperand(), B.getInt16(Flags),1297B.getInt8(I.getAlign().value())});1298replaceMemInstrUses(&I, NewI, B);1299return NewI;1300}13011302Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {1303if (!AggrStores.contains(&I))1304return &I;1305IRBuilder<> B(I.getParent());1306B.SetInsertPoint(&I);1307TrackConstants = false;1308const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();1309MachineMemOperand::Flags Flags =1310TLI->getStoreMemOperandFlags(I, F->getDataLayout());1311auto *PtrOp = I.getPointerOperand();1312auto *NewI = B.CreateIntrinsic(1313Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()},1314{I.getValueOperand(), PtrOp, B.getInt16(Flags),1315B.getInt8(I.getAlign().value())});1316I.eraseFromParent();1317return NewI;1318}13191320Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {1321Value *ArraySize = nullptr;1322if (I.isArrayAllocation()) {1323const SPIRVSubtarget *STI = TM->getSubtargetImpl(*I.getFunction());1324if (!STI->canUseExtension(1325SPIRV::Extension::SPV_INTEL_variable_length_array))1326report_fatal_error(1327"array allocation: this instruction requires the following "1328"SPIR-V extension: SPV_INTEL_variable_length_array",1329false);1330ArraySize = I.getArraySize();1331}1332IRBuilder<> B(I.getParent());1333B.SetInsertPoint(&I);1334TrackConstants = false;1335Type *PtrTy = I.getType();1336auto *NewI =1337ArraySize ? B.CreateIntrinsic(Intrinsic::spv_alloca_array,1338{PtrTy, ArraySize->getType()}, {ArraySize})1339: B.CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy}, {});1340std::string InstName = I.hasName() ? I.getName().str() : "";1341I.replaceAllUsesWith(NewI);1342I.eraseFromParent();1343NewI->setName(InstName);1344return NewI;1345}13461347Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {1348assert(I.getType()->isAggregateType() && "Aggregate result is expected");1349IRBuilder<> B(I.getParent());1350B.SetInsertPoint(&I);1351SmallVector<Value *> Args;1352for (auto &Op : I.operands())1353Args.push_back(Op);1354Args.push_back(B.getInt32(I.getSyncScopeID()));1355Args.push_back(B.getInt32(1356static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering()))));1357Args.push_back(B.getInt32(1358static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering()))));1359auto *NewI = B.CreateIntrinsic(Intrinsic::spv_cmpxchg,1360{I.getPointerOperand()->getType()}, {Args});1361replaceMemInstrUses(&I, NewI, B);1362return NewI;1363}13641365Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) {1366IRBuilder<> B(I.getParent());1367B.SetInsertPoint(&I);1368B.CreateIntrinsic(Intrinsic::spv_unreachable, {}, {});1369return &I;1370}13711372void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,1373IRBuilder<> &B) {1374// Skip special artifical variable llvm.global.annotations.1375if (GV.getName() == "llvm.global.annotations")1376return;1377if (GV.hasInitializer() && !isa<UndefValue>(GV.getInitializer())) {1378// Deduce element type and store results in Global Registry.1379// Result is ignored, because TypedPointerType is not supported1380// by llvm IR general logic.1381deduceElementTypeHelper(&GV, false);1382Constant *Init = GV.getInitializer();1383Type *Ty = isAggrConstForceInt32(Init) ? B.getInt32Ty() : Init->getType();1384Constant *Const = isAggrConstForceInt32(Init) ? B.getInt32(1) : Init;1385auto *InitInst = B.CreateIntrinsic(Intrinsic::spv_init_global,1386{GV.getType(), Ty}, {&GV, Const});1387InitInst->setArgOperand(1, Init);1388}1389if ((!GV.hasInitializer() || isa<UndefValue>(GV.getInitializer())) &&1390GV.getNumUses() == 0)1391B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);1392}13931394// Return true, if we can't decide what is the pointee type now and will get1395// back to the question later. Return false is spv_assign_ptr_type is not needed1396// or can be inserted immediately.1397bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,1398IRBuilder<> &B,1399bool UnknownElemTypeI8) {1400reportFatalOnTokenType(I);1401if (!isPointerTy(I->getType()) || !requireAssignType(I) ||1402isa<BitCastInst>(I))1403return false;14041405setInsertPointAfterDef(B, I);1406if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {1407buildAssignPtr(B, ElemTy, I);1408return false;1409}1410return true;1411}14121413void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,1414IRBuilder<> &B) {1415// TODO: extend the list of functions with known result types1416static StringMap<unsigned> ResTypeWellKnown = {1417{"async_work_group_copy", WellKnownTypes::Event},1418{"async_work_group_strided_copy", WellKnownTypes::Event},1419{"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};14201421reportFatalOnTokenType(I);14221423bool IsKnown = false;1424if (auto *CI = dyn_cast<CallInst>(I)) {1425if (!CI->isIndirectCall() && !CI->isInlineAsm() &&1426CI->getCalledFunction() && !CI->getCalledFunction()->isIntrinsic()) {1427Function *CalledF = CI->getCalledFunction();1428std::string DemangledName =1429getOclOrSpirvBuiltinDemangledName(CalledF->getName());1430if (DemangledName.length() > 0)1431DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);1432auto ResIt = ResTypeWellKnown.find(DemangledName);1433if (ResIt != ResTypeWellKnown.end()) {1434IsKnown = true;1435setInsertPointAfterDef(B, I);1436switch (ResIt->second) {1437case WellKnownTypes::Event:1438buildAssignType(B, TargetExtType::get(I->getContext(), "spirv.Event"),1439I);1440break;1441}1442}1443}1444}14451446Type *Ty = I->getType();1447if (!IsKnown && !Ty->isVoidTy() && !isPointerTy(Ty) && requireAssignType(I)) {1448setInsertPointAfterDef(B, I);1449Type *TypeToAssign = Ty;1450if (auto *II = dyn_cast<IntrinsicInst>(I)) {1451if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||1452II->getIntrinsicID() == Intrinsic::spv_undef) {1453auto It = AggrConstTypes.find(II);1454if (It == AggrConstTypes.end())1455report_fatal_error("Unknown composite intrinsic type");1456TypeToAssign = It->second;1457}1458}1459TypeToAssign = restoreMutatedType(GR, I, TypeToAssign);1460buildAssignType(B, TypeToAssign, I);1461}1462for (const auto &Op : I->operands()) {1463if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||1464// Check GetElementPtrConstantExpr case.1465(isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) {1466setInsertPointSkippingPhis(B, I);1467Type *OpTy = Op->getType();1468if (isa<UndefValue>(Op) && OpTy->isAggregateType()) {1469CallInst *AssignCI =1470buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,1471UndefValue::get(B.getInt32Ty()), {}, B);1472GR->addAssignPtrTypeInstr(Op, AssignCI);1473} else if (!isa<Instruction>(Op)) {1474Type *OpTy = Op->getType();1475if (auto PType = dyn_cast<TypedPointerType>(OpTy)) {1476buildAssignPtr(B, PType->getElementType(), Op);1477} else if (isPointerTy(OpTy)) {1478Type *ElemTy = GR->findDeducedElementType(Op);1479buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true), Op);1480} else {1481CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,1482{OpTy}, Op, Op, {}, B);1483GR->addAssignPtrTypeInstr(Op, AssignCI);1484}1485}1486}1487}1488}14891490void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,1491IRBuilder<> &B) {1492if (MDNode *MD = I->getMetadata("spirv.Decorations")) {1493setInsertPointAfterDef(B, I);1494B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},1495{I, MetadataAsValue::get(I->getContext(), MD)});1496}1497}14981499void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,1500IRBuilder<> &B) {1501auto *II = dyn_cast<IntrinsicInst>(I);1502if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&1503TrackConstants) {1504setInsertPointAfterDef(B, I);1505auto t = AggrConsts.find(I);1506assert(t != AggrConsts.end());1507auto *NewOp =1508buildIntrWithMD(Intrinsic::spv_track_constant,1509{II->getType(), II->getType()}, t->second, I, {}, B);1510I->replaceAllUsesWith(NewOp);1511NewOp->setArgOperand(0, I);1512}1513bool IsPhi = isa<PHINode>(I), BPrepared = false;1514for (const auto &Op : I->operands()) {1515if (isa<PHINode>(I) || isa<SwitchInst>(I))1516TrackConstants = false;1517if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) {1518unsigned OpNo = Op.getOperandNo();1519if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||1520(II->paramHasAttr(OpNo, Attribute::ImmArg))))1521continue;1522if (!BPrepared) {1523IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())1524: B.SetInsertPoint(I);1525BPrepared = true;1526}1527Value *OpTyVal = Op;1528if (Op->getType()->isTargetExtTy())1529OpTyVal = PoisonValue::get(Op->getType());1530auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,1531{Op->getType(), OpTyVal->getType()}, Op,1532OpTyVal, {}, B);1533I->setOperand(OpNo, NewOp);1534}1535}1536if (I->hasName()) {1537reportFatalOnTokenType(I);1538setInsertPointAfterDef(B, I);1539std::vector<Value *> Args = {I};1540addStringImm(I->getName(), B, Args);1541B.CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);1542}1543}15441545Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F,1546unsigned OpIdx) {1547std::unordered_set<Function *> FVisited;1548return deduceFunParamElementType(F, OpIdx, FVisited);1549}15501551Type *SPIRVEmitIntrinsics::deduceFunParamElementType(1552Function *F, unsigned OpIdx, std::unordered_set<Function *> &FVisited) {1553// maybe a cycle1554if (FVisited.find(F) != FVisited.end())1555return nullptr;1556FVisited.insert(F);15571558std::unordered_set<Value *> Visited;1559SmallVector<std::pair<Function *, unsigned>> Lookup;1560// search in function's call sites1561for (User *U : F->users()) {1562CallInst *CI = dyn_cast<CallInst>(U);1563if (!CI || OpIdx >= CI->arg_size())1564continue;1565Value *OpArg = CI->getArgOperand(OpIdx);1566if (!isPointerTy(OpArg->getType()))1567continue;1568// maybe we already know operand's element type1569if (Type *KnownTy = GR->findDeducedElementType(OpArg))1570return KnownTy;1571// try to deduce from the operand itself1572Visited.clear();1573if (Type *Ty = deduceElementTypeHelper(OpArg, Visited, false))1574return Ty;1575// search in actual parameter's users1576for (User *OpU : OpArg->users()) {1577Instruction *Inst = dyn_cast<Instruction>(OpU);1578if (!Inst || Inst == CI)1579continue;1580Visited.clear();1581if (Type *Ty = deduceElementTypeHelper(Inst, Visited, false))1582return Ty;1583}1584// check if it's a formal parameter of the outer function1585if (!CI->getParent() || !CI->getParent()->getParent())1586continue;1587Function *OuterF = CI->getParent()->getParent();1588if (FVisited.find(OuterF) != FVisited.end())1589continue;1590for (unsigned i = 0; i < OuterF->arg_size(); ++i) {1591if (OuterF->getArg(i) == OpArg) {1592Lookup.push_back(std::make_pair(OuterF, i));1593break;1594}1595}1596}15971598// search in function parameters1599for (auto &Pair : Lookup) {1600if (Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))1601return Ty;1602}16031604return nullptr;1605}16061607void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,1608IRBuilder<> &B) {1609B.SetInsertPointPastAllocas(F);1610for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {1611Argument *Arg = F->getArg(OpIdx);1612if (!isUntypedPointerTy(Arg->getType()))1613continue;1614Type *ElemTy = GR->findDeducedElementType(Arg);1615if (!ElemTy && hasPointeeTypeAttr(Arg) &&1616(ElemTy = getPointeeTypeByAttr(Arg)) != nullptr)1617buildAssignPtr(B, ElemTy, Arg);1618}1619}16201621void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {1622B.SetInsertPointPastAllocas(F);1623for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {1624Argument *Arg = F->getArg(OpIdx);1625if (!isUntypedPointerTy(Arg->getType()))1626continue;1627Type *ElemTy = GR->findDeducedElementType(Arg);1628if (!ElemTy && (ElemTy = deduceFunParamElementType(F, OpIdx)) != nullptr)1629buildAssignPtr(B, ElemTy, Arg);1630}1631}16321633bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {1634if (Func.isDeclaration())1635return false;16361637const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(Func);1638GR = ST.getSPIRVGlobalRegistry();1639InstrSet = ST.isOpenCLEnv() ? SPIRV::InstructionSet::OpenCL_std1640: SPIRV::InstructionSet::GLSL_std_450;16411642F = &Func;1643IRBuilder<> B(Func.getContext());1644AggrConsts.clear();1645AggrConstTypes.clear();1646AggrStores.clear();16471648processParamTypesByFunHeader(F, B);16491650// StoreInst's operand type can be changed during the next transformations,1651// so we need to store it in the set. Also store already transformed types.1652for (auto &I : instructions(Func)) {1653StoreInst *SI = dyn_cast<StoreInst>(&I);1654if (!SI)1655continue;1656Type *ElTy = SI->getValueOperand()->getType();1657if (ElTy->isAggregateType() || ElTy->isVectorTy())1658AggrStores.insert(&I);1659}16601661B.SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin());1662for (auto &GV : Func.getParent()->globals())1663processGlobalValue(GV, B);16641665preprocessUndefs(B);1666preprocessCompositeConstants(B);1667SmallVector<Instruction *> Worklist;1668for (auto &I : instructions(Func))1669Worklist.push_back(&I);16701671for (auto &I : Worklist) {1672// Don't emit intrinsincs for convergence intrinsics.1673if (isConvergenceIntrinsic(I))1674continue;16751676bool Postpone = insertAssignPtrTypeIntrs(I, B, false);1677// if Postpone is true, we can't decide on pointee type yet1678insertAssignTypeIntrs(I, B);1679insertPtrCastOrAssignTypeInstr(I, B);1680insertSpirvDecorations(I, B);1681// if instruction requires a pointee type set, let's check if we know it1682// already, and force it to be i8 if not1683if (Postpone && !GR->findAssignPtrTypeInstr(I))1684insertAssignPtrTypeIntrs(I, B, true);1685}16861687for (auto &I : instructions(Func))1688deduceOperandElementType(&I);16891690for (auto *I : Worklist) {1691TrackConstants = true;1692if (!I->getType()->isVoidTy() || isa<StoreInst>(I))1693setInsertPointAfterDef(B, I);1694// Visitors return either the original/newly created instruction for further1695// processing, nullptr otherwise.1696I = visit(*I);1697if (!I)1698continue;16991700// Don't emit intrinsics for convergence operations.1701if (isConvergenceIntrinsic(I))1702continue;17031704processInstrAfterVisit(I, B);1705}17061707return true;1708}17091710// Try to deduce a better type for pointers to untyped ptr.1711bool SPIRVEmitIntrinsics::postprocessTypes() {1712bool Changed = false;1713if (!GR)1714return Changed;1715for (auto IB = PostprocessWorklist.rbegin(), IE = PostprocessWorklist.rend();1716IB != IE; ++IB) {1717CallInst *AssignCI = GR->findAssignPtrTypeInstr(*IB);1718Type *KnownTy = GR->findDeducedElementType(*IB);1719if (!KnownTy || !AssignCI || !isa<Instruction>(AssignCI->getArgOperand(0)))1720continue;1721Instruction *I = cast<Instruction>(AssignCI->getArgOperand(0));1722for (User *U : I->users()) {1723Instruction *Inst = dyn_cast<Instruction>(U);1724if (!Inst || isa<IntrinsicInst>(Inst))1725continue;1726deduceOperandElementType(Inst, I, KnownTy, AssignCI);1727if (KnownTy != GR->findDeducedElementType(I)) {1728Changed = true;1729break;1730}1731}1732}1733return Changed;1734}17351736bool SPIRVEmitIntrinsics::runOnModule(Module &M) {1737bool Changed = false;17381739UncompleteTypeInfo.clear();1740PostprocessWorklist.clear();1741for (auto &F : M)1742Changed |= runOnFunction(F);17431744for (auto &F : M) {1745// check if function parameter types are set1746if (!F.isDeclaration() && !F.isIntrinsic()) {1747const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(F);1748GR = ST.getSPIRVGlobalRegistry();1749IRBuilder<> B(F.getContext());1750processParamTypes(&F, B);1751}1752}17531754Changed |= postprocessTypes();17551756return Changed;1757}17581759ModulePass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) {1760return new SPIRVEmitIntrinsics(TM);1761}176217631764