3084 lines · cpp
1//===-- SPIRVEmitIntrinsics.cpp - emit SPIRV intrinsics ---------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// The pass emits SPIRV intrinsics keeping essential high-level information for10// the translation of LLVM IR to SPIR-V.11//12//===----------------------------------------------------------------------===//13 14#include "SPIRV.h"15#include "SPIRVBuiltins.h"16#include "SPIRVSubtarget.h"17#include "SPIRVTargetMachine.h"18#include "SPIRVUtils.h"19#include "llvm/ADT/DenseSet.h"20#include "llvm/ADT/StringSet.h"21#include "llvm/IR/IRBuilder.h"22#include "llvm/IR/InstIterator.h"23#include "llvm/IR/InstVisitor.h"24#include "llvm/IR/IntrinsicsSPIRV.h"25#include "llvm/IR/PatternMatch.h"26#include "llvm/IR/TypedPointerType.h"27#include "llvm/Transforms/Utils/Local.h"28 29#include <cassert>30#include <queue>31#include <unordered_set>32 33// This pass performs the following transformation on LLVM IR level required34// for the following translation to SPIR-V:35// - replaces direct usages of aggregate constants with target-specific36// intrinsics;37// - replaces aggregates-related instructions (extract/insert, ld/st, etc)38// with a target-specific intrinsics;39// - emits intrinsics for the global variable initializers since IRTranslator40// doesn't handle them and it's not very convenient to translate them41// ourselves;42// - emits intrinsics to keep track of the string names assigned to the values;43// - emits intrinsics to keep track of constants (this is necessary to have an44// LLVM IR constant after the IRTranslation is completed) for their further45// deduplication;46// - emits intrinsics to keep track of original LLVM types of the values47// to be able to emit proper SPIR-V types eventually.48//49// TODO: consider removing spv.track.constant in favor of spv.assign.type.50 51using namespace llvm;52 53namespace llvm::SPIRV {54#define GET_BuiltinGroup_DECL55#include "SPIRVGenTables.inc"56} // namespace llvm::SPIRV57 58namespace {59 60class SPIRVEmitIntrinsics61 : public ModulePass,62 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {63 SPIRVTargetMachine *TM = nullptr;64 SPIRVGlobalRegistry *GR = nullptr;65 Function *CurrF = nullptr;66 bool TrackConstants = true;67 bool HaveFunPtrs = false;68 DenseMap<Instruction *, Constant *> AggrConsts;69 DenseMap<Instruction *, Type *> AggrConstTypes;70 DenseSet<Instruction *> AggrStores;71 std::unordered_set<Value *> Named;72 73 // map of function declarations to <pointer arg index => element type>74 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;75 76 // a register of Instructions that don't have a complete type definition77 bool CanTodoType = true;78 unsigned TodoTypeSz = 0;79 DenseMap<Value *, bool> TodoType;80 void insertTodoType(Value *Op) {81 // TODO: add isa<CallInst>(Op) to no-insert82 if (CanTodoType && !isa<GetElementPtrInst>(Op)) {83 auto It = TodoType.try_emplace(Op, true);84 if (It.second)85 ++TodoTypeSz;86 }87 }88 void eraseTodoType(Value *Op) {89 auto It = TodoType.find(Op);90 if (It != TodoType.end() && It->second) {91 It->second = false;92 --TodoTypeSz;93 }94 }95 bool isTodoType(Value *Op) {96 if (isa<GetElementPtrInst>(Op))97 return false;98 auto It = TodoType.find(Op);99 return It != TodoType.end() && It->second;100 }101 // a register of Instructions that were visited by deduceOperandElementType()102 // to validate operand types with an instruction103 std::unordered_set<Instruction *> TypeValidated;104 105 // well known result types of builtins106 enum WellKnownTypes { Event };107 108 // deduce element type of untyped pointers109 Type *deduceElementType(Value *I, bool UnknownElemTypeI8);110 Type *deduceElementTypeHelper(Value *I, bool UnknownElemTypeI8);111 Type *deduceElementTypeHelper(Value *I, std::unordered_set<Value *> &Visited,112 bool UnknownElemTypeI8,113 bool IgnoreKnownType = false);114 Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,115 bool UnknownElemTypeI8);116 Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,117 std::unordered_set<Value *> &Visited,118 bool UnknownElemTypeI8);119 Type *deduceElementTypeByUsersDeep(Value *Op,120 std::unordered_set<Value *> &Visited,121 bool UnknownElemTypeI8);122 void maybeAssignPtrType(Type *&Ty, Value *I, Type *RefTy,123 bool UnknownElemTypeI8);124 125 // deduce nested types of composites126 Type *deduceNestedTypeHelper(User *U, bool UnknownElemTypeI8);127 Type *deduceNestedTypeHelper(User *U, Type *Ty,128 std::unordered_set<Value *> &Visited,129 bool UnknownElemTypeI8);130 131 // deduce Types of operands of the Instruction if possible132 void deduceOperandElementType(Instruction *I,133 SmallPtrSet<Instruction *, 4> *IncompleteRets,134 const SmallPtrSet<Value *, 4> *AskOps = nullptr,135 bool IsPostprocessing = false);136 137 void preprocessCompositeConstants(IRBuilder<> &B);138 void preprocessUndefs(IRBuilder<> &B);139 140 Type *reconstructType(Value *Op, bool UnknownElemTypeI8,141 bool IsPostprocessing);142 143 void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);144 void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);145 bool insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B,146 bool UnknownElemTypeI8);147 void insertAssignTypeIntrs(Instruction *I, IRBuilder<> &B);148 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType, Value *V,149 IRBuilder<> &B);150 void replacePointerOperandWithPtrCast(Instruction *I, Value *Pointer,151 Type *ExpectedElementType,152 unsigned OperandToReplace,153 IRBuilder<> &B);154 void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);155 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);156 void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);157 void insertConstantsForFPFastMathDefault(Module &M);158 void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);159 void processParamTypes(Function *F, IRBuilder<> &B);160 void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);161 Type *deduceFunParamElementType(Function *F, unsigned OpIdx);162 Type *deduceFunParamElementType(Function *F, unsigned OpIdx,163 std::unordered_set<Function *> &FVisited);164 165 bool deduceOperandElementTypeCalledFunction(166 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,167 Type *&KnownElemTy, bool &Incomplete);168 void deduceOperandElementTypeFunctionPointer(169 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,170 Type *&KnownElemTy, bool IsPostprocessing);171 bool deduceOperandElementTypeFunctionRet(172 Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,173 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,174 Type *&KnownElemTy, Value *Op, Function *F);175 176 CallInst *buildSpvPtrcast(Function *F, Value *Op, Type *ElemTy);177 void replaceUsesOfWithSpvPtrcast(Value *Op, Type *ElemTy, Instruction *I,178 DenseMap<Function *, CallInst *> Ptrcasts);179 void propagateElemType(Value *Op, Type *ElemTy,180 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);181 void182 propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,183 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);184 void propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,185 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,186 std::unordered_set<Value *> &Visited,187 DenseMap<Function *, CallInst *> Ptrcasts);188 189 void replaceAllUsesWith(Value *Src, Value *Dest, bool DeleteOld = true);190 void replaceAllUsesWithAndErase(IRBuilder<> &B, Instruction *Src,191 Instruction *Dest, bool DeleteOld = true);192 193 void applyDemangledPtrArgTypes(IRBuilder<> &B);194 195 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP);196 197 bool runOnFunction(Function &F);198 bool postprocessTypes(Module &M);199 bool processFunctionPointers(Module &M);200 void parseFunDeclarations(Module &M);201 202 void useRoundingMode(ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);203 204 // Tries to walk the type accessed by the given GEP instruction.205 // For each nested type access, one of the 2 callbacks is called:206 // - OnLiteralIndexing when the index is a known constant value.207 // Parameters:208 // PointedType: the pointed type resulting of this indexing.209 // If the parent type is an array, this is the index in the array.210 // If the parent type is a struct, this is the field index.211 // Index: index of the element in the parent type.212 // - OnDynamnicIndexing when the index is a non-constant value.213 // This callback is only called when indexing into an array.214 // Parameters:215 // ElementType: the type of the elements stored in the parent array.216 // Offset: the Value* containing the byte offset into the array.217 // Return true if an error occured during the walk, false otherwise.218 bool walkLogicalAccessChain(219 GetElementPtrInst &GEP,220 const std::function<void(Type *PointedType, uint64_t Index)>221 &OnLiteralIndexing,222 const std::function<void(Type *ElementType, Value *Offset)>223 &OnDynamicIndexing);224 225 // Returns the type accessed using the given GEP instruction by relying226 // on the GEP type.227 // FIXME: GEP types are not supposed to be used to retrieve the pointed228 // type. This must be fixed.229 Type *getGEPType(GetElementPtrInst *GEP);230 231 // Returns the type accessed using the given GEP instruction by walking232 // the source type using the GEP indices.233 // FIXME: without help from the frontend, this method cannot reliably retrieve234 // the stored type, nor can robustly determine the depth of the type235 // we are accessing.236 Type *getGEPTypeLogical(GetElementPtrInst *GEP);237 238 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &GEP);239 240public:241 static char ID;242 SPIRVEmitIntrinsics(SPIRVTargetMachine *TM = nullptr)243 : ModulePass(ID), TM(TM) {}244 Instruction *visitInstruction(Instruction &I) { return &I; }245 Instruction *visitSwitchInst(SwitchInst &I);246 Instruction *visitGetElementPtrInst(GetElementPtrInst &I);247 Instruction *visitBitCastInst(BitCastInst &I);248 Instruction *visitInsertElementInst(InsertElementInst &I);249 Instruction *visitExtractElementInst(ExtractElementInst &I);250 Instruction *visitInsertValueInst(InsertValueInst &I);251 Instruction *visitExtractValueInst(ExtractValueInst &I);252 Instruction *visitLoadInst(LoadInst &I);253 Instruction *visitStoreInst(StoreInst &I);254 Instruction *visitAllocaInst(AllocaInst &I);255 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);256 Instruction *visitUnreachableInst(UnreachableInst &I);257 Instruction *visitCallInst(CallInst &I);258 259 StringRef getPassName() const override { return "SPIRV emit intrinsics"; }260 261 bool runOnModule(Module &M) override;262 263 void getAnalysisUsage(AnalysisUsage &AU) const override {264 ModulePass::getAnalysisUsage(AU);265 }266};267 268bool isConvergenceIntrinsic(const Instruction *I) {269 const auto *II = dyn_cast<IntrinsicInst>(I);270 if (!II)271 return false;272 273 return II->getIntrinsicID() == Intrinsic::experimental_convergence_entry ||274 II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||275 II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor;276}277 278bool expectIgnoredInIRTranslation(const Instruction *I) {279 const auto *II = dyn_cast<IntrinsicInst>(I);280 if (!II)281 return false;282 switch (II->getIntrinsicID()) {283 case Intrinsic::invariant_start:284 case Intrinsic::spv_resource_handlefrombinding:285 case Intrinsic::spv_resource_getpointer:286 return true;287 default:288 return false;289 }290}291 292// Returns the source pointer from `I` ignoring intermediate ptrcast.293Value *getPointerRoot(Value *I) {294 if (auto *II = dyn_cast<IntrinsicInst>(I)) {295 if (II->getIntrinsicID() == Intrinsic::spv_ptrcast) {296 Value *V = II->getArgOperand(0);297 return getPointerRoot(V);298 }299 }300 return I;301}302 303} // namespace304 305char SPIRVEmitIntrinsics::ID = 0;306 307INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics",308 false, false)309 310static inline bool isAssignTypeInstr(const Instruction *I) {311 return isa<IntrinsicInst>(I) &&312 cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type;313}314 315static bool isMemInstrToReplace(Instruction *I) {316 return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) ||317 isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I);318}319 320static bool isAggrConstForceInt32(const Value *V) {321 return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||322 isa<ConstantDataArray>(V) ||323 (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());324}325 326static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {327 if (isa<PHINode>(I))328 B.SetInsertPoint(I->getParent()->getFirstNonPHIOrDbgOrAlloca());329 else330 B.SetInsertPoint(I);331}332 333static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I) {334 B.SetCurrentDebugLocation(I->getDebugLoc());335 if (I->getType()->isVoidTy())336 B.SetInsertPoint(I->getNextNode());337 else338 B.SetInsertPoint(*I->getInsertionPointAfterDef());339}340 341static bool requireAssignType(Instruction *I) {342 if (const auto *Intr = dyn_cast<IntrinsicInst>(I)) {343 switch (Intr->getIntrinsicID()) {344 case Intrinsic::invariant_start:345 case Intrinsic::invariant_end:346 return false;347 }348 }349 return true;350}351 352static inline void reportFatalOnTokenType(const Instruction *I) {353 if (I->getType()->isTokenTy())354 report_fatal_error("A token is encountered but SPIR-V without extensions "355 "does not support token type",356 false);357}358 359static void emitAssignName(Instruction *I, IRBuilder<> &B) {360 if (!I->hasName() || I->getType()->isAggregateType() ||361 expectIgnoredInIRTranslation(I))362 return;363 reportFatalOnTokenType(I);364 setInsertPointAfterDef(B, I);365 LLVMContext &Ctx = I->getContext();366 std::vector<Value *> Args = {367 I, MetadataAsValue::get(368 Ctx, MDNode::get(Ctx, MDString::get(Ctx, I->getName())))};369 B.CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);370}371 372void SPIRVEmitIntrinsics::replaceAllUsesWith(Value *Src, Value *Dest,373 bool DeleteOld) {374 GR->replaceAllUsesWith(Src, Dest, DeleteOld);375 // Update uncomplete type records if any376 if (isTodoType(Src)) {377 if (DeleteOld)378 eraseTodoType(Src);379 insertTodoType(Dest);380 }381}382 383void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(IRBuilder<> &B,384 Instruction *Src,385 Instruction *Dest,386 bool DeleteOld) {387 replaceAllUsesWith(Src, Dest, DeleteOld);388 std::string Name = Src->hasName() ? Src->getName().str() : "";389 Src->eraseFromParent();390 if (!Name.empty()) {391 Dest->setName(Name);392 if (Named.insert(Dest).second)393 emitAssignName(Dest, B);394 }395}396 397static bool IsKernelArgInt8(Function *F, StoreInst *SI) {398 return SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&399 isPointerTy(SI->getValueOperand()->getType()) &&400 isa<Argument>(SI->getValueOperand());401}402 403// Maybe restore original function return type.404static inline Type *restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I,405 Type *Ty) {406 CallInst *CI = dyn_cast<CallInst>(I);407 if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||408 !CI->getCalledFunction() || CI->getCalledFunction()->isIntrinsic())409 return Ty;410 if (Type *OriginalTy = GR->findMutated(CI->getCalledFunction()))411 return OriginalTy;412 return Ty;413}414 415// Reconstruct type with nested element types according to deduced type info.416// Return nullptr if no detailed type info is available.417Type *SPIRVEmitIntrinsics::reconstructType(Value *Op, bool UnknownElemTypeI8,418 bool IsPostprocessing) {419 Type *Ty = Op->getType();420 if (auto *OpI = dyn_cast<Instruction>(Op))421 Ty = restoreMutatedType(GR, OpI, Ty);422 if (!isUntypedPointerTy(Ty))423 return Ty;424 // try to find the pointee type425 if (Type *NestedTy = GR->findDeducedElementType(Op))426 return getTypedPointerWrapper(NestedTy, getPointerAddressSpace(Ty));427 // not a pointer according to the type info (e.g., Event object)428 CallInst *CI = GR->findAssignPtrTypeInstr(Op);429 if (CI) {430 MetadataAsValue *MD = cast<MetadataAsValue>(CI->getArgOperand(1));431 return cast<ConstantAsMetadata>(MD->getMetadata())->getType();432 }433 if (UnknownElemTypeI8) {434 if (!IsPostprocessing)435 insertTodoType(Op);436 return getTypedPointerWrapper(IntegerType::getInt8Ty(Op->getContext()),437 getPointerAddressSpace(Ty));438 }439 return nullptr;440}441 442CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,443 Type *ElemTy) {444 IRBuilder<> B(Op->getContext());445 if (auto *OpI = dyn_cast<Instruction>(Op)) {446 // spv_ptrcast's argument Op denotes an instruction that generates447 // a value, and we may use getInsertionPointAfterDef()448 setInsertPointAfterDef(B, OpI);449 } else if (auto *OpA = dyn_cast<Argument>(Op)) {450 B.SetInsertPointPastAllocas(OpA->getParent());451 B.SetCurrentDebugLocation(DebugLoc());452 } else {453 B.SetInsertPoint(F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());454 }455 Type *OpTy = Op->getType();456 SmallVector<Type *, 2> Types = {OpTy, OpTy};457 SmallVector<Value *, 2> Args = {Op, buildMD(getNormalizedPoisonValue(ElemTy)),458 B.getInt32(getPointerAddressSpace(OpTy))};459 CallInst *PtrCasted =460 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);461 GR->buildAssignPtr(B, ElemTy, PtrCasted);462 return PtrCasted;463}464 465void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(466 Value *Op, Type *ElemTy, Instruction *I,467 DenseMap<Function *, CallInst *> Ptrcasts) {468 Function *F = I->getParent()->getParent();469 CallInst *PtrCastedI = nullptr;470 auto It = Ptrcasts.find(F);471 if (It == Ptrcasts.end()) {472 PtrCastedI = buildSpvPtrcast(F, Op, ElemTy);473 Ptrcasts[F] = PtrCastedI;474 } else {475 PtrCastedI = It->second;476 }477 I->replaceUsesOfWith(Op, PtrCastedI);478}479 480void SPIRVEmitIntrinsics::propagateElemType(481 Value *Op, Type *ElemTy,482 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {483 DenseMap<Function *, CallInst *> Ptrcasts;484 SmallVector<User *> Users(Op->users());485 for (auto *U : Users) {486 if (!isa<Instruction>(U) || isSpvIntrinsic(U))487 continue;488 if (!VisitedSubst.insert(std::make_pair(U, Op)).second)489 continue;490 Instruction *UI = dyn_cast<Instruction>(U);491 // If the instruction was validated already, we need to keep it valid by492 // keeping current Op type.493 if (isa<GetElementPtrInst>(UI) ||494 TypeValidated.find(UI) != TypeValidated.end())495 replaceUsesOfWithSpvPtrcast(Op, ElemTy, UI, Ptrcasts);496 }497}498 499void SPIRVEmitIntrinsics::propagateElemTypeRec(500 Value *Op, Type *PtrElemTy, Type *CastElemTy,501 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {502 std::unordered_set<Value *> Visited;503 DenseMap<Function *, CallInst *> Ptrcasts;504 propagateElemTypeRec(Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,505 std::move(Ptrcasts));506}507 508void SPIRVEmitIntrinsics::propagateElemTypeRec(509 Value *Op, Type *PtrElemTy, Type *CastElemTy,510 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,511 std::unordered_set<Value *> &Visited,512 DenseMap<Function *, CallInst *> Ptrcasts) {513 if (!Visited.insert(Op).second)514 return;515 SmallVector<User *> Users(Op->users());516 for (auto *U : Users) {517 if (!isa<Instruction>(U) || isSpvIntrinsic(U))518 continue;519 if (!VisitedSubst.insert(std::make_pair(U, Op)).second)520 continue;521 Instruction *UI = dyn_cast<Instruction>(U);522 // If the instruction was validated already, we need to keep it valid by523 // keeping current Op type.524 if (isa<GetElementPtrInst>(UI) ||525 TypeValidated.find(UI) != TypeValidated.end())526 replaceUsesOfWithSpvPtrcast(Op, CastElemTy, UI, Ptrcasts);527 }528}529 530// Set element pointer type to the given value of ValueTy and tries to531// specify this type further (recursively) by Operand value, if needed.532 533Type *534SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,535 bool UnknownElemTypeI8) {536 std::unordered_set<Value *> Visited;537 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,538 UnknownElemTypeI8);539}540 541Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(542 Type *ValueTy, Value *Operand, std::unordered_set<Value *> &Visited,543 bool UnknownElemTypeI8) {544 Type *Ty = ValueTy;545 if (Operand) {546 if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {547 if (Type *NestedTy =548 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))549 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());550 } else {551 Ty = deduceNestedTypeHelper(dyn_cast<User>(Operand), Ty, Visited,552 UnknownElemTypeI8);553 }554 }555 return Ty;556}557 558// Traverse User instructions to deduce an element pointer type of the operand.559Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(560 Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {561 if (!Op || !isPointerTy(Op->getType()) || isa<ConstantPointerNull>(Op) ||562 isa<UndefValue>(Op))563 return nullptr;564 565 if (auto ElemTy = getPointeeType(Op->getType()))566 return ElemTy;567 568 // maybe we already know operand's element type569 if (Type *KnownTy = GR->findDeducedElementType(Op))570 return KnownTy;571 572 for (User *OpU : Op->users()) {573 if (Instruction *Inst = dyn_cast<Instruction>(OpU)) {574 if (Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))575 return Ty;576 }577 }578 return nullptr;579}580 581// Implements what we know in advance about intrinsics and builtin calls582// TODO: consider feasibility of this particular case to be generalized by583// encoding knowledge about intrinsics and builtin calls by corresponding584// specification rules585static Type *getPointeeTypeByCallInst(StringRef DemangledName,586 Function *CalledF, unsigned OpIdx) {587 if ((DemangledName.starts_with("__spirv_ocl_printf(") ||588 DemangledName.starts_with("printf(")) &&589 OpIdx == 0)590 return IntegerType::getInt8Ty(CalledF->getContext());591 return nullptr;592}593 594// Deduce and return a successfully deduced Type of the Instruction,595// or nullptr otherwise.596Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,597 bool UnknownElemTypeI8) {598 std::unordered_set<Value *> Visited;599 return deduceElementTypeHelper(I, Visited, UnknownElemTypeI8);600}601 602void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,603 bool UnknownElemTypeI8) {604 if (isUntypedPointerTy(RefTy)) {605 if (!UnknownElemTypeI8)606 return;607 insertTodoType(Op);608 }609 Ty = RefTy;610}611 612bool SPIRVEmitIntrinsics::walkLogicalAccessChain(613 GetElementPtrInst &GEP,614 const std::function<void(Type *, uint64_t)> &OnLiteralIndexing,615 const std::function<void(Type *, Value *)> &OnDynamicIndexing) {616 // We only rewrite i8* GEP. Other should be left as-is.617 // Valid i8* GEP must always have a single index.618 assert(GEP.getSourceElementType() ==619 IntegerType::getInt8Ty(CurrF->getContext()));620 assert(GEP.getNumIndices() == 1);621 622 auto &DL = CurrF->getDataLayout();623 Value *Src = getPointerRoot(GEP.getPointerOperand());624 Type *CurType = deduceElementType(Src, true);625 626 Value *Operand = *GEP.idx_begin();627 ConstantInt *CI = dyn_cast<ConstantInt>(Operand);628 if (!CI) {629 ArrayType *AT = dyn_cast<ArrayType>(CurType);630 // Operand is not constant. Either we have an array and accept it, or we631 // give up.632 if (AT)633 OnDynamicIndexing(AT->getElementType(), Operand);634 return AT == nullptr;635 }636 637 assert(CI);638 uint64_t Offset = CI->getZExtValue();639 640 do {641 if (ArrayType *AT = dyn_cast<ArrayType>(CurType)) {642 uint32_t EltTypeSize = DL.getTypeSizeInBits(AT->getElementType()) / 8;643 assert(Offset < AT->getNumElements() * EltTypeSize);644 uint64_t Index = Offset / EltTypeSize;645 Offset = Offset - (Index * EltTypeSize);646 CurType = AT->getElementType();647 OnLiteralIndexing(CurType, Index);648 } else if (StructType *ST = dyn_cast<StructType>(CurType)) {649 uint32_t StructSize = DL.getTypeSizeInBits(ST) / 8;650 assert(Offset < StructSize);651 (void)StructSize;652 const auto &STL = DL.getStructLayout(ST);653 unsigned Element = STL->getElementContainingOffset(Offset);654 Offset -= STL->getElementOffset(Element);655 CurType = ST->getElementType(Element);656 OnLiteralIndexing(CurType, Element);657 } else {658 // Vector type indexing should not use GEP.659 // So if we have an index left, something is wrong. Giving up.660 return true;661 }662 } while (Offset > 0);663 664 return false;665}666 667Instruction *668SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &GEP) {669 auto &DL = CurrF->getDataLayout();670 IRBuilder<> B(GEP.getParent());671 B.SetInsertPoint(&GEP);672 673 std::vector<Value *> Indices;674 Indices.push_back(ConstantInt::get(675 IntegerType::getInt32Ty(CurrF->getContext()), 0, /* Signed= */ false));676 walkLogicalAccessChain(677 GEP,678 [&Indices, &B](Type *EltType, uint64_t Index) {679 Indices.push_back(680 ConstantInt::get(B.getInt64Ty(), Index, /* Signed= */ false));681 },682 [&Indices, &B, &DL](Type *EltType, Value *Offset) {683 uint32_t EltTypeSize = DL.getTypeSizeInBits(EltType) / 8;684 Value *Index = B.CreateUDiv(685 Offset, ConstantInt::get(Offset->getType(), EltTypeSize,686 /* Signed= */ false));687 Indices.push_back(Index);688 });689 690 SmallVector<Type *, 2> Types = {GEP.getType(), GEP.getOperand(0)->getType()};691 SmallVector<Value *, 4> Args;692 Args.push_back(B.getInt1(GEP.isInBounds()));693 Args.push_back(GEP.getOperand(0));694 llvm::append_range(Args, Indices);695 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});696 replaceAllUsesWithAndErase(B, &GEP, NewI);697 return NewI;698}699 700Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *GEP) {701 702 Type *CurType = GEP->getResultElementType();703 704 bool Interrupted = walkLogicalAccessChain(705 *GEP, [&CurType](Type *EltType, uint64_t Index) { CurType = EltType; },706 [&CurType](Type *EltType, Value *Index) { CurType = EltType; });707 708 return Interrupted ? GEP->getResultElementType() : CurType;709}710 711Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *Ref) {712 if (Ref->getSourceElementType() ==713 IntegerType::getInt8Ty(CurrF->getContext()) &&714 TM->getSubtargetImpl()->isLogicalSPIRV()) {715 return getGEPTypeLogical(Ref);716 }717 718 Type *Ty = nullptr;719 // TODO: not sure if GetElementPtrInst::getTypeAtIndex() does anything720 // useful here721 if (isNestedPointer(Ref->getSourceElementType())) {722 Ty = Ref->getSourceElementType();723 for (Use &U : drop_begin(Ref->indices()))724 Ty = GetElementPtrInst::getTypeAtIndex(Ty, U.get());725 } else {726 Ty = Ref->getResultElementType();727 }728 return Ty;729}730 731Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(732 Value *I, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8,733 bool IgnoreKnownType) {734 // allow to pass nullptr as an argument735 if (!I)736 return nullptr;737 738 // maybe already known739 if (!IgnoreKnownType)740 if (Type *KnownTy = GR->findDeducedElementType(I))741 return KnownTy;742 743 // maybe a cycle744 if (!Visited.insert(I).second)745 return nullptr;746 747 // fallback value in case when we fail to deduce a type748 Type *Ty = nullptr;749 // look for known basic patterns of type inference750 if (auto *Ref = dyn_cast<AllocaInst>(I)) {751 maybeAssignPtrType(Ty, I, Ref->getAllocatedType(), UnknownElemTypeI8);752 } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {753 Ty = getGEPType(Ref);754 } else if (auto *Ref = dyn_cast<LoadInst>(I)) {755 Value *Op = Ref->getPointerOperand();756 Type *KnownTy = GR->findDeducedElementType(Op);757 if (!KnownTy)758 KnownTy = Op->getType();759 if (Type *ElemTy = getPointeeType(KnownTy))760 maybeAssignPtrType(Ty, I, ElemTy, UnknownElemTypeI8);761 } else if (auto *Ref = dyn_cast<GlobalValue>(I)) {762 Ty = deduceElementTypeByValueDeep(763 Ref->getValueType(),764 Ref->getNumOperands() > 0 ? Ref->getOperand(0) : nullptr, Visited,765 UnknownElemTypeI8);766 } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {767 Type *RefTy = deduceElementTypeHelper(Ref->getPointerOperand(), Visited,768 UnknownElemTypeI8);769 maybeAssignPtrType(Ty, I, RefTy, UnknownElemTypeI8);770 } else if (auto *Ref = dyn_cast<IntToPtrInst>(I)) {771 maybeAssignPtrType(Ty, I, Ref->getDestTy(), UnknownElemTypeI8);772 } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {773 if (Type *Src = Ref->getSrcTy(), *Dest = Ref->getDestTy();774 isPointerTy(Src) && isPointerTy(Dest))775 Ty = deduceElementTypeHelper(Ref->getOperand(0), Visited,776 UnknownElemTypeI8);777 } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {778 Value *Op = Ref->getNewValOperand();779 if (isPointerTy(Op->getType()))780 Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);781 } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {782 Value *Op = Ref->getValOperand();783 if (isPointerTy(Op->getType()))784 Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);785 } else if (auto *Ref = dyn_cast<PHINode>(I)) {786 Type *BestTy = nullptr;787 unsigned MaxN = 1;788 DenseMap<Type *, unsigned> PhiTys;789 for (int i = Ref->getNumIncomingValues() - 1; i >= 0; --i) {790 Ty = deduceElementTypeByUsersDeep(Ref->getIncomingValue(i), Visited,791 UnknownElemTypeI8);792 if (!Ty)793 continue;794 auto It = PhiTys.try_emplace(Ty, 1);795 if (!It.second) {796 ++It.first->second;797 if (It.first->second > MaxN) {798 MaxN = It.first->second;799 BestTy = Ty;800 }801 }802 }803 if (BestTy)804 Ty = BestTy;805 } else if (auto *Ref = dyn_cast<SelectInst>(I)) {806 for (Value *Op : {Ref->getTrueValue(), Ref->getFalseValue()}) {807 Ty = deduceElementTypeByUsersDeep(Op, Visited, UnknownElemTypeI8);808 if (Ty)809 break;810 }811 } else if (auto *CI = dyn_cast<CallInst>(I)) {812 static StringMap<unsigned> ResTypeByArg = {813 {"to_global", 0},814 {"to_local", 0},815 {"to_private", 0},816 {"__spirv_GenericCastToPtr_ToGlobal", 0},817 {"__spirv_GenericCastToPtr_ToLocal", 0},818 {"__spirv_GenericCastToPtr_ToPrivate", 0},819 {"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},820 {"__spirv_GenericCastToPtrExplicit_ToLocal", 0},821 {"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};822 // TODO: maybe improve performance by caching demangled names823 824 auto *II = dyn_cast<IntrinsicInst>(I);825 if (II && II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {826 auto *HandleType = cast<TargetExtType>(II->getOperand(0)->getType());827 if (HandleType->getTargetExtName() == "spirv.Image" ||828 HandleType->getTargetExtName() == "spirv.SignedImage") {829 for (User *U : II->users()) {830 Ty = cast<Instruction>(U)->getAccessType();831 if (Ty)832 break;833 }834 } else if (HandleType->getTargetExtName() == "spirv.VulkanBuffer") {835 // This call is supposed to index into an array836 Ty = HandleType->getTypeParameter(0);837 if (Ty->isArrayTy())838 Ty = Ty->getArrayElementType();839 else {840 assert(Ty && Ty->isStructTy());841 uint32_t Index = cast<ConstantInt>(II->getOperand(1))->getZExtValue();842 Ty = cast<StructType>(Ty)->getElementType(Index);843 }844 Ty = reconstitutePeeledArrayType(Ty);845 } else {846 llvm_unreachable("Unknown handle type for spv_resource_getpointer.");847 }848 } else if (II && II->getIntrinsicID() ==849 Intrinsic::spv_generic_cast_to_ptr_explicit) {850 Ty = deduceElementTypeHelper(CI->getArgOperand(0), Visited,851 UnknownElemTypeI8);852 } else if (Function *CalledF = CI->getCalledFunction()) {853 std::string DemangledName =854 getOclOrSpirvBuiltinDemangledName(CalledF->getName());855 if (DemangledName.length() > 0)856 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);857 auto AsArgIt = ResTypeByArg.find(DemangledName);858 if (AsArgIt != ResTypeByArg.end())859 Ty = deduceElementTypeHelper(CI->getArgOperand(AsArgIt->second),860 Visited, UnknownElemTypeI8);861 else if (Type *KnownRetTy = GR->findDeducedElementType(CalledF))862 Ty = KnownRetTy;863 }864 }865 866 // remember the found relationship867 if (Ty && !IgnoreKnownType) {868 // specify nested types if needed, otherwise return unchanged869 GR->addDeducedElementType(I, normalizeType(Ty));870 }871 872 return Ty;873}874 875// Re-create a type of the value if it has untyped pointer fields, also nested.876// Return the original value type if no corrections of untyped pointer877// information is found or needed.878Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,879 bool UnknownElemTypeI8) {880 std::unordered_set<Value *> Visited;881 return deduceNestedTypeHelper(U, U->getType(), Visited, UnknownElemTypeI8);882}883 884Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(885 User *U, Type *OrigTy, std::unordered_set<Value *> &Visited,886 bool UnknownElemTypeI8) {887 if (!U)888 return OrigTy;889 890 // maybe already known891 if (Type *KnownTy = GR->findDeducedCompositeType(U))892 return KnownTy;893 894 // maybe a cycle895 if (!Visited.insert(U).second)896 return OrigTy;897 898 if (isa<StructType>(OrigTy)) {899 SmallVector<Type *> Tys;900 bool Change = false;901 for (unsigned i = 0; i < U->getNumOperands(); ++i) {902 Value *Op = U->getOperand(i);903 assert(Op && "Operands should not be null.");904 Type *OpTy = Op->getType();905 Type *Ty = OpTy;906 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {907 if (Type *NestedTy =908 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))909 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());910 } else {911 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,912 UnknownElemTypeI8);913 }914 Tys.push_back(Ty);915 Change |= Ty != OpTy;916 }917 if (Change) {918 Type *NewTy = StructType::create(Tys);919 GR->addDeducedCompositeType(U, NewTy);920 return NewTy;921 }922 } else if (auto *ArrTy = dyn_cast<ArrayType>(OrigTy)) {923 if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {924 Type *OpTy = ArrTy->getElementType();925 Type *Ty = OpTy;926 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {927 if (Type *NestedTy =928 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))929 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());930 } else {931 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,932 UnknownElemTypeI8);933 }934 if (Ty != OpTy) {935 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());936 GR->addDeducedCompositeType(U, NewTy);937 return NewTy;938 }939 }940 } else if (auto *VecTy = dyn_cast<VectorType>(OrigTy)) {941 if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {942 Type *OpTy = VecTy->getElementType();943 Type *Ty = OpTy;944 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {945 if (Type *NestedTy =946 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))947 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());948 } else {949 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,950 UnknownElemTypeI8);951 }952 if (Ty != OpTy) {953 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());954 GR->addDeducedCompositeType(U, normalizeType(NewTy));955 return NewTy;956 }957 }958 }959 960 return OrigTy;961}962 963Type *SPIRVEmitIntrinsics::deduceElementType(Value *I, bool UnknownElemTypeI8) {964 if (Type *Ty = deduceElementTypeHelper(I, UnknownElemTypeI8))965 return Ty;966 if (!UnknownElemTypeI8)967 return nullptr;968 insertTodoType(I);969 return IntegerType::getInt8Ty(I->getContext());970}971 972static inline Type *getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I,973 Value *PointerOperand) {974 Type *PointeeTy = GR->findDeducedElementType(PointerOperand);975 if (PointeeTy && !isUntypedPointerTy(PointeeTy))976 return nullptr;977 auto *PtrTy = dyn_cast<PointerType>(I->getType());978 if (!PtrTy)979 return I->getType();980 if (Type *NestedTy = GR->findDeducedElementType(I))981 return getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());982 return nullptr;983}984 985// Try to deduce element type for a call base. Returns false if this is an986// indirect function invocation, and true otherwise.987bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(988 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,989 Type *&KnownElemTy, bool &Incomplete) {990 Function *CalledF = CI->getCalledFunction();991 if (!CalledF)992 return false;993 std::string DemangledName =994 getOclOrSpirvBuiltinDemangledName(CalledF->getName());995 if (DemangledName.length() > 0 &&996 !StringRef(DemangledName).starts_with("llvm.")) {997 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(*CalledF);998 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(999 DemangledName, ST.getPreferredInstructionSet());1000 if (Opcode == SPIRV::OpGroupAsyncCopy) {1001 for (unsigned i = 0, PtrCnt = 0; i < CI->arg_size() && PtrCnt < 2; ++i) {1002 Value *Op = CI->getArgOperand(i);1003 if (!isPointerTy(Op->getType()))1004 continue;1005 ++PtrCnt;1006 if (Type *ElemTy = GR->findDeducedElementType(Op))1007 KnownElemTy = ElemTy; // src will rewrite dest if both are defined1008 Ops.push_back(std::make_pair(Op, i));1009 }1010 } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {1011 if (CI->arg_size() == 0)1012 return true;1013 Value *Op = CI->getArgOperand(0);1014 if (!isPointerTy(Op->getType()))1015 return true;1016 switch (Opcode) {1017 case SPIRV::OpAtomicFAddEXT:1018 case SPIRV::OpAtomicFMinEXT:1019 case SPIRV::OpAtomicFMaxEXT:1020 case SPIRV::OpAtomicLoad:1021 case SPIRV::OpAtomicCompareExchangeWeak:1022 case SPIRV::OpAtomicCompareExchange:1023 case SPIRV::OpAtomicExchange:1024 case SPIRV::OpAtomicIAdd:1025 case SPIRV::OpAtomicISub:1026 case SPIRV::OpAtomicOr:1027 case SPIRV::OpAtomicXor:1028 case SPIRV::OpAtomicAnd:1029 case SPIRV::OpAtomicUMin:1030 case SPIRV::OpAtomicUMax:1031 case SPIRV::OpAtomicSMin:1032 case SPIRV::OpAtomicSMax: {1033 KnownElemTy = isPointerTy(CI->getType()) ? getAtomicElemTy(GR, CI, Op)1034 : CI->getType();1035 if (!KnownElemTy)1036 return true;1037 Incomplete = isTodoType(Op);1038 Ops.push_back(std::make_pair(Op, 0));1039 } break;1040 case SPIRV::OpAtomicStore: {1041 if (CI->arg_size() < 4)1042 return true;1043 Value *ValOp = CI->getArgOperand(3);1044 KnownElemTy = isPointerTy(ValOp->getType())1045 ? getAtomicElemTy(GR, CI, Op)1046 : ValOp->getType();1047 if (!KnownElemTy)1048 return true;1049 Incomplete = isTodoType(Op);1050 Ops.push_back(std::make_pair(Op, 0));1051 } break;1052 }1053 }1054 }1055 return true;1056}1057 1058// Try to deduce element type for a function pointer.1059void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(1060 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,1061 Type *&KnownElemTy, bool IsPostprocessing) {1062 Value *Op = CI->getCalledOperand();1063 if (!Op || !isPointerTy(Op->getType()))1064 return;1065 Ops.push_back(std::make_pair(Op, std::numeric_limits<unsigned>::max()));1066 FunctionType *FTy = CI->getFunctionType();1067 bool IsNewFTy = false, IsIncomplete = false;1068 SmallVector<Type *, 4> ArgTys;1069 for (Value *Arg : CI->args()) {1070 Type *ArgTy = Arg->getType();1071 if (ArgTy->isPointerTy()) {1072 if (Type *ElemTy = GR->findDeducedElementType(Arg)) {1073 IsNewFTy = true;1074 ArgTy = getTypedPointerWrapper(ElemTy, getPointerAddressSpace(ArgTy));1075 if (isTodoType(Arg))1076 IsIncomplete = true;1077 } else {1078 IsIncomplete = true;1079 }1080 }1081 ArgTys.push_back(ArgTy);1082 }1083 Type *RetTy = FTy->getReturnType();1084 if (CI->getType()->isPointerTy()) {1085 if (Type *ElemTy = GR->findDeducedElementType(CI)) {1086 IsNewFTy = true;1087 RetTy =1088 getTypedPointerWrapper(ElemTy, getPointerAddressSpace(CI->getType()));1089 if (isTodoType(CI))1090 IsIncomplete = true;1091 } else {1092 IsIncomplete = true;1093 }1094 }1095 if (!IsPostprocessing && IsIncomplete)1096 insertTodoType(Op);1097 KnownElemTy =1098 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;1099}1100 1101bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(1102 Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,1103 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,1104 Type *&KnownElemTy, Value *Op, Function *F) {1105 KnownElemTy = GR->findDeducedElementType(F);1106 if (KnownElemTy)1107 return false;1108 if (Type *OpElemTy = GR->findDeducedElementType(Op)) {1109 OpElemTy = normalizeType(OpElemTy);1110 GR->addDeducedElementType(F, OpElemTy);1111 GR->addReturnType(1112 F, TypedPointerType::get(OpElemTy,1113 getPointerAddressSpace(F->getReturnType())));1114 // non-recursive update of types in function uses1115 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(I, Op)};1116 for (User *U : F->users()) {1117 CallInst *CI = dyn_cast<CallInst>(U);1118 if (!CI || CI->getCalledFunction() != F)1119 continue;1120 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(CI)) {1121 if (Type *PrevElemTy = GR->findDeducedElementType(CI)) {1122 GR->updateAssignType(AssignCI, CI,1123 getNormalizedPoisonValue(OpElemTy));1124 propagateElemType(CI, PrevElemTy, VisitedSubst);1125 }1126 }1127 }1128 // Non-recursive update of types in the function uncomplete returns.1129 // This may happen just once per a function, the latch is a pair of1130 // findDeducedElementType(F) / addDeducedElementType(F, ...).1131 // With or without the latch it is a non-recursive call due to1132 // IncompleteRets set to nullptr in this call.1133 if (IncompleteRets)1134 for (Instruction *IncompleteRetI : *IncompleteRets)1135 deduceOperandElementType(IncompleteRetI, nullptr, AskOps,1136 IsPostprocessing);1137 } else if (IncompleteRets) {1138 IncompleteRets->insert(I);1139 }1140 TypeValidated.insert(I);1141 return true;1142}1143 1144// If the Instruction has Pointer operands with unresolved types, this function1145// tries to deduce them. If the Instruction has Pointer operands with known1146// types which differ from expected, this function tries to insert a bitcast to1147// resolve the issue.1148void SPIRVEmitIntrinsics::deduceOperandElementType(1149 Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,1150 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing) {1151 SmallVector<std::pair<Value *, unsigned>> Ops;1152 Type *KnownElemTy = nullptr;1153 bool Incomplete = false;1154 // look for known basic patterns of type inference1155 if (auto *Ref = dyn_cast<PHINode>(I)) {1156 if (!isPointerTy(I->getType()) ||1157 !(KnownElemTy = GR->findDeducedElementType(I)))1158 return;1159 Incomplete = isTodoType(I);1160 for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {1161 Value *Op = Ref->getIncomingValue(i);1162 if (isPointerTy(Op->getType()))1163 Ops.push_back(std::make_pair(Op, i));1164 }1165 } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {1166 KnownElemTy = GR->findDeducedElementType(I);1167 if (!KnownElemTy)1168 return;1169 Incomplete = isTodoType(I);1170 Ops.push_back(std::make_pair(Ref->getPointerOperand(), 0));1171 } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {1172 if (!isPointerTy(I->getType()))1173 return;1174 KnownElemTy = GR->findDeducedElementType(I);1175 if (!KnownElemTy)1176 return;1177 Incomplete = isTodoType(I);1178 Ops.push_back(std::make_pair(Ref->getOperand(0), 0));1179 } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {1180 if (GR->findDeducedElementType(Ref->getPointerOperand()))1181 return;1182 KnownElemTy = Ref->getSourceElementType();1183 Ops.push_back(std::make_pair(Ref->getPointerOperand(),1184 GetElementPtrInst::getPointerOperandIndex()));1185 } else if (auto *Ref = dyn_cast<LoadInst>(I)) {1186 KnownElemTy = I->getType();1187 if (isUntypedPointerTy(KnownElemTy))1188 return;1189 Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());1190 if (PointeeTy && !isUntypedPointerTy(PointeeTy))1191 return;1192 Ops.push_back(std::make_pair(Ref->getPointerOperand(),1193 LoadInst::getPointerOperandIndex()));1194 } else if (auto *Ref = dyn_cast<StoreInst>(I)) {1195 if (!(KnownElemTy =1196 reconstructType(Ref->getValueOperand(), false, IsPostprocessing)))1197 return;1198 Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());1199 if (PointeeTy && !isUntypedPointerTy(PointeeTy))1200 return;1201 Ops.push_back(std::make_pair(Ref->getPointerOperand(),1202 StoreInst::getPointerOperandIndex()));1203 } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {1204 KnownElemTy = isPointerTy(I->getType())1205 ? getAtomicElemTy(GR, I, Ref->getPointerOperand())1206 : I->getType();1207 if (!KnownElemTy)1208 return;1209 Incomplete = isTodoType(Ref->getPointerOperand());1210 Ops.push_back(std::make_pair(Ref->getPointerOperand(),1211 AtomicCmpXchgInst::getPointerOperandIndex()));1212 } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {1213 KnownElemTy = isPointerTy(I->getType())1214 ? getAtomicElemTy(GR, I, Ref->getPointerOperand())1215 : I->getType();1216 if (!KnownElemTy)1217 return;1218 Incomplete = isTodoType(Ref->getPointerOperand());1219 Ops.push_back(std::make_pair(Ref->getPointerOperand(),1220 AtomicRMWInst::getPointerOperandIndex()));1221 } else if (auto *Ref = dyn_cast<SelectInst>(I)) {1222 if (!isPointerTy(I->getType()) ||1223 !(KnownElemTy = GR->findDeducedElementType(I)))1224 return;1225 Incomplete = isTodoType(I);1226 for (unsigned i = 0; i < Ref->getNumOperands(); i++) {1227 Value *Op = Ref->getOperand(i);1228 if (isPointerTy(Op->getType()))1229 Ops.push_back(std::make_pair(Op, i));1230 }1231 } else if (auto *Ref = dyn_cast<ReturnInst>(I)) {1232 if (!isPointerTy(CurrF->getReturnType()))1233 return;1234 Value *Op = Ref->getReturnValue();1235 if (!Op)1236 return;1237 if (deduceOperandElementTypeFunctionRet(I, IncompleteRets, AskOps,1238 IsPostprocessing, KnownElemTy, Op,1239 CurrF))1240 return;1241 Incomplete = isTodoType(CurrF);1242 Ops.push_back(std::make_pair(Op, 0));1243 } else if (auto *Ref = dyn_cast<ICmpInst>(I)) {1244 if (!isPointerTy(Ref->getOperand(0)->getType()))1245 return;1246 Value *Op0 = Ref->getOperand(0);1247 Value *Op1 = Ref->getOperand(1);1248 bool Incomplete0 = isTodoType(Op0);1249 bool Incomplete1 = isTodoType(Op1);1250 Type *ElemTy1 = GR->findDeducedElementType(Op1);1251 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)1252 ? nullptr1253 : GR->findDeducedElementType(Op0);1254 if (ElemTy0) {1255 KnownElemTy = ElemTy0;1256 Incomplete = Incomplete0;1257 Ops.push_back(std::make_pair(Op1, 1));1258 } else if (ElemTy1) {1259 KnownElemTy = ElemTy1;1260 Incomplete = Incomplete1;1261 Ops.push_back(std::make_pair(Op0, 0));1262 }1263 } else if (CallInst *CI = dyn_cast<CallInst>(I)) {1264 if (!CI->isIndirectCall())1265 deduceOperandElementTypeCalledFunction(CI, Ops, KnownElemTy, Incomplete);1266 else if (HaveFunPtrs)1267 deduceOperandElementTypeFunctionPointer(CI, Ops, KnownElemTy,1268 IsPostprocessing);1269 }1270 1271 // There is no enough info to deduce types or all is valid.1272 if (!KnownElemTy || Ops.size() == 0)1273 return;1274 1275 LLVMContext &Ctx = CurrF->getContext();1276 IRBuilder<> B(Ctx);1277 for (auto &OpIt : Ops) {1278 Value *Op = OpIt.first;1279 if (AskOps && !AskOps->contains(Op))1280 continue;1281 Type *AskTy = nullptr;1282 CallInst *AskCI = nullptr;1283 if (IsPostprocessing && AskOps) {1284 AskTy = GR->findDeducedElementType(Op);1285 AskCI = GR->findAssignPtrTypeInstr(Op);1286 assert(AskTy && AskCI);1287 }1288 Type *Ty = AskTy ? AskTy : GR->findDeducedElementType(Op);1289 if (Ty == KnownElemTy)1290 continue;1291 Value *OpTyVal = getNormalizedPoisonValue(KnownElemTy);1292 Type *OpTy = Op->getType();1293 if (Op->hasUseList() &&1294 (!Ty || AskTy || isUntypedPointerTy(Ty) || isTodoType(Op))) {1295 Type *PrevElemTy = GR->findDeducedElementType(Op);1296 GR->addDeducedElementType(Op, normalizeType(KnownElemTy));1297 // check if KnownElemTy is complete1298 if (!Incomplete)1299 eraseTodoType(Op);1300 else if (!IsPostprocessing)1301 insertTodoType(Op);1302 // check if there is existing Intrinsic::spv_assign_ptr_type instruction1303 CallInst *AssignCI = AskCI ? AskCI : GR->findAssignPtrTypeInstr(Op);1304 if (AssignCI == nullptr) {1305 Instruction *User = dyn_cast<Instruction>(Op->use_begin()->get());1306 setInsertPointSkippingPhis(B, User ? User->getNextNode() : I);1307 CallInst *CI =1308 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,1309 {B.getInt32(getPointerAddressSpace(OpTy))}, B);1310 GR->addAssignPtrTypeInstr(Op, CI);1311 } else {1312 GR->updateAssignType(AssignCI, Op, OpTyVal);1313 DenseSet<std::pair<Value *, Value *>> VisitedSubst{1314 std::make_pair(I, Op)};1315 propagateElemTypeRec(Op, KnownElemTy, PrevElemTy, VisitedSubst);1316 }1317 } else {1318 eraseTodoType(Op);1319 CallInst *PtrCastI =1320 buildSpvPtrcast(I->getParent()->getParent(), Op, KnownElemTy);1321 if (OpIt.second == std::numeric_limits<unsigned>::max())1322 dyn_cast<CallInst>(I)->setCalledOperand(PtrCastI);1323 else1324 I->setOperand(OpIt.second, PtrCastI);1325 }1326 }1327 TypeValidated.insert(I);1328}1329 1330void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,1331 Instruction *New,1332 IRBuilder<> &B) {1333 while (!Old->user_empty()) {1334 auto *U = Old->user_back();1335 if (isAssignTypeInstr(U)) {1336 B.SetInsertPoint(U);1337 SmallVector<Value *, 2> Args = {New, U->getOperand(1)};1338 CallInst *AssignCI =1339 B.CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);1340 GR->addAssignPtrTypeInstr(New, AssignCI);1341 U->eraseFromParent();1342 } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||1343 isa<CallInst>(U)) {1344 U->replaceUsesOfWith(Old, New);1345 } else {1346 llvm_unreachable("illegal aggregate intrinsic user");1347 }1348 }1349 New->copyMetadata(*Old);1350 Old->eraseFromParent();1351}1352 1353void SPIRVEmitIntrinsics::preprocessUndefs(IRBuilder<> &B) {1354 std::queue<Instruction *> Worklist;1355 for (auto &I : instructions(CurrF))1356 Worklist.push(&I);1357 1358 while (!Worklist.empty()) {1359 Instruction *I = Worklist.front();1360 bool BPrepared = false;1361 Worklist.pop();1362 1363 for (auto &Op : I->operands()) {1364 auto *AggrUndef = dyn_cast<UndefValue>(Op);1365 if (!AggrUndef || !Op->getType()->isAggregateType())1366 continue;1367 1368 if (!BPrepared) {1369 setInsertPointSkippingPhis(B, I);1370 BPrepared = true;1371 }1372 auto *IntrUndef = B.CreateIntrinsic(Intrinsic::spv_undef, {});1373 Worklist.push(IntrUndef);1374 I->replaceUsesOfWith(Op, IntrUndef);1375 AggrConsts[IntrUndef] = AggrUndef;1376 AggrConstTypes[IntrUndef] = AggrUndef->getType();1377 }1378 }1379}1380 1381void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {1382 std::queue<Instruction *> Worklist;1383 for (auto &I : instructions(CurrF))1384 Worklist.push(&I);1385 1386 while (!Worklist.empty()) {1387 auto *I = Worklist.front();1388 bool IsPhi = isa<PHINode>(I), BPrepared = false;1389 assert(I);1390 bool KeepInst = false;1391 for (const auto &Op : I->operands()) {1392 Constant *AggrConst = nullptr;1393 Type *ResTy = nullptr;1394 if (auto *COp = dyn_cast<ConstantVector>(Op)) {1395 AggrConst = COp;1396 ResTy = COp->getType();1397 } else if (auto *COp = dyn_cast<ConstantArray>(Op)) {1398 AggrConst = COp;1399 ResTy = B.getInt32Ty();1400 } else if (auto *COp = dyn_cast<ConstantStruct>(Op)) {1401 AggrConst = COp;1402 ResTy = B.getInt32Ty();1403 } else if (auto *COp = dyn_cast<ConstantDataArray>(Op)) {1404 AggrConst = COp;1405 ResTy = B.getInt32Ty();1406 } else if (auto *COp = dyn_cast<ConstantAggregateZero>(Op)) {1407 AggrConst = COp;1408 ResTy = Op->getType()->isVectorTy() ? COp->getType() : B.getInt32Ty();1409 }1410 if (AggrConst) {1411 SmallVector<Value *> Args;1412 if (auto *COp = dyn_cast<ConstantDataSequential>(Op))1413 for (unsigned i = 0; i < COp->getNumElements(); ++i)1414 Args.push_back(COp->getElementAsConstant(i));1415 else1416 llvm::append_range(Args, AggrConst->operands());1417 if (!BPrepared) {1418 IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())1419 : B.SetInsertPoint(I);1420 BPrepared = true;1421 }1422 auto *CI =1423 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {Args});1424 Worklist.push(CI);1425 I->replaceUsesOfWith(Op, CI);1426 KeepInst = true;1427 AggrConsts[CI] = AggrConst;1428 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst, false);1429 }1430 }1431 if (!KeepInst)1432 Worklist.pop();1433 }1434}1435 1436static void createDecorationIntrinsic(Instruction *I, MDNode *Node,1437 IRBuilder<> &B) {1438 LLVMContext &Ctx = I->getContext();1439 setInsertPointAfterDef(B, I);1440 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},1441 {I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, {Node}))});1442}1443 1444static void createRoundingModeDecoration(Instruction *I,1445 unsigned RoundingModeDeco,1446 IRBuilder<> &B) {1447 LLVMContext &Ctx = I->getContext();1448 Type *Int32Ty = Type::getInt32Ty(Ctx);1449 MDNode *RoundingModeNode = MDNode::get(1450 Ctx,1451 {ConstantAsMetadata::get(1452 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),1453 ConstantAsMetadata::get(ConstantInt::get(Int32Ty, RoundingModeDeco))});1454 createDecorationIntrinsic(I, RoundingModeNode, B);1455}1456 1457static void createSaturatedConversionDecoration(Instruction *I,1458 IRBuilder<> &B) {1459 LLVMContext &Ctx = I->getContext();1460 Type *Int32Ty = Type::getInt32Ty(Ctx);1461 MDNode *SaturatedConversionNode =1462 MDNode::get(Ctx, {ConstantAsMetadata::get(ConstantInt::get(1463 Int32Ty, SPIRV::Decoration::SaturatedConversion))});1464 createDecorationIntrinsic(I, SaturatedConversionNode, B);1465}1466 1467static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B) {1468 if (auto *CI = dyn_cast<CallInst>(I)) {1469 if (Function *Fu = CI->getCalledFunction()) {1470 if (Fu->isIntrinsic()) {1471 unsigned const int IntrinsicId = Fu->getIntrinsicID();1472 switch (IntrinsicId) {1473 case Intrinsic::fptosi_sat:1474 case Intrinsic::fptoui_sat:1475 createSaturatedConversionDecoration(I, B);1476 break;1477 default:1478 break;1479 }1480 }1481 }1482 }1483}1484 1485Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {1486 if (!Call.isInlineAsm())1487 return &Call;1488 1489 const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());1490 LLVMContext &Ctx = CurrF->getContext();1491 1492 Constant *TyC = UndefValue::get(IA->getFunctionType());1493 MDString *ConstraintString = MDString::get(Ctx, IA->getConstraintString());1494 SmallVector<Value *> Args = {1495 buildMD(TyC),1496 MetadataAsValue::get(Ctx, MDNode::get(Ctx, ConstraintString))};1497 for (unsigned OpIdx = 0; OpIdx < Call.arg_size(); OpIdx++)1498 Args.push_back(Call.getArgOperand(OpIdx));1499 1500 IRBuilder<> B(Call.getParent());1501 B.SetInsertPoint(&Call);1502 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {Args});1503 return &Call;1504}1505 1506// Use a tip about rounding mode to create a decoration.1507void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,1508 IRBuilder<> &B) {1509 std::optional<RoundingMode> RM = FPI->getRoundingMode();1510 if (!RM.has_value())1511 return;1512 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();1513 switch (RM.value()) {1514 default:1515 // ignore unknown rounding modes1516 break;1517 case RoundingMode::NearestTiesToEven:1518 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;1519 break;1520 case RoundingMode::TowardNegative:1521 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;1522 break;1523 case RoundingMode::TowardPositive:1524 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;1525 break;1526 case RoundingMode::TowardZero:1527 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;1528 break;1529 case RoundingMode::Dynamic:1530 case RoundingMode::NearestTiesToAway:1531 // TODO: check if supported1532 break;1533 }1534 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())1535 return;1536 // Convert the tip about rounding mode into a decoration record.1537 createRoundingModeDecoration(FPI, RoundingModeDeco, B);1538}1539 1540Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {1541 BasicBlock *ParentBB = I.getParent();1542 IRBuilder<> B(ParentBB);1543 B.SetInsertPoint(&I);1544 SmallVector<Value *, 4> Args;1545 SmallVector<BasicBlock *> BBCases;1546 for (auto &Op : I.operands()) {1547 if (Op.get()->getType()->isSized()) {1548 Args.push_back(Op);1549 } else if (BasicBlock *BB = dyn_cast<BasicBlock>(Op.get())) {1550 BBCases.push_back(BB);1551 Args.push_back(BlockAddress::get(BB->getParent(), BB));1552 } else {1553 report_fatal_error("Unexpected switch operand");1554 }1555 }1556 CallInst *NewI = B.CreateIntrinsic(Intrinsic::spv_switch,1557 {I.getOperand(0)->getType()}, {Args});1558 // remove switch to avoid its unneeded and undesirable unwrap into branches1559 // and conditions1560 replaceAllUsesWith(&I, NewI);1561 I.eraseFromParent();1562 // insert artificial and temporary instruction to preserve valid CFG,1563 // it will be removed after IR translation pass1564 B.SetInsertPoint(ParentBB);1565 IndirectBrInst *BrI = B.CreateIndirectBr(1566 Constant::getNullValue(PointerType::getUnqual(ParentBB->getContext())),1567 BBCases.size());1568 for (BasicBlock *BBCase : BBCases)1569 BrI->addDestination(BBCase);1570 return BrI;1571}1572 1573static bool isFirstIndexZero(const GetElementPtrInst *GEP) {1574 if (GEP->getNumIndices() == 0)1575 return false;1576 if (const auto *CI = dyn_cast<ConstantInt>(GEP->getOperand(1))) {1577 return CI->getZExtValue() == 0;1578 }1579 return false;1580}1581 1582Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {1583 IRBuilder<> B(I.getParent());1584 B.SetInsertPoint(&I);1585 1586 if (TM->getSubtargetImpl()->isLogicalSPIRV() && !isFirstIndexZero(&I)) {1587 // Logical SPIR-V cannot use the OpPtrAccessChain instruction. If the first1588 // index of the GEP is not 0, then we need to try to adjust it.1589 //1590 // If the GEP is doing byte addressing, try to rebuild the full access chain1591 // from the type of the pointer.1592 if (I.getSourceElementType() ==1593 IntegerType::getInt8Ty(CurrF->getContext())) {1594 return buildLogicalAccessChainFromGEP(I);1595 }1596 1597 // Look for the array-to-pointer decay. If this is the pattern1598 // we can adjust the types, and prepend a 0 to the indices.1599 Value *PtrOp = I.getPointerOperand();1600 Type *SrcElemTy = I.getSourceElementType();1601 Type *DeducedPointeeTy = deduceElementType(PtrOp, true);1602 1603 if (auto *ArrTy = dyn_cast<ArrayType>(DeducedPointeeTy)) {1604 if (ArrTy->getElementType() == SrcElemTy) {1605 SmallVector<Value *> NewIndices;1606 Type *FirstIdxType = I.getOperand(1)->getType();1607 NewIndices.push_back(ConstantInt::get(FirstIdxType, 0));1608 for (Value *Idx : I.indices())1609 NewIndices.push_back(Idx);1610 1611 SmallVector<Type *, 2> Types = {I.getType(), I.getPointerOperandType()};1612 SmallVector<Value *, 4> Args;1613 Args.push_back(B.getInt1(I.isInBounds()));1614 Args.push_back(I.getPointerOperand());1615 Args.append(NewIndices.begin(), NewIndices.end());1616 1617 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});1618 replaceAllUsesWithAndErase(B, &I, NewI);1619 return NewI;1620 }1621 }1622 }1623 1624 SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};1625 SmallVector<Value *, 4> Args;1626 Args.push_back(B.getInt1(I.isInBounds()));1627 llvm::append_range(Args, I.operands());1628 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});1629 replaceAllUsesWithAndErase(B, &I, NewI);1630 return NewI;1631}1632 1633Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {1634 IRBuilder<> B(I.getParent());1635 B.SetInsertPoint(&I);1636 Value *Source = I.getOperand(0);1637 1638 // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of1639 // varying element types. In case of IR coming from older versions of LLVM1640 // such bitcasts do not provide sufficient information, should be just skipped1641 // here, and handled in insertPtrCastOrAssignTypeInstr.1642 if (isPointerTy(I.getType())) {1643 replaceAllUsesWith(&I, Source);1644 I.eraseFromParent();1645 return nullptr;1646 }1647 1648 SmallVector<Type *, 2> Types = {I.getType(), Source->getType()};1649 SmallVector<Value *> Args(I.op_begin(), I.op_end());1650 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});1651 replaceAllUsesWithAndErase(B, &I, NewI);1652 return NewI;1653}1654 1655void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(1656 TargetExtType *AssignedType, Value *V, IRBuilder<> &B) {1657 Type *VTy = V->getType();1658 1659 // A couple of sanity checks.1660 assert((isPointerTy(VTy)) && "Expect a pointer type!");1661 if (Type *ElemTy = getPointeeType(VTy))1662 if (ElemTy != AssignedType)1663 report_fatal_error("Unexpected pointer element type!");1664 1665 CallInst *AssignCI = GR->findAssignPtrTypeInstr(V);1666 if (!AssignCI) {1667 GR->buildAssignType(B, AssignedType, V);1668 return;1669 }1670 1671 Type *CurrentType =1672 dyn_cast<ConstantAsMetadata>(1673 cast<MetadataAsValue>(AssignCI->getOperand(1))->getMetadata())1674 ->getType();1675 if (CurrentType == AssignedType)1676 return;1677 1678 // Builtin types cannot be redeclared or casted.1679 if (CurrentType->isTargetExtTy())1680 report_fatal_error("Type mismatch " + CurrentType->getTargetExtName() +1681 "/" + AssignedType->getTargetExtName() +1682 " for value " + V->getName(),1683 false);1684 1685 // Our previous guess about the type seems to be wrong, let's update1686 // inferred type according to a new, more precise type information.1687 GR->updateAssignType(AssignCI, V, getNormalizedPoisonValue(AssignedType));1688}1689 1690void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(1691 Instruction *I, Value *Pointer, Type *ExpectedElementType,1692 unsigned OperandToReplace, IRBuilder<> &B) {1693 TypeValidated.insert(I);1694 1695 // Do not emit spv_ptrcast if Pointer's element type is ExpectedElementType1696 Type *PointerElemTy = deduceElementTypeHelper(Pointer, false);1697 if (PointerElemTy == ExpectedElementType ||1698 isEquivalentTypes(PointerElemTy, ExpectedElementType))1699 return;1700 1701 setInsertPointSkippingPhis(B, I);1702 Value *ExpectedElementVal = getNormalizedPoisonValue(ExpectedElementType);1703 MetadataAsValue *VMD = buildMD(ExpectedElementVal);1704 unsigned AddressSpace = getPointerAddressSpace(Pointer->getType());1705 bool FirstPtrCastOrAssignPtrType = true;1706 1707 // Do not emit new spv_ptrcast if equivalent one already exists or when1708 // spv_assign_ptr_type already targets this pointer with the same element1709 // type.1710 if (Pointer->hasUseList()) {1711 for (auto User : Pointer->users()) {1712 auto *II = dyn_cast<IntrinsicInst>(User);1713 if (!II ||1714 (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&1715 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||1716 II->getOperand(0) != Pointer)1717 continue;1718 1719 // There is some spv_ptrcast/spv_assign_ptr_type already targeting this1720 // pointer.1721 FirstPtrCastOrAssignPtrType = false;1722 if (II->getOperand(1) != VMD ||1723 dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=1724 AddressSpace)1725 continue;1726 1727 // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the1728 // same element type and address space.1729 if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)1730 return;1731 1732 // This must be a spv_ptrcast, do not emit new if this one has the same BB1733 // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.1734 if (II->getParent() != I->getParent())1735 continue;1736 1737 I->setOperand(OperandToReplace, II);1738 return;1739 }1740 }1741 1742 if (isa<Instruction>(Pointer) || isa<Argument>(Pointer)) {1743 if (FirstPtrCastOrAssignPtrType) {1744 // If this would be the first spv_ptrcast, do not emit spv_ptrcast and1745 // emit spv_assign_ptr_type instead.1746 GR->buildAssignPtr(B, ExpectedElementType, Pointer);1747 return;1748 } else if (isTodoType(Pointer)) {1749 eraseTodoType(Pointer);1750 if (!isa<CallInst>(Pointer) && !isa<GetElementPtrInst>(Pointer)) {1751 // If this wouldn't be the first spv_ptrcast but existing type info is1752 // uncomplete, update spv_assign_ptr_type arguments.1753 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Pointer)) {1754 Type *PrevElemTy = GR->findDeducedElementType(Pointer);1755 assert(PrevElemTy);1756 DenseSet<std::pair<Value *, Value *>> VisitedSubst{1757 std::make_pair(I, Pointer)};1758 GR->updateAssignType(AssignCI, Pointer, ExpectedElementVal);1759 propagateElemType(Pointer, PrevElemTy, VisitedSubst);1760 } else {1761 GR->buildAssignPtr(B, ExpectedElementType, Pointer);1762 }1763 return;1764 }1765 }1766 }1767 1768 // Emit spv_ptrcast1769 SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};1770 SmallVector<Value *, 2> Args = {Pointer, VMD, B.getInt32(AddressSpace)};1771 auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);1772 I->setOperand(OperandToReplace, PtrCastI);1773 // We need to set up a pointee type for the newly created spv_ptrcast.1774 GR->buildAssignPtr(B, ExpectedElementType, PtrCastI);1775}1776 1777void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,1778 IRBuilder<> &B) {1779 // Handle basic instructions:1780 StoreInst *SI = dyn_cast<StoreInst>(I);1781 if (IsKernelArgInt8(CurrF, SI)) {1782 replacePointerOperandWithPtrCast(1783 I, SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->getContext()),1784 0, B);1785 }1786 if (SI) {1787 Value *Op = SI->getValueOperand();1788 Value *Pointer = SI->getPointerOperand();1789 Type *OpTy = Op->getType();1790 if (auto *OpI = dyn_cast<Instruction>(Op))1791 OpTy = restoreMutatedType(GR, OpI, OpTy);1792 if (OpTy == Op->getType())1793 OpTy = deduceElementTypeByValueDeep(OpTy, Op, false);1794 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 1, B);1795 return;1796 }1797 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {1798 Value *Pointer = LI->getPointerOperand();1799 Type *OpTy = LI->getType();1800 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {1801 if (Type *ElemTy = GR->findDeducedElementType(LI)) {1802 OpTy = getTypedPointerWrapper(ElemTy, PtrTy->getAddressSpace());1803 } else {1804 Type *NewOpTy = OpTy;1805 OpTy = deduceElementTypeByValueDeep(OpTy, LI, false);1806 if (OpTy == NewOpTy)1807 insertTodoType(Pointer);1808 }1809 }1810 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 0, B);1811 return;1812 }1813 if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {1814 Value *Pointer = GEPI->getPointerOperand();1815 Type *OpTy = nullptr;1816 1817 // Logical SPIR-V is not allowed to use Op*PtrAccessChain instructions. If1818 // the first index is 0, then we can trivially lower to OpAccessChain. If1819 // not we need to try to rewrite the GEP. We avoid adding a pointer cast at1820 // this time, and will rewrite the GEP when visiting it.1821 if (TM->getSubtargetImpl()->isLogicalSPIRV() && !isFirstIndexZero(GEPI)) {1822 return;1823 }1824 1825 // In all cases, fall back to the GEP type if type scavenging failed.1826 if (!OpTy)1827 OpTy = GEPI->getSourceElementType();1828 1829 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 0, B);1830 if (isNestedPointer(OpTy))1831 insertTodoType(Pointer);1832 return;1833 }1834 1835 // TODO: review and merge with existing logics:1836 // Handle calls to builtins (non-intrinsics):1837 CallInst *CI = dyn_cast<CallInst>(I);1838 if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||1839 !CI->getCalledFunction() || CI->getCalledFunction()->isIntrinsic())1840 return;1841 1842 // collect information about formal parameter types1843 std::string DemangledName =1844 getOclOrSpirvBuiltinDemangledName(CI->getCalledFunction()->getName());1845 Function *CalledF = CI->getCalledFunction();1846 SmallVector<Type *, 4> CalledArgTys;1847 bool HaveTypes = false;1848 for (unsigned OpIdx = 0; OpIdx < CalledF->arg_size(); ++OpIdx) {1849 Argument *CalledArg = CalledF->getArg(OpIdx);1850 Type *ArgType = CalledArg->getType();1851 if (!isPointerTy(ArgType)) {1852 CalledArgTys.push_back(nullptr);1853 } else if (Type *ArgTypeElem = getPointeeType(ArgType)) {1854 CalledArgTys.push_back(ArgTypeElem);1855 HaveTypes = true;1856 } else {1857 Type *ElemTy = GR->findDeducedElementType(CalledArg);1858 if (!ElemTy && hasPointeeTypeAttr(CalledArg))1859 ElemTy = getPointeeTypeByAttr(CalledArg);1860 if (!ElemTy) {1861 ElemTy = getPointeeTypeByCallInst(DemangledName, CalledF, OpIdx);1862 if (ElemTy) {1863 GR->addDeducedElementType(CalledArg, normalizeType(ElemTy));1864 } else {1865 for (User *U : CalledArg->users()) {1866 if (Instruction *Inst = dyn_cast<Instruction>(U)) {1867 if ((ElemTy = deduceElementTypeHelper(Inst, false)) != nullptr)1868 break;1869 }1870 }1871 }1872 }1873 HaveTypes |= ElemTy != nullptr;1874 CalledArgTys.push_back(ElemTy);1875 }1876 }1877 1878 if (DemangledName.empty() && !HaveTypes)1879 return;1880 1881 for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) {1882 Value *ArgOperand = CI->getArgOperand(OpIdx);1883 if (!isPointerTy(ArgOperand->getType()))1884 continue;1885 1886 // Constants (nulls/undefs) are handled in insertAssignPtrTypeIntrs()1887 if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand)) {1888 // However, we may have assumptions about the formal argument's type and1889 // may have a need to insert a ptr cast for the actual parameter of this1890 // call.1891 Argument *CalledArg = CalledF->getArg(OpIdx);1892 if (!GR->findDeducedElementType(CalledArg))1893 continue;1894 }1895 1896 Type *ExpectedType =1897 OpIdx < CalledArgTys.size() ? CalledArgTys[OpIdx] : nullptr;1898 if (!ExpectedType && !DemangledName.empty())1899 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(1900 DemangledName, OpIdx, I->getContext());1901 if (!ExpectedType || ExpectedType->isVoidTy())1902 continue;1903 1904 if (ExpectedType->isTargetExtTy() &&1905 !isTypedPointerWrapper(cast<TargetExtType>(ExpectedType)))1906 insertAssignPtrTypeTargetExt(cast<TargetExtType>(ExpectedType),1907 ArgOperand, B);1908 else1909 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx, B);1910 }1911}1912 1913Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {1914 // If it's a <1 x Type> vector type, don't modify it. It's not a legal vector1915 // type in LLT and IRTranslator will replace it by the scalar.1916 if (isVector1(I.getType()))1917 return &I;1918 1919 SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),1920 I.getOperand(1)->getType(),1921 I.getOperand(2)->getType()};1922 IRBuilder<> B(I.getParent());1923 B.SetInsertPoint(&I);1924 SmallVector<Value *> Args(I.op_begin(), I.op_end());1925 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});1926 replaceAllUsesWithAndErase(B, &I, NewI);1927 return NewI;1928}1929 1930Instruction *1931SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {1932 // If it's a <1 x Type> vector type, don't modify it. It's not a legal vector1933 // type in LLT and IRTranslator will replace it by the scalar.1934 if (isVector1(I.getVectorOperandType()))1935 return &I;1936 1937 IRBuilder<> B(I.getParent());1938 B.SetInsertPoint(&I);1939 SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(),1940 I.getIndexOperand()->getType()};1941 SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};1942 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});1943 replaceAllUsesWithAndErase(B, &I, NewI);1944 return NewI;1945}1946 1947Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {1948 IRBuilder<> B(I.getParent());1949 B.SetInsertPoint(&I);1950 SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()};1951 SmallVector<Value *> Args;1952 Value *AggregateOp = I.getAggregateOperand();1953 if (isa<UndefValue>(AggregateOp))1954 Args.push_back(UndefValue::get(B.getInt32Ty()));1955 else1956 Args.push_back(AggregateOp);1957 Args.push_back(I.getInsertedValueOperand());1958 for (auto &Op : I.indices())1959 Args.push_back(B.getInt32(Op));1960 Instruction *NewI =1961 B.CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args});1962 replaceMemInstrUses(&I, NewI, B);1963 return NewI;1964}1965 1966Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {1967 if (I.getAggregateOperand()->getType()->isAggregateType())1968 return &I;1969 IRBuilder<> B(I.getParent());1970 B.SetInsertPoint(&I);1971 SmallVector<Value *> Args(I.operands());1972 for (auto &Op : I.indices())1973 Args.push_back(B.getInt32(Op));1974 auto *NewI =1975 B.CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});1976 replaceAllUsesWithAndErase(B, &I, NewI);1977 return NewI;1978}1979 1980Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) {1981 if (!I.getType()->isAggregateType())1982 return &I;1983 IRBuilder<> B(I.getParent());1984 B.SetInsertPoint(&I);1985 TrackConstants = false;1986 const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();1987 MachineMemOperand::Flags Flags =1988 TLI->getLoadMemOperandFlags(I, CurrF->getDataLayout());1989 auto *NewI =1990 B.CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()},1991 {I.getPointerOperand(), B.getInt16(Flags),1992 B.getInt8(I.getAlign().value())});1993 replaceMemInstrUses(&I, NewI, B);1994 return NewI;1995}1996 1997Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {1998 if (!AggrStores.contains(&I))1999 return &I;2000 IRBuilder<> B(I.getParent());2001 B.SetInsertPoint(&I);2002 TrackConstants = false;2003 const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();2004 MachineMemOperand::Flags Flags =2005 TLI->getStoreMemOperandFlags(I, CurrF->getDataLayout());2006 auto *PtrOp = I.getPointerOperand();2007 auto *NewI = B.CreateIntrinsic(2008 Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()},2009 {I.getValueOperand(), PtrOp, B.getInt16(Flags),2010 B.getInt8(I.getAlign().value())});2011 NewI->copyMetadata(I);2012 I.eraseFromParent();2013 return NewI;2014}2015 2016Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {2017 Value *ArraySize = nullptr;2018 if (I.isArrayAllocation()) {2019 const SPIRVSubtarget *STI = TM->getSubtargetImpl(*I.getFunction());2020 if (!STI->canUseExtension(2021 SPIRV::Extension::SPV_INTEL_variable_length_array))2022 report_fatal_error(2023 "array allocation: this instruction requires the following "2024 "SPIR-V extension: SPV_INTEL_variable_length_array",2025 false);2026 ArraySize = I.getArraySize();2027 }2028 IRBuilder<> B(I.getParent());2029 B.SetInsertPoint(&I);2030 TrackConstants = false;2031 Type *PtrTy = I.getType();2032 auto *NewI =2033 ArraySize2034 ? B.CreateIntrinsic(Intrinsic::spv_alloca_array,2035 {PtrTy, ArraySize->getType()},2036 {ArraySize, B.getInt8(I.getAlign().value())})2037 : B.CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy},2038 {B.getInt8(I.getAlign().value())});2039 replaceAllUsesWithAndErase(B, &I, NewI);2040 return NewI;2041}2042 2043Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {2044 assert(I.getType()->isAggregateType() && "Aggregate result is expected");2045 IRBuilder<> B(I.getParent());2046 B.SetInsertPoint(&I);2047 SmallVector<Value *> Args(I.operands());2048 Args.push_back(B.getInt32(2049 static_cast<uint32_t>(getMemScope(I.getContext(), I.getSyncScopeID()))));2050 Args.push_back(B.getInt32(2051 static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering()))));2052 Args.push_back(B.getInt32(2053 static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering()))));2054 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_cmpxchg,2055 {I.getPointerOperand()->getType()}, {Args});2056 replaceMemInstrUses(&I, NewI, B);2057 return NewI;2058}2059 2060Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) {2061 IRBuilder<> B(I.getParent());2062 B.SetInsertPoint(&I);2063 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});2064 return &I;2065}2066 2067void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,2068 IRBuilder<> &B) {2069 // Skip special artificial variables.2070 static const StringSet<> ArtificialGlobals{"llvm.global.annotations",2071 "llvm.compiler.used"};2072 2073 if (ArtificialGlobals.contains(GV.getName()))2074 return;2075 2076 Constant *Init = nullptr;2077 if (hasInitializer(&GV)) {2078 // Deduce element type and store results in Global Registry.2079 // Result is ignored, because TypedPointerType is not supported2080 // by llvm IR general logic.2081 deduceElementTypeHelper(&GV, false);2082 Init = GV.getInitializer();2083 Type *Ty = isAggrConstForceInt32(Init) ? B.getInt32Ty() : Init->getType();2084 Constant *Const = isAggrConstForceInt32(Init) ? B.getInt32(1) : Init;2085 auto *InitInst = B.CreateIntrinsic(Intrinsic::spv_init_global,2086 {GV.getType(), Ty}, {&GV, Const});2087 InitInst->setArgOperand(1, Init);2088 }2089 if (!Init && GV.use_empty())2090 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);2091}2092 2093// Return true, if we can't decide what is the pointee type now and will get2094// back to the question later. Return false is spv_assign_ptr_type is not needed2095// or can be inserted immediately.2096bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,2097 IRBuilder<> &B,2098 bool UnknownElemTypeI8) {2099 reportFatalOnTokenType(I);2100 if (!isPointerTy(I->getType()) || !requireAssignType(I))2101 return false;2102 2103 setInsertPointAfterDef(B, I);2104 if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {2105 GR->buildAssignPtr(B, ElemTy, I);2106 return false;2107 }2108 return true;2109}2110 2111void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,2112 IRBuilder<> &B) {2113 // TODO: extend the list of functions with known result types2114 static StringMap<unsigned> ResTypeWellKnown = {2115 {"async_work_group_copy", WellKnownTypes::Event},2116 {"async_work_group_strided_copy", WellKnownTypes::Event},2117 {"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};2118 2119 reportFatalOnTokenType(I);2120 2121 bool IsKnown = false;2122 if (auto *CI = dyn_cast<CallInst>(I)) {2123 if (!CI->isIndirectCall() && !CI->isInlineAsm() &&2124 CI->getCalledFunction() && !CI->getCalledFunction()->isIntrinsic()) {2125 Function *CalledF = CI->getCalledFunction();2126 std::string DemangledName =2127 getOclOrSpirvBuiltinDemangledName(CalledF->getName());2128 FPDecorationId DecorationId = FPDecorationId::NONE;2129 if (DemangledName.length() > 0)2130 DemangledName =2131 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);2132 auto ResIt = ResTypeWellKnown.find(DemangledName);2133 if (ResIt != ResTypeWellKnown.end()) {2134 IsKnown = true;2135 setInsertPointAfterDef(B, I);2136 switch (ResIt->second) {2137 case WellKnownTypes::Event:2138 GR->buildAssignType(2139 B, TargetExtType::get(I->getContext(), "spirv.Event"), I);2140 break;2141 }2142 }2143 // check if a floating rounding mode or saturation info is present2144 switch (DecorationId) {2145 default:2146 break;2147 case FPDecorationId::SAT:2148 createSaturatedConversionDecoration(CI, B);2149 break;2150 case FPDecorationId::RTE:2151 createRoundingModeDecoration(2152 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE, B);2153 break;2154 case FPDecorationId::RTZ:2155 createRoundingModeDecoration(2156 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ, B);2157 break;2158 case FPDecorationId::RTP:2159 createRoundingModeDecoration(2160 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP, B);2161 break;2162 case FPDecorationId::RTN:2163 createRoundingModeDecoration(2164 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN, B);2165 break;2166 }2167 }2168 }2169 2170 Type *Ty = I->getType();2171 if (!IsKnown && !Ty->isVoidTy() && !isPointerTy(Ty) && requireAssignType(I)) {2172 setInsertPointAfterDef(B, I);2173 Type *TypeToAssign = Ty;2174 if (auto *II = dyn_cast<IntrinsicInst>(I)) {2175 if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||2176 II->getIntrinsicID() == Intrinsic::spv_undef) {2177 auto It = AggrConstTypes.find(II);2178 if (It == AggrConstTypes.end())2179 report_fatal_error("Unknown composite intrinsic type");2180 TypeToAssign = It->second;2181 }2182 }2183 TypeToAssign = restoreMutatedType(GR, I, TypeToAssign);2184 GR->buildAssignType(B, TypeToAssign, I);2185 }2186 for (const auto &Op : I->operands()) {2187 if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||2188 // Check GetElementPtrConstantExpr case.2189 (isa<ConstantExpr>(Op) &&2190 (isa<GEPOperator>(Op) ||2191 (cast<ConstantExpr>(Op)->getOpcode() == CastInst::IntToPtr)))) {2192 setInsertPointSkippingPhis(B, I);2193 Type *OpTy = Op->getType();2194 if (isa<UndefValue>(Op) && OpTy->isAggregateType()) {2195 CallInst *AssignCI =2196 buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,2197 UndefValue::get(B.getInt32Ty()), {}, B);2198 GR->addAssignPtrTypeInstr(Op, AssignCI);2199 } else if (!isa<Instruction>(Op)) {2200 Type *OpTy = Op->getType();2201 Type *OpTyElem = getPointeeType(OpTy);2202 if (OpTyElem) {2203 GR->buildAssignPtr(B, OpTyElem, Op);2204 } else if (isPointerTy(OpTy)) {2205 Type *ElemTy = GR->findDeducedElementType(Op);2206 GR->buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true),2207 Op);2208 } else {2209 Value *OpTyVal = Op;2210 if (OpTy->isTargetExtTy()) {2211 // We need to do this in order to be consistent with how target ext2212 // types are handled in `processInstrAfterVisit`2213 OpTyVal = getNormalizedPoisonValue(OpTy);2214 }2215 CallInst *AssignCI =2216 buildIntrWithMD(Intrinsic::spv_assign_type, {OpTy},2217 getNormalizedPoisonValue(OpTy), OpTyVal, {}, B);2218 GR->addAssignPtrTypeInstr(OpTyVal, AssignCI);2219 }2220 }2221 }2222 }2223}2224 2225bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(2226 Instruction *Inst) {2227 const SPIRVSubtarget *STI = TM->getSubtargetImpl(*Inst->getFunction());2228 if (!STI->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))2229 return false;2230 // Add aliasing decorations to internal load and store intrinsics2231 // and atomic instructions, skipping atomic store as it won't have ID to2232 // attach the decoration.2233 CallInst *CI = dyn_cast<CallInst>(Inst);2234 if (!CI)2235 return false;2236 if (Function *Fun = CI->getCalledFunction()) {2237 if (Fun->isIntrinsic()) {2238 switch (Fun->getIntrinsicID()) {2239 case Intrinsic::spv_load:2240 case Intrinsic::spv_store:2241 return true;2242 default:2243 return false;2244 }2245 }2246 std::string Name = getOclOrSpirvBuiltinDemangledName(Fun->getName());2247 const std::string Prefix = "__spirv_Atomic";2248 const bool IsAtomic = Name.find(Prefix) == 0;2249 2250 if (!Fun->getReturnType()->isVoidTy() && IsAtomic)2251 return true;2252 }2253 return false;2254}2255 2256void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,2257 IRBuilder<> &B) {2258 if (MDNode *MD = I->getMetadata("spirv.Decorations")) {2259 setInsertPointAfterDef(B, I);2260 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},2261 {I, MetadataAsValue::get(I->getContext(), MD)});2262 }2263 // Lower alias.scope/noalias metadata2264 {2265 auto processMemAliasingDecoration = [&](unsigned Kind) {2266 if (MDNode *AliasListMD = I->getMetadata(Kind)) {2267 if (shouldTryToAddMemAliasingDecoration(I)) {2268 uint32_t Dec = Kind == LLVMContext::MD_alias_scope2269 ? SPIRV::Decoration::AliasScopeINTEL2270 : SPIRV::Decoration::NoAliasINTEL;2271 SmallVector<Value *, 3> Args = {2272 I, ConstantInt::get(B.getInt32Ty(), Dec),2273 MetadataAsValue::get(I->getContext(), AliasListMD)};2274 setInsertPointAfterDef(B, I);2275 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,2276 {I->getType()}, {Args});2277 }2278 }2279 };2280 processMemAliasingDecoration(LLVMContext::MD_alias_scope);2281 processMemAliasingDecoration(LLVMContext::MD_noalias);2282 }2283 // MD_fpmath2284 if (MDNode *MD = I->getMetadata(LLVMContext::MD_fpmath)) {2285 const SPIRVSubtarget *STI = TM->getSubtargetImpl(*I->getFunction());2286 bool AllowFPMaxError =2287 STI->canUseExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);2288 if (!AllowFPMaxError)2289 return;2290 2291 setInsertPointAfterDef(B, I);2292 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,2293 {I->getType()},2294 {I, MetadataAsValue::get(I->getContext(), MD)});2295 }2296}2297 2298static SPIRV::FPFastMathDefaultInfoVector &getOrCreateFPFastMathDefaultInfoVec(2299 const Module &M,2300 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>2301 &FPFastMathDefaultInfoMap,2302 Function *F) {2303 auto it = FPFastMathDefaultInfoMap.find(F);2304 if (it != FPFastMathDefaultInfoMap.end())2305 return it->second;2306 2307 // If the map does not contain the entry, create a new one. Initialize it to2308 // contain all 3 elements sorted by bit width of target type: {half, float,2309 // double}.2310 SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec;2311 FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()),2312 SPIRV::FPFastMathMode::None);2313 FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()),2314 SPIRV::FPFastMathMode::None);2315 FPFastMathDefaultInfoVec.emplace_back(Type::getDoubleTy(M.getContext()),2316 SPIRV::FPFastMathMode::None);2317 return FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec);2318}2319 2320static SPIRV::FPFastMathDefaultInfo &getFPFastMathDefaultInfo(2321 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec,2322 const Type *Ty) {2323 size_t BitWidth = Ty->getScalarSizeInBits();2324 int Index =2325 SPIRV::FPFastMathDefaultInfoVector::computeFPFastMathDefaultInfoVecIndex(2326 BitWidth);2327 assert(Index >= 0 && Index < 3 &&2328 "Expected FPFastMathDefaultInfo for half, float, or double");2329 assert(FPFastMathDefaultInfoVec.size() == 3 &&2330 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");2331 return FPFastMathDefaultInfoVec[Index];2332}2333 2334void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) {2335 const SPIRVSubtarget *ST = TM->getSubtargetImpl();2336 if (!ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))2337 return;2338 2339 // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.2340 // We need the entry point (function) as the key, and the target2341 // type and flags as the value.2342 // We also need to check ContractionOff and SignedZeroInfNanPreserve2343 // execution modes, as they are now deprecated and must be replaced2344 // with FPFastMathDefaultInfo.2345 auto Node = M.getNamedMetadata("spirv.ExecutionMode");2346 if (!Node) {2347 if (!M.getNamedMetadata("opencl.enable.FP_CONTRACT")) {2348 // This requires emitting ContractionOff. However, because2349 // ContractionOff is now deprecated, we need to replace it with2350 // FPFastMathDefaultInfo with FP Fast Math Mode bitmask set to all 0.2351 // We need to create the constant for that.2352 2353 // Create constant instruction with the bitmask flags.2354 Constant *InitValue =2355 ConstantInt::get(Type::getInt32Ty(M.getContext()), 0);2356 // TODO: Reuse constant if there is one already with the required2357 // value.2358 [[maybe_unused]] GlobalVariable *GV =2359 new GlobalVariable(M, // Module2360 Type::getInt32Ty(M.getContext()), // Type2361 true, // isConstant2362 GlobalValue::InternalLinkage, // Linkage2363 InitValue // Initializer2364 );2365 }2366 return;2367 }2368 2369 // The table maps function pointers to their default FP fast math info. It2370 // can be assumed that the SmallVector is sorted by the bit width of the2371 // type. The first element is the smallest bit width, and the last element2372 // is the largest bit width, therefore, we will have {half, float, double}2373 // in the order of their bit widths.2374 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>2375 FPFastMathDefaultInfoMap;2376 2377 for (unsigned i = 0; i < Node->getNumOperands(); i++) {2378 MDNode *MDN = cast<MDNode>(Node->getOperand(i));2379 assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");2380 Function *F = cast<Function>(2381 cast<ConstantAsMetadata>(MDN->getOperand(0))->getValue());2382 const auto EM =2383 cast<ConstantInt>(2384 cast<ConstantAsMetadata>(MDN->getOperand(1))->getValue())2385 ->getZExtValue();2386 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {2387 assert(MDN->getNumOperands() == 4 &&2388 "Expected 4 operands for FPFastMathDefault");2389 const Type *T = cast<ValueAsMetadata>(MDN->getOperand(2))->getType();2390 unsigned Flags =2391 cast<ConstantInt>(2392 cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())2393 ->getZExtValue();2394 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =2395 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);2396 SPIRV::FPFastMathDefaultInfo &Info =2397 getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T);2398 Info.FastMathFlags = Flags;2399 Info.FPFastMathDefault = true;2400 } else if (EM == SPIRV::ExecutionMode::ContractionOff) {2401 assert(MDN->getNumOperands() == 2 &&2402 "Expected no operands for ContractionOff");2403 2404 // We need to save this info for every possible FP type, i.e. {half,2405 // float, double, fp128}.2406 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =2407 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);2408 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {2409 Info.ContractionOff = true;2410 }2411 } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {2412 assert(MDN->getNumOperands() == 3 &&2413 "Expected 1 operand for SignedZeroInfNanPreserve");2414 unsigned TargetWidth =2415 cast<ConstantInt>(2416 cast<ConstantAsMetadata>(MDN->getOperand(2))->getValue())2417 ->getZExtValue();2418 // We need to save this info only for the FP type with TargetWidth.2419 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =2420 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);2421 int Index = SPIRV::FPFastMathDefaultInfoVector::2422 computeFPFastMathDefaultInfoVecIndex(TargetWidth);2423 assert(Index >= 0 && Index < 3 &&2424 "Expected FPFastMathDefaultInfo for half, float, or double");2425 assert(FPFastMathDefaultInfoVec.size() == 3 &&2426 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");2427 FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;2428 }2429 }2430 2431 std::unordered_map<unsigned, GlobalVariable *> GlobalVars;2432 for (auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {2433 if (FPFastMathDefaultInfoVec.empty())2434 continue;2435 2436 for (const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {2437 assert(Info.Ty && "Expected target type for FPFastMathDefaultInfo");2438 // Skip if none of the execution modes was used.2439 unsigned Flags = Info.FastMathFlags;2440 if (Flags == SPIRV::FPFastMathMode::None && !Info.ContractionOff &&2441 !Info.SignedZeroInfNanPreserve && !Info.FPFastMathDefault)2442 continue;2443 2444 // Check if flags are compatible.2445 if (Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))2446 report_fatal_error("Conflicting FPFastMathFlags: ContractionOff "2447 "and AllowContract");2448 2449 if (Info.SignedZeroInfNanPreserve &&2450 !(Flags &2451 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |2452 SPIRV::FPFastMathMode::NSZ))) {2453 if (Info.FPFastMathDefault)2454 report_fatal_error("Conflicting FPFastMathFlags: "2455 "SignedZeroInfNanPreserve but at least one of "2456 "NotNaN/NotInf/NSZ is enabled.");2457 }2458 2459 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&2460 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&2461 (Flags & SPIRV::FPFastMathMode::AllowContract))) {2462 report_fatal_error("Conflicting FPFastMathFlags: "2463 "AllowTransform requires AllowReassoc and "2464 "AllowContract to be set.");2465 }2466 2467 auto it = GlobalVars.find(Flags);2468 GlobalVariable *GV = nullptr;2469 if (it != GlobalVars.end()) {2470 // Reuse existing global variable.2471 GV = it->second;2472 } else {2473 // Create constant instruction with the bitmask flags.2474 Constant *InitValue =2475 ConstantInt::get(Type::getInt32Ty(M.getContext()), Flags);2476 // TODO: Reuse constant if there is one already with the required2477 // value.2478 GV = new GlobalVariable(M, // Module2479 Type::getInt32Ty(M.getContext()), // Type2480 true, // isConstant2481 GlobalValue::InternalLinkage, // Linkage2482 InitValue // Initializer2483 );2484 GlobalVars[Flags] = GV;2485 }2486 }2487 }2488}2489 2490void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,2491 IRBuilder<> &B) {2492 auto *II = dyn_cast<IntrinsicInst>(I);2493 bool IsConstComposite =2494 II && II->getIntrinsicID() == Intrinsic::spv_const_composite;2495 if (IsConstComposite && TrackConstants) {2496 setInsertPointAfterDef(B, I);2497 auto t = AggrConsts.find(I);2498 assert(t != AggrConsts.end());2499 auto *NewOp =2500 buildIntrWithMD(Intrinsic::spv_track_constant,2501 {II->getType(), II->getType()}, t->second, I, {}, B);2502 replaceAllUsesWith(I, NewOp, false);2503 NewOp->setArgOperand(0, I);2504 }2505 bool IsPhi = isa<PHINode>(I), BPrepared = false;2506 for (const auto &Op : I->operands()) {2507 if (isa<PHINode>(I) || isa<SwitchInst>(I) ||2508 !(isa<ConstantData>(Op) || isa<ConstantExpr>(Op)))2509 continue;2510 unsigned OpNo = Op.getOperandNo();2511 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||2512 (II->paramHasAttr(OpNo, Attribute::ImmArg))))2513 continue;2514 2515 if (!BPrepared) {2516 IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())2517 : B.SetInsertPoint(I);2518 BPrepared = true;2519 }2520 Type *OpTy = Op->getType();2521 Type *OpElemTy = GR->findDeducedElementType(Op);2522 Value *NewOp = Op;2523 if (OpTy->isTargetExtTy()) {2524 // Since this value is replaced by poison, we need to do the same in2525 // `insertAssignTypeIntrs`.2526 Value *OpTyVal = getNormalizedPoisonValue(OpTy);2527 NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,2528 {OpTy, OpTyVal->getType()}, Op, OpTyVal, {}, B);2529 }2530 if (!IsConstComposite && isPointerTy(OpTy) && OpElemTy != nullptr &&2531 OpElemTy != IntegerType::getInt8Ty(I->getContext())) {2532 SmallVector<Type *, 2> Types = {OpTy, OpTy};2533 SmallVector<Value *, 2> Args = {2534 NewOp, buildMD(getNormalizedPoisonValue(OpElemTy)),2535 B.getInt32(getPointerAddressSpace(OpTy))};2536 CallInst *PtrCasted =2537 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);2538 GR->buildAssignPtr(B, OpElemTy, PtrCasted);2539 NewOp = PtrCasted;2540 }2541 if (NewOp != Op)2542 I->setOperand(OpNo, NewOp);2543 }2544 if (Named.insert(I).second)2545 emitAssignName(I, B);2546}2547 2548Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F,2549 unsigned OpIdx) {2550 std::unordered_set<Function *> FVisited;2551 return deduceFunParamElementType(F, OpIdx, FVisited);2552}2553 2554Type *SPIRVEmitIntrinsics::deduceFunParamElementType(2555 Function *F, unsigned OpIdx, std::unordered_set<Function *> &FVisited) {2556 // maybe a cycle2557 if (!FVisited.insert(F).second)2558 return nullptr;2559 2560 std::unordered_set<Value *> Visited;2561 SmallVector<std::pair<Function *, unsigned>> Lookup;2562 // search in function's call sites2563 for (User *U : F->users()) {2564 CallInst *CI = dyn_cast<CallInst>(U);2565 if (!CI || OpIdx >= CI->arg_size())2566 continue;2567 Value *OpArg = CI->getArgOperand(OpIdx);2568 if (!isPointerTy(OpArg->getType()))2569 continue;2570 // maybe we already know operand's element type2571 if (Type *KnownTy = GR->findDeducedElementType(OpArg))2572 return KnownTy;2573 // try to deduce from the operand itself2574 Visited.clear();2575 if (Type *Ty = deduceElementTypeHelper(OpArg, Visited, false))2576 return Ty;2577 // search in actual parameter's users2578 for (User *OpU : OpArg->users()) {2579 Instruction *Inst = dyn_cast<Instruction>(OpU);2580 if (!Inst || Inst == CI)2581 continue;2582 Visited.clear();2583 if (Type *Ty = deduceElementTypeHelper(Inst, Visited, false))2584 return Ty;2585 }2586 // check if it's a formal parameter of the outer function2587 if (!CI->getParent() || !CI->getParent()->getParent())2588 continue;2589 Function *OuterF = CI->getParent()->getParent();2590 if (FVisited.find(OuterF) != FVisited.end())2591 continue;2592 for (unsigned i = 0; i < OuterF->arg_size(); ++i) {2593 if (OuterF->getArg(i) == OpArg) {2594 Lookup.push_back(std::make_pair(OuterF, i));2595 break;2596 }2597 }2598 }2599 2600 // search in function parameters2601 for (auto &Pair : Lookup) {2602 if (Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))2603 return Ty;2604 }2605 2606 return nullptr;2607}2608 2609void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,2610 IRBuilder<> &B) {2611 B.SetInsertPointPastAllocas(F);2612 for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {2613 Argument *Arg = F->getArg(OpIdx);2614 if (!isUntypedPointerTy(Arg->getType()))2615 continue;2616 Type *ElemTy = GR->findDeducedElementType(Arg);2617 if (ElemTy)2618 continue;2619 if (hasPointeeTypeAttr(Arg) &&2620 (ElemTy = getPointeeTypeByAttr(Arg)) != nullptr) {2621 GR->buildAssignPtr(B, ElemTy, Arg);2622 continue;2623 }2624 // search in function's call sites2625 for (User *U : F->users()) {2626 CallInst *CI = dyn_cast<CallInst>(U);2627 if (!CI || OpIdx >= CI->arg_size())2628 continue;2629 Value *OpArg = CI->getArgOperand(OpIdx);2630 if (!isPointerTy(OpArg->getType()))2631 continue;2632 // maybe we already know operand's element type2633 if ((ElemTy = GR->findDeducedElementType(OpArg)) != nullptr)2634 break;2635 }2636 if (ElemTy) {2637 GR->buildAssignPtr(B, ElemTy, Arg);2638 continue;2639 }2640 if (HaveFunPtrs) {2641 for (User *U : Arg->users()) {2642 CallInst *CI = dyn_cast<CallInst>(U);2643 if (CI && !isa<IntrinsicInst>(CI) && CI->isIndirectCall() &&2644 CI->getCalledOperand() == Arg &&2645 CI->getParent()->getParent() == CurrF) {2646 SmallVector<std::pair<Value *, unsigned>> Ops;2647 deduceOperandElementTypeFunctionPointer(CI, Ops, ElemTy, false);2648 if (ElemTy) {2649 GR->buildAssignPtr(B, ElemTy, Arg);2650 break;2651 }2652 }2653 }2654 }2655 }2656}2657 2658void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {2659 B.SetInsertPointPastAllocas(F);2660 for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {2661 Argument *Arg = F->getArg(OpIdx);2662 if (!isUntypedPointerTy(Arg->getType()))2663 continue;2664 Type *ElemTy = GR->findDeducedElementType(Arg);2665 if (!ElemTy && (ElemTy = deduceFunParamElementType(F, OpIdx)) != nullptr) {2666 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Arg)) {2667 DenseSet<std::pair<Value *, Value *>> VisitedSubst;2668 GR->updateAssignType(AssignCI, Arg, getNormalizedPoisonValue(ElemTy));2669 propagateElemType(Arg, IntegerType::getInt8Ty(F->getContext()),2670 VisitedSubst);2671 } else {2672 GR->buildAssignPtr(B, ElemTy, Arg);2673 }2674 }2675 }2676}2677 2678static FunctionType *getFunctionPointerElemType(Function *F,2679 SPIRVGlobalRegistry *GR) {2680 FunctionType *FTy = F->getFunctionType();2681 bool IsNewFTy = false;2682 SmallVector<Type *, 4> ArgTys;2683 for (Argument &Arg : F->args()) {2684 Type *ArgTy = Arg.getType();2685 if (ArgTy->isPointerTy())2686 if (Type *ElemTy = GR->findDeducedElementType(&Arg)) {2687 IsNewFTy = true;2688 ArgTy = getTypedPointerWrapper(ElemTy, getPointerAddressSpace(ArgTy));2689 }2690 ArgTys.push_back(ArgTy);2691 }2692 return IsNewFTy2693 ? FunctionType::get(FTy->getReturnType(), ArgTys, FTy->isVarArg())2694 : FTy;2695}2696 2697bool SPIRVEmitIntrinsics::processFunctionPointers(Module &M) {2698 SmallVector<Function *> Worklist;2699 for (auto &F : M) {2700 if (F.isIntrinsic())2701 continue;2702 if (F.isDeclaration()) {2703 for (User *U : F.users()) {2704 CallInst *CI = dyn_cast<CallInst>(U);2705 if (!CI || CI->getCalledFunction() != &F) {2706 Worklist.push_back(&F);2707 break;2708 }2709 }2710 } else {2711 if (F.user_empty())2712 continue;2713 Type *FPElemTy = GR->findDeducedElementType(&F);2714 if (!FPElemTy)2715 FPElemTy = getFunctionPointerElemType(&F, GR);2716 for (User *U : F.users()) {2717 IntrinsicInst *II = dyn_cast<IntrinsicInst>(U);2718 if (!II || II->arg_size() != 3 || II->getOperand(0) != &F)2719 continue;2720 if (II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||2721 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {2722 GR->updateAssignType(II, &F, getNormalizedPoisonValue(FPElemTy));2723 break;2724 }2725 }2726 }2727 }2728 if (Worklist.empty())2729 return false;2730 2731 std::string ServiceFunName = SPIRV_BACKEND_SERVICE_FUN_NAME;2732 if (!getVacantFunctionName(M, ServiceFunName))2733 report_fatal_error(2734 "cannot allocate a name for the internal service function");2735 LLVMContext &Ctx = M.getContext();2736 Function *SF =2737 Function::Create(FunctionType::get(Type::getVoidTy(Ctx), {}, false),2738 GlobalValue::PrivateLinkage, ServiceFunName, M);2739 SF->addFnAttr(SPIRV_BACKEND_SERVICE_FUN_NAME, "");2740 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", SF);2741 IRBuilder<> IRB(BB);2742 2743 for (Function *F : Worklist) {2744 SmallVector<Value *> Args;2745 for (const auto &Arg : F->args())2746 Args.push_back(getNormalizedPoisonValue(Arg.getType()));2747 IRB.CreateCall(F, Args);2748 }2749 IRB.CreateRetVoid();2750 2751 return true;2752}2753 2754// Apply types parsed from demangled function declarations.2755void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) {2756 DenseMap<Function *, CallInst *> Ptrcasts;2757 for (auto It : FDeclPtrTys) {2758 Function *F = It.first;2759 for (auto *U : F->users()) {2760 CallInst *CI = dyn_cast<CallInst>(U);2761 if (!CI || CI->getCalledFunction() != F)2762 continue;2763 unsigned Sz = CI->arg_size();2764 for (auto [Idx, ElemTy] : It.second) {2765 if (Idx >= Sz)2766 continue;2767 Value *Param = CI->getArgOperand(Idx);2768 if (GR->findDeducedElementType(Param) || isa<GlobalValue>(Param))2769 continue;2770 if (Argument *Arg = dyn_cast<Argument>(Param)) {2771 if (!hasPointeeTypeAttr(Arg)) {2772 B.SetInsertPointPastAllocas(Arg->getParent());2773 B.SetCurrentDebugLocation(DebugLoc());2774 GR->buildAssignPtr(B, ElemTy, Arg);2775 }2776 } else if (isa<GetElementPtrInst>(Param)) {2777 replaceUsesOfWithSpvPtrcast(Param, normalizeType(ElemTy), CI,2778 Ptrcasts);2779 } else if (isa<Instruction>(Param)) {2780 GR->addDeducedElementType(Param, normalizeType(ElemTy));2781 // insertAssignTypeIntrs() will complete buildAssignPtr()2782 } else {2783 B.SetInsertPoint(CI->getParent()2784 ->getParent()2785 ->getEntryBlock()2786 .getFirstNonPHIOrDbgOrAlloca());2787 GR->buildAssignPtr(B, ElemTy, Param);2788 }2789 CallInst *Ref = dyn_cast<CallInst>(Param);2790 if (!Ref)2791 continue;2792 Function *RefF = Ref->getCalledFunction();2793 if (!RefF || !isPointerTy(RefF->getReturnType()) ||2794 GR->findDeducedElementType(RefF))2795 continue;2796 ElemTy = normalizeType(ElemTy);2797 GR->addDeducedElementType(RefF, ElemTy);2798 GR->addReturnType(2799 RefF, TypedPointerType::get(2800 ElemTy, getPointerAddressSpace(RefF->getReturnType())));2801 }2802 }2803 }2804}2805 2806GetElementPtrInst *2807SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP) {2808 // getelementptr [0 x T], P, 0 (zero), I -> getelementptr T, P, I.2809 // If type is 0-length array and first index is 0 (zero), drop both the2810 // 0-length array type and the first index. This is a common pattern in2811 // the IR, e.g. when using a zero-length array as a placeholder for a2812 // flexible array such as unbound arrays.2813 assert(GEP && "GEP is null");2814 Type *SrcTy = GEP->getSourceElementType();2815 SmallVector<Value *, 8> Indices(GEP->indices());2816 ArrayType *ArrTy = dyn_cast<ArrayType>(SrcTy);2817 if (ArrTy && ArrTy->getNumElements() == 0 &&2818 PatternMatch::match(Indices[0], PatternMatch::m_Zero())) {2819 IRBuilder<> Builder(GEP);2820 Indices.erase(Indices.begin());2821 SrcTy = ArrTy->getElementType();2822 Value *NewGEP = Builder.CreateGEP(SrcTy, GEP->getPointerOperand(), Indices,2823 "", GEP->getNoWrapFlags());2824 assert(llvm::isa<GetElementPtrInst>(NewGEP) && "NewGEP should be a GEP");2825 return cast<GetElementPtrInst>(NewGEP);2826 }2827 return nullptr;2828}2829 2830bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {2831 if (Func.isDeclaration())2832 return false;2833 2834 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(Func);2835 GR = ST.getSPIRVGlobalRegistry();2836 2837 if (!CurrF)2838 HaveFunPtrs =2839 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);2840 2841 CurrF = &Func;2842 IRBuilder<> B(Func.getContext());2843 AggrConsts.clear();2844 AggrConstTypes.clear();2845 AggrStores.clear();2846 2847 // Fix GEP result types ahead of inference, and simplify if possible.2848 // Data structure for dead instructions that were simplified and replaced.2849 SmallPtrSet<Instruction *, 4> DeadInsts;2850 for (auto &I : instructions(Func)) {2851 auto *Ref = dyn_cast<GetElementPtrInst>(&I);2852 if (!Ref || GR->findDeducedElementType(Ref))2853 continue;2854 2855 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(Ref);2856 if (NewGEP) {2857 Ref->replaceAllUsesWith(NewGEP);2858 DeadInsts.insert(Ref);2859 Ref = NewGEP;2860 }2861 if (Type *GepTy = getGEPType(Ref))2862 GR->addDeducedElementType(Ref, normalizeType(GepTy));2863 }2864 // Remove dead instructions that were simplified and replaced.2865 for (auto *I : DeadInsts) {2866 assert(I->use_empty() && "Dead instruction should not have any uses left");2867 I->eraseFromParent();2868 }2869 2870 processParamTypesByFunHeader(CurrF, B);2871 2872 // StoreInst's operand type can be changed during the next2873 // transformations, so we need to store it in the set. Also store already2874 // transformed types.2875 for (auto &I : instructions(Func)) {2876 StoreInst *SI = dyn_cast<StoreInst>(&I);2877 if (!SI)2878 continue;2879 Type *ElTy = SI->getValueOperand()->getType();2880 if (ElTy->isAggregateType() || ElTy->isVectorTy())2881 AggrStores.insert(&I);2882 }2883 2884 B.SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin());2885 for (auto &GV : Func.getParent()->globals())2886 processGlobalValue(GV, B);2887 2888 preprocessUndefs(B);2889 preprocessCompositeConstants(B);2890 SmallVector<Instruction *> Worklist(2891 llvm::make_pointer_range(instructions(Func)));2892 2893 applyDemangledPtrArgTypes(B);2894 2895 // Pass forward: use operand to deduce instructions result.2896 for (auto &I : Worklist) {2897 // Don't emit intrinsincs for convergence intrinsics.2898 if (isConvergenceIntrinsic(I))2899 continue;2900 2901 bool Postpone = insertAssignPtrTypeIntrs(I, B, false);2902 // if Postpone is true, we can't decide on pointee type yet2903 insertAssignTypeIntrs(I, B);2904 insertPtrCastOrAssignTypeInstr(I, B);2905 insertSpirvDecorations(I, B);2906 // if instruction requires a pointee type set, let's check if we know it2907 // already, and force it to be i8 if not2908 if (Postpone && !GR->findAssignPtrTypeInstr(I))2909 insertAssignPtrTypeIntrs(I, B, true);2910 2911 if (auto *FPI = dyn_cast<ConstrainedFPIntrinsic>(I))2912 useRoundingMode(FPI, B);2913 }2914 2915 // Pass backward: use instructions results to specify/update/cast operands2916 // where needed.2917 SmallPtrSet<Instruction *, 4> IncompleteRets;2918 for (auto &I : llvm::reverse(instructions(Func)))2919 deduceOperandElementType(&I, &IncompleteRets);2920 2921 // Pass forward for PHIs only, their operands are not preceed the2922 // instruction in meaning of `instructions(Func)`.2923 for (BasicBlock &BB : Func)2924 for (PHINode &Phi : BB.phis())2925 if (isPointerTy(Phi.getType()))2926 deduceOperandElementType(&Phi, nullptr);2927 2928 for (auto *I : Worklist) {2929 TrackConstants = true;2930 if (!I->getType()->isVoidTy() || isa<StoreInst>(I))2931 setInsertPointAfterDef(B, I);2932 // Visitors return either the original/newly created instruction for2933 // further processing, nullptr otherwise.2934 I = visit(*I);2935 if (!I)2936 continue;2937 2938 // Don't emit intrinsics for convergence operations.2939 if (isConvergenceIntrinsic(I))2940 continue;2941 2942 addSaturatedDecorationToIntrinsic(I, B);2943 processInstrAfterVisit(I, B);2944 }2945 2946 return true;2947}2948 2949// Try to deduce a better type for pointers to untyped ptr.2950bool SPIRVEmitIntrinsics::postprocessTypes(Module &M) {2951 if (!GR || TodoTypeSz == 0)2952 return false;2953 2954 unsigned SzTodo = TodoTypeSz;2955 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;2956 for (auto [Op, Enabled] : TodoType) {2957 // TODO: add isa<CallInst>(Op) to continue2958 if (!Enabled || isa<GetElementPtrInst>(Op))2959 continue;2960 CallInst *AssignCI = GR->findAssignPtrTypeInstr(Op);2961 Type *KnownTy = GR->findDeducedElementType(Op);2962 if (!KnownTy || !AssignCI)2963 continue;2964 assert(Op == AssignCI->getArgOperand(0));2965 // Try to improve the type deduced after all Functions are processed.2966 if (auto *CI = dyn_cast<Instruction>(Op)) {2967 CurrF = CI->getParent()->getParent();2968 std::unordered_set<Value *> Visited;2969 if (Type *ElemTy = deduceElementTypeHelper(Op, Visited, false, true)) {2970 if (ElemTy != KnownTy) {2971 DenseSet<std::pair<Value *, Value *>> VisitedSubst;2972 propagateElemType(CI, ElemTy, VisitedSubst);2973 eraseTodoType(Op);2974 continue;2975 }2976 }2977 }2978 2979 if (Op->hasUseList()) {2980 for (User *U : Op->users()) {2981 Instruction *Inst = dyn_cast<Instruction>(U);2982 if (Inst && !isa<IntrinsicInst>(Inst))2983 ToProcess[Inst].insert(Op);2984 }2985 }2986 }2987 if (TodoTypeSz == 0)2988 return true;2989 2990 for (auto &F : M) {2991 CurrF = &F;2992 SmallPtrSet<Instruction *, 4> IncompleteRets;2993 for (auto &I : llvm::reverse(instructions(F))) {2994 auto It = ToProcess.find(&I);2995 if (It == ToProcess.end())2996 continue;2997 It->second.remove_if([this](Value *V) { return !isTodoType(V); });2998 if (It->second.size() == 0)2999 continue;3000 deduceOperandElementType(&I, &IncompleteRets, &It->second, true);3001 if (TodoTypeSz == 0)3002 return true;3003 }3004 }3005 3006 return SzTodo > TodoTypeSz;3007}3008 3009// Parse and store argument types of function declarations where needed.3010void SPIRVEmitIntrinsics::parseFunDeclarations(Module &M) {3011 for (auto &F : M) {3012 if (!F.isDeclaration() || F.isIntrinsic())3013 continue;3014 // get the demangled name3015 std::string DemangledName = getOclOrSpirvBuiltinDemangledName(F.getName());3016 if (DemangledName.empty())3017 continue;3018 // allow only OpGroupAsyncCopy use case at the moment3019 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(F);3020 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(3021 DemangledName, ST.getPreferredInstructionSet());3022 if (Opcode != SPIRV::OpGroupAsyncCopy)3023 continue;3024 // find pointer arguments3025 SmallVector<unsigned> Idxs;3026 for (unsigned OpIdx = 0; OpIdx < F.arg_size(); ++OpIdx) {3027 Argument *Arg = F.getArg(OpIdx);3028 if (isPointerTy(Arg->getType()) && !hasPointeeTypeAttr(Arg))3029 Idxs.push_back(OpIdx);3030 }3031 if (!Idxs.size())3032 continue;3033 // parse function arguments3034 LLVMContext &Ctx = F.getContext();3035 SmallVector<StringRef, 10> TypeStrs;3036 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);3037 if (!TypeStrs.size())3038 continue;3039 // find type info for pointer arguments3040 for (unsigned Idx : Idxs) {3041 if (Idx >= TypeStrs.size())3042 continue;3043 if (Type *ElemTy =3044 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))3045 if (TypedPointerType::isValidElementType(ElemTy) &&3046 !ElemTy->isTargetExtTy())3047 FDeclPtrTys[&F].push_back(std::make_pair(Idx, ElemTy));3048 }3049 }3050}3051 3052bool SPIRVEmitIntrinsics::runOnModule(Module &M) {3053 bool Changed = false;3054 3055 parseFunDeclarations(M);3056 insertConstantsForFPFastMathDefault(M);3057 3058 TodoType.clear();3059 for (auto &F : M)3060 Changed |= runOnFunction(F);3061 3062 // Specify function parameters after all functions were processed.3063 for (auto &F : M) {3064 // check if function parameter types are set3065 CurrF = &F;3066 if (!F.isDeclaration() && !F.isIntrinsic()) {3067 IRBuilder<> B(F.getContext());3068 processParamTypes(&F, B);3069 }3070 }3071 3072 CanTodoType = false;3073 Changed |= postprocessTypes(M);3074 3075 if (HaveFunPtrs)3076 Changed |= processFunctionPointers(M);3077 3078 return Changed;3079}3080 3081ModulePass *llvm::createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM) {3082 return new SPIRVEmitIntrinsics(TM);3083}3084