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 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 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; 149*0fca6ea1SDimitry Andric SPIRVEmitIntrinsics() : ModulePass(ID) { 15081ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 15181ad6265SDimitry Andric } 152*0fca6ea1SDimitry Andric SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : ModulePass(ID), TM(_TM) { 15381ad6265SDimitry Andric initializeSPIRVEmitIntrinsicsPass(*PassRegistry::getPassRegistry()); 15481ad6265SDimitry Andric } 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 170*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 176*0fca6ea1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 177*0fca6ea1SDimitry Andric ModulePass::getAnalysisUsage(AU); 178*0fca6ea1SDimitry Andric } 17981ad6265SDimitry Andric }; 180*0fca6ea1SDimitry Andric 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 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 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 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 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 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 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 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 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. 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. 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 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 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 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 * 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 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. 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 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. 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 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 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. 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 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 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 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. 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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. 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 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 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 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 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 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 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 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 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. 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 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 1760*0fca6ea1SDimitry Andric ModulePass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) { 176181ad6265SDimitry Andric return new SPIRVEmitIntrinsics(TM); 176281ad6265SDimitry Andric } 1763