LLVM 23.0.0git
SPIRVEmitIntrinsics.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The pass emits SPIRV intrinsics keeping essential high-level information for
10// the translation of LLVM IR to SPIR-V.
11//
12//===----------------------------------------------------------------------===//
13
14#include "SPIRVEmitIntrinsics.h"
15#include "SPIRV.h"
16#include "SPIRVBuiltins.h"
17#include "SPIRVSubtarget.h"
18#include "SPIRVTargetMachine.h"
19#include "SPIRVUtils.h"
20#include "llvm/ADT/DenseSet.h"
21#include "llvm/ADT/StringSet.h"
23#include "llvm/IR/Dominators.h"
24#include "llvm/IR/IRBuilder.h"
26#include "llvm/IR/InstVisitor.h"
27#include "llvm/IR/IntrinsicsSPIRV.h"
30#include "llvm/IR/Value.h"
32#include "llvm/Support/Debug.h"
34
35#include <cassert>
36#include <optional>
37#include <queue>
38#include <unordered_set>
39
40// This pass performs the following transformation on LLVM IR level required
41// for the following translation to SPIR-V:
42// - replaces direct usages of aggregate constants with target-specific
43// intrinsics;
44// - replaces aggregates-related instructions (extract/insert, ld/st, etc)
45// with a target-specific intrinsics;
46// - emits intrinsics for the global variable initializers since IRTranslator
47// doesn't handle them and it's not very convenient to translate them
48// ourselves;
49// - emits intrinsics to keep track of the string names assigned to the values;
50// - emits intrinsics to keep track of constants (this is necessary to have an
51// LLVM IR constant after the IRTranslation is completed) for their further
52// deduplication;
53// - emits intrinsics to keep track of original LLVM types of the values
54// to be able to emit proper SPIR-V types eventually.
55//
56// TODO: consider removing spv.track.constant in favor of spv.assign.type.
57
58using namespace llvm;
59using namespace llvm::PatternMatch;
60
61#define DEBUG_TYPE "spirv-emit-intrinsics"
62
63static cl::opt<bool>
64 SpirvEmitOpNames("spirv-emit-op-names",
65 cl::desc("Emit OpName for all instructions"),
66 cl::init(false));
67
68namespace llvm::SPIRV {
69#define GET_BuiltinGroup_DECL
70#include "SPIRVGenTables.inc"
71} // namespace llvm::SPIRV
72
73namespace {
74// This class keeps track of which functions reference which global variables.
75class GlobalVariableUsers {
76 template <typename T1, typename T2>
77 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
78
79 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
80
81 void collectGlobalUsers(
82 const GlobalVariable *GV,
83 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
84 &GlobalIsUsedByGlobal) {
86 while (!Stack.empty()) {
87 const Value *V = Stack.pop_back_val();
88
89 if (const Instruction *I = dyn_cast<Instruction>(V)) {
90 GlobalIsUsedByFun[GV].insert(I->getFunction());
91 continue;
92 }
93
94 if (const GlobalVariable *UserGV = dyn_cast<GlobalVariable>(V)) {
95 GlobalIsUsedByGlobal[GV].insert(UserGV);
96 continue;
97 }
98
99 if (const Constant *C = dyn_cast<Constant>(V))
100 Stack.append(C->user_begin(), C->user_end());
101 }
102 }
103
104 bool propagateGlobalToGlobalUsers(
105 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
106 &GlobalIsUsedByGlobal) {
108 bool Changed = false;
109 for (auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
110 OldUsersGlobals.assign(UserGlobals.begin(), UserGlobals.end());
111 for (const GlobalVariable *UserGV : OldUsersGlobals) {
112 auto It = GlobalIsUsedByGlobal.find(UserGV);
113 if (It == GlobalIsUsedByGlobal.end())
114 continue;
115 Changed |= set_union(UserGlobals, It->second);
116 }
117 }
118 return Changed;
119 }
120
121 void propagateGlobalToFunctionReferences(
122 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
123 &GlobalIsUsedByGlobal) {
124 for (auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
125 auto &UserFunctions = GlobalIsUsedByFun[GV];
126 for (const GlobalVariable *UserGV : UserGlobals) {
127 auto It = GlobalIsUsedByFun.find(UserGV);
128 if (It == GlobalIsUsedByFun.end())
129 continue;
130 set_union(UserFunctions, It->second);
131 }
132 }
133 }
134
135public:
136 void init(Module &M) {
137 // Collect which global variables are referenced by which global variables
138 // and which functions reference each global variables.
139 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
140 GlobalIsUsedByGlobal;
141 GlobalIsUsedByFun.clear();
142 for (GlobalVariable &GV : M.globals())
143 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
144
145 // Compute indirect references by iterating until a fixed point is reached.
146 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
147 (void)0;
148
149 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
150 }
151
152 using FunctionSetType = typename decltype(GlobalIsUsedByFun)::mapped_type;
153 const FunctionSetType &
154 getTransitiveUserFunctions(const GlobalVariable &GV) const {
155 auto It = GlobalIsUsedByFun.find(&GV);
156 if (It != GlobalIsUsedByFun.end())
157 return It->second;
158
159 static const FunctionSetType Empty{};
160 return Empty;
161 }
162};
163
164static bool isaGEP(const Value *V) {
166}
167
168// If Ty is a byte-addressing type, return the multiplier for the offset.
169// Otherwise return std::nullopt.
170static std::optional<uint64_t> getByteAddressingMultiplier(Type *Ty) {
171 if (Ty == IntegerType::getInt8Ty(Ty->getContext())) {
172 return 1;
173 }
174 if (auto *AT = dyn_cast<ArrayType>(Ty)) {
175 if (AT->getElementType() == IntegerType::getInt8Ty(Ty->getContext())) {
176 return AT->getNumElements();
177 }
178 }
179 return std::nullopt;
180}
181
182class SPIRVEmitIntrinsics
183 : public ModulePass,
184 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
185 const SPIRVTargetMachine &TM;
186 SPIRVGlobalRegistry *GR = nullptr;
187 Function *CurrF = nullptr;
188 bool TrackConstants = true;
189 bool HaveFunPtrs = false;
190 DenseMap<Instruction *, Constant *> AggrConsts;
191 DenseMap<Instruction *, Type *> AggrConstTypes;
192 DenseSet<Instruction *> AggrStores;
193 SmallPtrSet<Instruction *, 8> DeletedInstrs;
194 GlobalVariableUsers GVUsers;
195 std::unordered_set<Value *> Named;
196
197 // map of function declarations to <pointer arg index => element type>
198 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
199
200 // a register of Instructions that don't have a complete type definition
201 bool CanTodoType = true;
202 unsigned TodoTypeSz = 0;
203 DenseMap<Value *, bool> TodoType;
204 void insertTodoType(Value *Op) {
205 // TODO: add isa<CallInst>(Op) to no-insert
206 if (CanTodoType && !isaGEP(Op)) {
207 auto It = TodoType.try_emplace(Op, true);
208 if (It.second)
209 ++TodoTypeSz;
210 }
211 }
212 void eraseTodoType(Value *Op) {
213 auto It = TodoType.find(Op);
214 if (It != TodoType.end() && It->second) {
215 It->second = false;
216 --TodoTypeSz;
217 }
218 }
219 bool isTodoType(Value *Op) {
220 if (isaGEP(Op))
221 return false;
222 auto It = TodoType.find(Op);
223 return It != TodoType.end() && It->second;
224 }
225 // a register of Instructions that were visited by deduceOperandElementType()
226 // to validate operand types with an instruction
227 std::unordered_set<Instruction *> TypeValidated;
228
229 // well known result types of builtins
230 enum WellKnownTypes { Event };
231
232 // deduce element type of untyped pointers
233 Type *deduceElementType(Value *I, bool UnknownElemTypeI8);
234 Type *deduceElementTypeHelper(Value *I, bool UnknownElemTypeI8);
235 Type *deduceElementTypeHelper(Value *I, std::unordered_set<Value *> &Visited,
236 bool UnknownElemTypeI8,
237 bool IgnoreKnownType = false);
238 Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
239 bool UnknownElemTypeI8);
240 Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
241 std::unordered_set<Value *> &Visited,
242 bool UnknownElemTypeI8);
243 Type *deduceElementTypeByUsersDeep(Value *Op,
244 std::unordered_set<Value *> &Visited,
245 bool UnknownElemTypeI8);
246 void maybeAssignPtrType(Type *&Ty, Value *I, Type *RefTy,
247 bool UnknownElemTypeI8);
248
249 // deduce nested types of composites
250 Type *deduceNestedTypeHelper(User *U, bool UnknownElemTypeI8);
251 Type *deduceNestedTypeHelper(User *U, Type *Ty,
252 std::unordered_set<Value *> &Visited,
253 bool UnknownElemTypeI8);
254
255 // deduce Types of operands of the Instruction if possible
256 void deduceOperandElementType(Instruction *I,
257 SmallPtrSet<Instruction *, 4> *IncompleteRets,
258 const SmallPtrSet<Value *, 4> *AskOps = nullptr,
259 bool IsPostprocessing = false);
260
261 void preprocessCompositeConstants(IRBuilder<> &B);
262 void preprocessUndefs(IRBuilder<> &B);
263 void preprocessPoisons(IRBuilder<> &B);
264 void simplifyNullAddrSpaceCasts();
265
266 Type *reconstructType(Value *Op, bool UnknownElemTypeI8,
267 bool IsPostprocessing);
268
269 void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
270 void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);
271 bool insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B,
272 bool UnknownElemTypeI8);
273 void insertAssignTypeIntrs(Instruction *I, IRBuilder<> &B);
274 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType, Value *V,
275 IRBuilder<> &B);
276 void replacePointerOperandWithPtrCast(Instruction *I, Value *Pointer,
277 Type *ExpectedElementType,
278 unsigned OperandToReplace,
279 IRBuilder<> &B);
280 void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
281 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
282 void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);
283 void insertConstantsForFPFastMathDefault(Module &M);
284 Value *buildSpvUndefComposite(Type *AggrTy, IRBuilder<> &B);
285 void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
286 void processParamTypes(Function *F, IRBuilder<> &B);
287 void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
288 Type *deduceFunParamElementType(Function *F, unsigned OpIdx);
289 Type *deduceFunParamElementType(Function *F, unsigned OpIdx,
290 std::unordered_set<Function *> &FVisited);
291
292 bool deduceOperandElementTypeCalledFunction(
293 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
294 Type *&KnownElemTy, bool &Incomplete);
295 void deduceOperandElementTypeFunctionPointer(
296 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
297 Type *&KnownElemTy, bool IsPostprocessing);
298 bool deduceOperandElementTypeFunctionRet(
299 Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
300 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,
301 Type *&KnownElemTy, Value *Op, Function *F);
302
303 CallInst *buildSpvPtrcast(Function *F, Value *Op, Type *ElemTy);
304 void replaceUsesOfWithSpvPtrcast(Value *Op, Type *ElemTy, Instruction *I,
305 DenseMap<Function *, CallInst *> Ptrcasts);
306 void propagateElemType(Value *Op, Type *ElemTy,
307 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
308 void
309 propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,
310 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
311 void propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,
312 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
313 std::unordered_set<Value *> &Visited,
314 DenseMap<Function *, CallInst *> Ptrcasts);
315
316 void replaceAllUsesWith(Value *Src, Value *Dest, bool DeleteOld = true);
317 void replaceAllUsesWithAndErase(IRBuilder<> &B, Instruction *Src,
318 Instruction *Dest, bool DeleteOld = true);
319
320 void applyDemangledPtrArgTypes(IRBuilder<> &B);
321
322 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP);
323
324 bool runOnFunction(Function &F);
325 bool postprocessTypes(Module &M);
326 bool processFunctionPointers(Module &M);
327 void parseFunDeclarations(Module &M);
328 void useRoundingMode(ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
329 bool processMaskedMemIntrinsic(IntrinsicInst &I);
330 bool convertMaskedMemIntrinsics(Module &M);
331 void preprocessBoolVectorBitcasts(Function &F);
332
333 void emitUnstructuredLoopControls(Function &F, IRBuilder<> &B);
334
335 // Tries to walk the type accessed by the given GEP instruction.
336 // For each nested type access, one of the 2 callbacks is called:
337 // - OnLiteralIndexing when the index is a known constant value.
338 // Parameters:
339 // PointedType: the pointed type resulting of this indexing.
340 // If the parent type is an array, this is the index in the array.
341 // If the parent type is a struct, this is the field index.
342 // Index: index of the element in the parent type.
343 // - OnDynamnicIndexing when the index is a non-constant value.
344 // This callback is only called when indexing into an array.
345 // Parameters:
346 // ElementType: the type of the elements stored in the parent array.
347 // Offset: the Value* containing the byte offset into the array.
348 // Multiplier: a scaling factor for the offset.
349 // Return true if an error occurred during the walk, false otherwise.
350 bool walkLogicalAccessChain(
351 GetElementPtrInst &GEP,
352 const std::function<void(Type *PointedType, uint64_t Index)>
353 &OnLiteralIndexing,
354 const std::function<void(Type *ElementType, Value *Offset,
355 uint64_t Multiplier)> &OnDynamicIndexing);
356
357 bool walkLogicalAccessChainDynamic(
358 Type *CurType, Value *Operand, uint64_t Multiplier,
359 const std::function<void(Type *, uint64_t)> &OnLiteralIndexing,
360 const std::function<void(Type *, Value *, uint64_t)> &OnDynamicIndexing);
361
362 bool walkLogicalAccessChainConstant(
363 Type *CurType, uint64_t Offset,
364 const std::function<void(Type *, uint64_t)> &OnLiteralIndexing);
365
366 // Returns the type accessed using the given GEP instruction by relying
367 // on the GEP type.
368 // FIXME: GEP types are not supposed to be used to retrieve the pointed
369 // type. This must be fixed.
370 Type *getGEPType(GetElementPtrInst *GEP);
371
372 // Returns the type accessed using the given GEP instruction by walking
373 // the source type using the GEP indices.
374 // FIXME: without help from the frontend, this method cannot reliably retrieve
375 // the stored type, nor can robustly determine the depth of the type
376 // we are accessing.
377 Type *getGEPTypeLogical(GetElementPtrInst *GEP);
378
379 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &GEP);
380
381public:
382 static char ID;
383 SPIRVEmitIntrinsics(const SPIRVTargetMachine &TM) : ModulePass(ID), TM(TM) {}
384 Instruction *visitInstruction(Instruction &I) { return &I; }
385 Instruction *visitSwitchInst(SwitchInst &I);
386 Instruction *visitGetElementPtrInst(GetElementPtrInst &I);
387 Instruction *visitIntrinsicInst(IntrinsicInst &I);
388 Instruction *visitBitCastInst(BitCastInst &I);
389 Instruction *visitInsertElementInst(InsertElementInst &I);
390 Instruction *visitExtractElementInst(ExtractElementInst &I);
391 Instruction *visitInsertValueInst(InsertValueInst &I);
392 Instruction *visitExtractValueInst(ExtractValueInst &I);
393 Instruction *visitLoadInst(LoadInst &I);
394 Instruction *visitStoreInst(StoreInst &I);
395 Instruction *visitAllocaInst(AllocaInst &I);
396 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
397 Instruction *visitUnreachableInst(UnreachableInst &I);
398 Instruction *visitCallInst(CallInst &I);
399
400 StringRef getPassName() const override { return "SPIRV emit intrinsics"; }
401
402 bool runOnModule(Module &M) override;
403
404 void getAnalysisUsage(AnalysisUsage &AU) const override {
405 ModulePass::getAnalysisUsage(AU);
406 }
407};
408
409bool isConvergenceIntrinsic(const Instruction *I) {
410 return match(I, m_AnyIntrinsic<Intrinsic::experimental_convergence_entry,
411 Intrinsic::experimental_convergence_loop,
412 Intrinsic::experimental_convergence_anchor>());
413}
414
415bool expectIgnoredInIRTranslation(const Instruction *I) {
416 return match(I, m_AnyIntrinsic<Intrinsic::invariant_start,
417 Intrinsic::spv_resource_handlefrombinding,
418 Intrinsic::spv_resource_getbasepointer,
419 Intrinsic::spv_resource_getpointer>());
420}
421
422// Returns the source pointer from `I` ignoring intermediate ptrcast.
423Value *getPointerRoot(Value *I) {
424 Value *V;
426 return getPointerRoot(V);
427 return I;
428}
429
430} // namespace
431
432char SPIRVEmitIntrinsics::ID = 0;
433
434INITIALIZE_PASS(SPIRVEmitIntrinsics, "spirv-emit-intrinsics",
435 "SPIRV emit intrinsics", false, false)
436
437static inline bool isAssignTypeInstr(const Instruction *I) {
439}
440
445
446static bool isAggrConstForceInt32(const Value *V) {
447 bool IsAggrZero =
448 isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy();
449 bool IsUndefAggregate = isa<UndefValue>(V) && V->getType()->isAggregateType();
450 return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||
451 isa<ConstantDataArray>(V) || IsAggrZero || IsUndefAggregate;
452}
453
459
461 if (isa<PHINode>(I))
462 B.SetInsertPoint(I->getParent()->getFirstNonPHIOrDbgOrAlloca());
463 else
464 B.SetInsertPoint(I);
465}
466
468 B.SetCurrentDebugLocation(I->getDebugLoc());
469 if (I->getType()->isVoidTy())
470 B.SetInsertPoint(I->getNextNode());
471 else
472 B.SetInsertPoint(*I->getInsertionPointAfterDef());
473}
474
480
481static inline void reportFatalOnTokenType(const Instruction *I) {
482 if (I->getType()->isTokenTy())
483 report_fatal_error("A token is encountered but SPIR-V without extensions "
484 "does not support token type",
485 false);
486}
487
489 if (!I->hasName() || I->getType()->isAggregateType() ||
490 expectIgnoredInIRTranslation(I))
491 return;
492
493 // We want to be conservative when adding the names because they can interfere
494 // with later optimizations.
495 bool KeepName = SpirvEmitOpNames;
496 if (!KeepName) {
497 if (isa<AllocaInst>(I)) {
498 KeepName = true;
499 } else if (auto *CI = dyn_cast<CallBase>(I)) {
500 Function *F = CI->getCalledFunction();
501 if (F && F->getName().starts_with("llvm.spv.alloca"))
502 KeepName = true;
503 }
504 }
505
506 if (!KeepName)
507 return;
508
511 LLVMContext &Ctx = I->getContext();
512 std::vector<Value *> Args = {
514 Ctx, MDNode::get(Ctx, MDString::get(Ctx, I->getName())))};
515 B.CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);
516}
517
518void SPIRVEmitIntrinsics::replaceAllUsesWith(Value *Src, Value *Dest,
519 bool DeleteOld) {
520 GR->replaceAllUsesWith(Src, Dest, DeleteOld);
521 // Update uncomplete type records if any
522 if (isTodoType(Src)) {
523 if (DeleteOld)
524 eraseTodoType(Src);
525 insertTodoType(Dest);
526 }
527}
528
529void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(IRBuilder<> &B,
530 Instruction *Src,
531 Instruction *Dest,
532 bool DeleteOld) {
533 replaceAllUsesWith(Src, Dest, DeleteOld);
534 std::string Name = Src->hasName() ? Src->getName().str() : "";
535 Src->eraseFromParent();
536 if (!Name.empty()) {
537 Dest->setName(Name);
538 if (Named.insert(Dest).second)
539 emitAssignName(Dest, B);
540 }
541}
542
544 return SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&
545 isPointerTy(SI->getValueOperand()->getType()) &&
546 isa<Argument>(SI->getValueOperand());
547}
548
549// Maybe restore original function return type.
551 Type *Ty) {
553 if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||
555 return Ty;
556 if (Type *OriginalTy = GR->findMutated(CI->getCalledFunction()))
557 return OriginalTy;
558 return Ty;
559}
560
561// Reconstruct type with nested element types according to deduced type info.
562// Return nullptr if no detailed type info is available.
563Type *SPIRVEmitIntrinsics::reconstructType(Value *Op, bool UnknownElemTypeI8,
564 bool IsPostprocessing) {
565 Type *Ty = Op->getType();
566 if (auto *OpI = dyn_cast<Instruction>(Op)) {
567 Ty = restoreMutatedType(GR, OpI, Ty);
568 if (auto It = AggrConstTypes.find(OpI); It != AggrConstTypes.end())
569 Ty = It->second;
570 }
571 if (!isUntypedPointerTy(Ty))
572 return Ty;
573 // try to find the pointee type
574 if (Type *NestedTy = GR->findDeducedElementType(Op))
576 // not a pointer according to the type info (e.g., Event object)
577 CallInst *CI = GR->findAssignPtrTypeInstr(Op);
578 if (CI) {
579 MetadataAsValue *MD = cast<MetadataAsValue>(CI->getArgOperand(1));
580 return cast<ConstantAsMetadata>(MD->getMetadata())->getType();
581 }
582 if (UnknownElemTypeI8) {
583 if (!IsPostprocessing)
584 insertTodoType(Op);
585 return getTypedPointerWrapper(IntegerType::getInt8Ty(Op->getContext()),
587 }
588 return nullptr;
589}
590
591CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,
592 Type *ElemTy) {
593 IRBuilder<> B(Op->getContext());
594 if (auto *OpI = dyn_cast<Instruction>(Op)) {
595 // spv_ptrcast's argument Op denotes an instruction that generates
596 // a value, and we may use getInsertionPointAfterDef()
598 } else if (auto *OpA = dyn_cast<Argument>(Op)) {
599 B.SetInsertPointPastAllocas(OpA->getParent());
600 B.SetCurrentDebugLocation(DebugLoc());
601 } else {
602 B.SetInsertPoint(F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
603 }
604 Type *OpTy = Op->getType();
605 SmallVector<Type *, 2> Types = {OpTy, OpTy};
606 SmallVector<Value *, 2> Args = {Op, buildMD(getNormalizedPoisonValue(ElemTy)),
607 B.getInt32(getPointerAddressSpace(OpTy))};
608 CallInst *PtrCasted =
609 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
610 GR->buildAssignPtr(B, ElemTy, PtrCasted);
611 return PtrCasted;
612}
613
614void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
615 Value *Op, Type *ElemTy, Instruction *I,
616 DenseMap<Function *, CallInst *> Ptrcasts) {
617 Function *F = I->getParent()->getParent();
618 CallInst *PtrCastedI = nullptr;
619 auto It = Ptrcasts.find(F);
620 if (It == Ptrcasts.end()) {
621 PtrCastedI = buildSpvPtrcast(F, Op, ElemTy);
622 Ptrcasts[F] = PtrCastedI;
623 } else {
624 PtrCastedI = It->second;
625 }
626 I->replaceUsesOfWith(Op, PtrCastedI);
627}
628
629void SPIRVEmitIntrinsics::propagateElemType(
630 Value *Op, Type *ElemTy,
631 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
632 DenseMap<Function *, CallInst *> Ptrcasts;
633 SmallVector<User *> Users(Op->users());
634 for (auto *U : Users) {
635 if (!isa<Instruction>(U) || isSpvIntrinsic(U))
636 continue;
637 if (!VisitedSubst.insert(std::make_pair(U, Op)).second)
638 continue;
640 // If the instruction was validated already, we need to keep it valid by
641 // keeping current Op type.
642 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
643 replaceUsesOfWithSpvPtrcast(Op, ElemTy, UI, Ptrcasts);
644 }
645}
646
647void SPIRVEmitIntrinsics::propagateElemTypeRec(
648 Value *Op, Type *PtrElemTy, Type *CastElemTy,
649 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
650 std::unordered_set<Value *> Visited;
651 DenseMap<Function *, CallInst *> Ptrcasts;
652 propagateElemTypeRec(Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
653 std::move(Ptrcasts));
654}
655
656void SPIRVEmitIntrinsics::propagateElemTypeRec(
657 Value *Op, Type *PtrElemTy, Type *CastElemTy,
658 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
659 std::unordered_set<Value *> &Visited,
660 DenseMap<Function *, CallInst *> Ptrcasts) {
661 if (!Visited.insert(Op).second)
662 return;
663 SmallVector<User *> Users(Op->users());
664 for (auto *U : Users) {
665 if (!isa<Instruction>(U) || isSpvIntrinsic(U))
666 continue;
667 if (!VisitedSubst.insert(std::make_pair(U, Op)).second)
668 continue;
670 // If the instruction was validated already, we need to keep it valid by
671 // keeping current Op type.
672 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
673 replaceUsesOfWithSpvPtrcast(Op, CastElemTy, UI, Ptrcasts);
674 }
675}
676
677// Set element pointer type to the given value of ValueTy and tries to
678// specify this type further (recursively) by Operand value, if needed.
679
680Type *
681SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
682 bool UnknownElemTypeI8) {
683 std::unordered_set<Value *> Visited;
684 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
685 UnknownElemTypeI8);
686}
687
688Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
689 Type *ValueTy, Value *Operand, std::unordered_set<Value *> &Visited,
690 bool UnknownElemTypeI8) {
691 Type *Ty = ValueTy;
692 if (Operand) {
693 if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
694 if (Type *NestedTy =
695 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
696 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
697 } else {
698 Ty = deduceNestedTypeHelper(dyn_cast<User>(Operand), Ty, Visited,
699 UnknownElemTypeI8);
700 }
701 }
702 return Ty;
703}
704
705// Traverse User instructions to deduce an element pointer type of the operand.
706Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
707 Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {
708 if (!Op || !isPointerTy(Op->getType()) || isa<ConstantPointerNull>(Op) ||
710 return nullptr;
711
712 if (auto ElemTy = getPointeeType(Op->getType()))
713 return ElemTy;
714
715 // maybe we already know operand's element type
716 if (Type *KnownTy = GR->findDeducedElementType(Op))
717 return KnownTy;
718
719 for (User *OpU : Op->users()) {
720 if (Instruction *Inst = dyn_cast<Instruction>(OpU)) {
721 if (Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
722 return Ty;
723 }
724 }
725 return nullptr;
726}
727
728// Implements what we know in advance about intrinsics and builtin calls
729// TODO: consider feasibility of this particular case to be generalized by
730// encoding knowledge about intrinsics and builtin calls by corresponding
731// specification rules
733 Function *CalledF, unsigned OpIdx) {
734 if ((DemangledName.starts_with("__spirv_ocl_printf(") ||
735 DemangledName.starts_with("printf(")) &&
736 OpIdx == 0)
737 return IntegerType::getInt8Ty(CalledF->getContext());
738 return nullptr;
739}
740
741// Deduce and return a successfully deduced Type of the Instruction,
742// or nullptr otherwise.
743Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
744 bool UnknownElemTypeI8) {
745 std::unordered_set<Value *> Visited;
746 return deduceElementTypeHelper(I, Visited, UnknownElemTypeI8);
747}
748
749void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,
750 bool UnknownElemTypeI8) {
751 if (isUntypedPointerTy(RefTy)) {
752 if (!UnknownElemTypeI8)
753 return;
754 insertTodoType(Op);
756 return;
757 }
758 Ty = RefTy;
759}
760
761bool SPIRVEmitIntrinsics::walkLogicalAccessChainDynamic(
762 Type *CurType, Value *Operand, uint64_t Multiplier,
763 const std::function<void(Type *, uint64_t)> &OnLiteralIndexing,
764 const std::function<void(Type *, Value *, uint64_t)> &OnDynamicIndexing) {
765 // Dynamic indexing into a struct is not possible.
766 // We know that we must be accessing the first element
767 // of the struct if the current type is a struct.
768 // Try to find the first array type that is at offset 0 in the struct.
769 while (auto *ST = dyn_cast<StructType>(CurType)) {
770 if (ST->getNumElements() > 0) {
771 CurType = ST->getElementType(0);
772 OnLiteralIndexing(CurType, 0);
773 continue;
774 }
775 }
776
777 assert(CurType);
778 ArrayType *AT = dyn_cast<ArrayType>(CurType);
779 // Operand is not constant. Either we have an array and accept it, or we
780 // give up.
781 if (AT)
782 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
783 return AT == nullptr;
784}
785
786bool SPIRVEmitIntrinsics::walkLogicalAccessChainConstant(
787 Type *CurType, uint64_t Offset,
788 const std::function<void(Type *, uint64_t)> &OnLiteralIndexing) {
789 auto &DL = CurrF->getDataLayout();
790
791 do {
792 if (ArrayType *AT = dyn_cast<ArrayType>(CurType)) {
793 uint32_t EltTypeSize = DL.getTypeSizeInBits(AT->getElementType()) / 8;
794 assert(Offset < AT->getNumElements() * EltTypeSize);
795 uint64_t Index = Offset / EltTypeSize;
796 Offset = Offset - (Index * EltTypeSize);
797 CurType = AT->getElementType();
798 OnLiteralIndexing(CurType, Index);
799 } else if (StructType *ST = dyn_cast<StructType>(CurType)) {
800 uint32_t StructSize = DL.getTypeSizeInBits(ST) / 8;
801 assert(Offset < StructSize);
802 (void)StructSize;
803 const auto &STL = DL.getStructLayout(ST);
804 unsigned Element = STL->getElementContainingOffset(Offset);
805 Offset -= STL->getElementOffset(Element);
806 CurType = ST->getElementType(Element);
807 OnLiteralIndexing(CurType, Element);
808 } else if (auto *VT = dyn_cast<FixedVectorType>(CurType)) {
809 Type *EltTy = VT->getElementType();
810 TypeSize EltSizeBits = DL.getTypeSizeInBits(EltTy);
811 assert(EltSizeBits % 8 == 0 &&
812 "Element type size in bits must be a multiple of 8.");
813 uint32_t EltTypeSize = EltSizeBits / 8;
814 assert(Offset < VT->getNumElements() * EltTypeSize);
815 uint64_t Index = Offset / EltTypeSize;
816 Offset -= Index * EltTypeSize;
817 CurType = EltTy;
818 OnLiteralIndexing(CurType, Index);
819 } else {
820 // Unknown composite kind; give up.
821 return true;
822 }
823 } while (Offset > 0);
824
825 return false;
826}
827
828bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
829 GetElementPtrInst &GEP,
830 const std::function<void(Type *, uint64_t)> &OnLiteralIndexing,
831 const std::function<void(Type *, Value *, uint64_t)> &OnDynamicIndexing) {
832 // We only rewrite byte-addressing GEP. Other should be left as-is.
833 // Valid byte-addressing GEP must always have a single index.
834 std::optional<uint64_t> MultiplierOpt =
835 getByteAddressingMultiplier(GEP.getSourceElementType());
836 assert(MultiplierOpt && "We only rewrite byte-addressing GEP");
837 uint64_t Multiplier = *MultiplierOpt;
838 assert(GEP.getNumIndices() == 1);
839
840 Value *Src = getPointerRoot(GEP.getPointerOperand());
841 Type *CurType = deduceElementType(Src, true);
842
843 Value *Operand = *GEP.idx_begin();
844 if (ConstantInt *CI = dyn_cast<ConstantInt>(Operand))
845 return walkLogicalAccessChainConstant(
846 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
847
848 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
849 OnLiteralIndexing, OnDynamicIndexing);
850}
851
853SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &GEP) {
854 auto &DL = CurrF->getDataLayout();
855 IRBuilder<> B(GEP.getParent());
856 B.SetInsertPoint(&GEP);
857
858 std::vector<Value *> Indices;
859 Indices.push_back(ConstantInt::get(
860 IntegerType::getInt32Ty(CurrF->getContext()), 0, /* Signed= */ false));
861 walkLogicalAccessChain(
862 GEP,
863 [&Indices, &B](Type *EltType, uint64_t Index) {
864 Indices.push_back(
865 ConstantInt::get(B.getInt64Ty(), Index, /* Signed= */ false));
866 },
867 [&Indices, &B, &DL, this](Type *EltType, Value *Offset,
868 uint64_t Multiplier) {
869 Value *Index = nullptr;
870 uint32_t EltTypeSize = DL.getTypeSizeInBits(EltType) / 8;
871 assert(Multiplier != 0);
872 if (Multiplier == EltTypeSize) {
873 Index = Offset;
874 } else if (EltTypeSize % Multiplier == 0) {
875 Index =
876 B.CreateUDiv(Offset, ConstantInt::get(Offset->getType(),
877 EltTypeSize / Multiplier,
878 /* Signed= */ false));
879 } else {
880 Index = B.CreateMul(Offset,
881 ConstantInt::get(Offset->getType(), Multiplier,
882 /* Signed= */ false));
883 insertAssignTypeIntrs(cast<Instruction>(Index), B);
884 Index = B.CreateUDiv(Index,
885 ConstantInt::get(Offset->getType(), EltTypeSize,
886 /* Signed= */ false));
887 }
888 insertAssignTypeIntrs(cast<Instruction>(Index), B);
889 Indices.push_back(Index);
890 });
891
892 SmallVector<Type *, 2> Types = {GEP.getType(), GEP.getOperand(0)->getType()};
893 SmallVector<Value *, 4> Args;
894 Args.push_back(B.getInt1(GEP.isInBounds()));
895 Args.push_back(GEP.getOperand(0));
896 llvm::append_range(Args, Indices);
897 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
898 replaceAllUsesWithAndErase(B, &GEP, NewI);
899 return NewI;
900}
901
902Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *GEP) {
903
904 Type *CurType = GEP->getResultElementType();
905
906 bool Interrupted = walkLogicalAccessChain(
907 *GEP, [&CurType](Type *EltType, uint64_t Index) { CurType = EltType; },
908 [&CurType](Type *EltType, Value *Index, uint64_t) { CurType = EltType; });
909
910 return Interrupted ? GEP->getResultElementType() : CurType;
911}
912
913Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *Ref) {
914 if (getByteAddressingMultiplier(Ref->getSourceElementType()) &&
916 return getGEPTypeLogical(Ref);
917 }
918
919 Type *Ty = nullptr;
920 // TODO: not sure if GetElementPtrInst::getTypeAtIndex() does anything
921 // useful here
922 if (isNestedPointer(Ref->getSourceElementType())) {
923 Ty = Ref->getSourceElementType();
924 for (Use &U : drop_begin(Ref->indices()))
925 Ty = GetElementPtrInst::getTypeAtIndex(Ty, U.get());
926 } else {
927 Ty = Ref->getResultElementType();
928 }
929 return Ty;
930}
931
932Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
933 Value *I, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8,
934 bool IgnoreKnownType) {
935 // allow to pass nullptr as an argument
936 if (!I)
937 return nullptr;
938
939 // maybe already known
940 if (!IgnoreKnownType)
941 if (Type *KnownTy = GR->findDeducedElementType(I))
942 return KnownTy;
943
944 // maybe a cycle
945 if (!Visited.insert(I).second)
946 return nullptr;
947
948 // fallback value in case when we fail to deduce a type
949 Type *Ty = nullptr;
950 // look for known basic patterns of type inference
951 if (auto *Ref = dyn_cast<AllocaInst>(I)) {
952 maybeAssignPtrType(Ty, I, Ref->getAllocatedType(), UnknownElemTypeI8);
953 } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
954 Ty = getGEPType(Ref);
955 } else if (auto *SGEP = dyn_cast<StructuredGEPInst>(I)) {
956 Ty = SGEP->getResultElementType();
957 } else if (auto *Ref = dyn_cast<LoadInst>(I)) {
958 Value *Op = Ref->getPointerOperand();
959 Type *KnownTy = GR->findDeducedElementType(Op);
960 if (!KnownTy)
961 KnownTy = Op->getType();
962 if (Type *ElemTy = getPointeeType(KnownTy))
963 maybeAssignPtrType(Ty, I, ElemTy, UnknownElemTypeI8);
964 } else if (auto *Ref = dyn_cast<GlobalValue>(I)) {
965 if (auto *Fn = dyn_cast<Function>(Ref)) {
966 Ty = SPIRV::getOriginalFunctionType(*Fn);
967 GR->addDeducedElementType(I, Ty);
968 } else {
969 Ty = deduceElementTypeByValueDeep(
970 Ref->getValueType(),
971 Ref->getNumOperands() > 0 ? Ref->getOperand(0) : nullptr, Visited,
972 UnknownElemTypeI8);
973 }
974 } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {
975 Type *RefTy = deduceElementTypeHelper(Ref->getPointerOperand(), Visited,
976 UnknownElemTypeI8);
977 maybeAssignPtrType(Ty, I, RefTy, UnknownElemTypeI8);
978 } else if (auto *Ref = dyn_cast<IntToPtrInst>(I)) {
979 maybeAssignPtrType(Ty, I, Ref->getDestTy(), UnknownElemTypeI8);
980 } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {
981 if (Type *Src = Ref->getSrcTy(), *Dest = Ref->getDestTy();
982 isPointerTy(Src) && isPointerTy(Dest))
983 Ty = deduceElementTypeHelper(Ref->getOperand(0), Visited,
984 UnknownElemTypeI8);
985 } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {
986 Value *Op = Ref->getNewValOperand();
987 if (isPointerTy(Op->getType()))
988 Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
989 } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {
990 Value *Op = Ref->getValOperand();
991 if (isPointerTy(Op->getType()))
992 Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
993 } else if (auto *Ref = dyn_cast<PHINode>(I)) {
994 Type *BestTy = nullptr;
995 unsigned MaxN = 1;
996 DenseMap<Type *, unsigned> PhiTys;
997 for (int i = Ref->getNumIncomingValues() - 1; i >= 0; --i) {
998 Ty = deduceElementTypeByUsersDeep(Ref->getIncomingValue(i), Visited,
999 UnknownElemTypeI8);
1000 if (!Ty)
1001 continue;
1002 auto It = PhiTys.try_emplace(Ty, 1);
1003 if (!It.second) {
1004 ++It.first->second;
1005 if (It.first->second > MaxN) {
1006 MaxN = It.first->second;
1007 BestTy = Ty;
1008 }
1009 }
1010 }
1011 if (BestTy)
1012 Ty = BestTy;
1013 } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
1014 for (Value *Op : {Ref->getTrueValue(), Ref->getFalseValue()}) {
1015 Ty = deduceElementTypeByUsersDeep(Op, Visited, UnknownElemTypeI8);
1016 if (Ty)
1017 break;
1018 }
1019 } else if (auto *CI = dyn_cast<CallInst>(I)) {
1020 static StringMap<unsigned> ResTypeByArg = {
1021 {"to_global", 0},
1022 {"to_local", 0},
1023 {"to_private", 0},
1024 {"__spirv_GenericCastToPtr_ToGlobal", 0},
1025 {"__spirv_GenericCastToPtr_ToLocal", 0},
1026 {"__spirv_GenericCastToPtr_ToPrivate", 0},
1027 {"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1028 {"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1029 {"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1030 // TODO: maybe improve performance by caching demangled names
1031
1032 auto *II = dyn_cast<IntrinsicInst>(I);
1033 if (II && (II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1034 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1035 auto *HandleType = cast<TargetExtType>(II->getOperand(0)->getType());
1036 if (HandleType->getTargetExtName() == "spirv.Image" ||
1037 HandleType->getTargetExtName() == "spirv.SignedImage") {
1038 for (User *U : II->users()) {
1039 Ty = cast<Instruction>(U)->getAccessType();
1040 if (Ty)
1041 break;
1042 }
1043 } else if (HandleType->getTargetExtName() == "spirv.VulkanBuffer") {
1044 // This call is supposed to index into an array
1045 Ty = HandleType->getTypeParameter(0);
1046 if (II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1047 if (Ty->isArrayTy())
1048 Ty = Ty->getArrayElementType();
1049 else {
1050 assert(Ty && Ty->isStructTy());
1051 uint32_t Index =
1052 cast<ConstantInt>(II->getOperand(1))->getZExtValue();
1053 Ty = cast<StructType>(Ty)->getElementType(Index);
1054 }
1055 }
1057 } else {
1058 llvm_unreachable("Unknown handle type for spv_resource_getpointer.");
1059 }
1060 } else if (II && II->getIntrinsicID() ==
1061 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1062 Ty = deduceElementTypeHelper(CI->getArgOperand(0), Visited,
1063 UnknownElemTypeI8);
1064 } else if (Function *CalledF = CI->getCalledFunction()) {
1065 std::string DemangledName =
1066 getOclOrSpirvBuiltinDemangledName(CalledF->getName());
1067 if (DemangledName.length() > 0)
1068 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1069 auto AsArgIt = ResTypeByArg.find(DemangledName);
1070 if (AsArgIt != ResTypeByArg.end())
1071 Ty = deduceElementTypeHelper(CI->getArgOperand(AsArgIt->second),
1072 Visited, UnknownElemTypeI8);
1073 else if (Type *KnownRetTy = GR->findDeducedElementType(CalledF))
1074 Ty = KnownRetTy;
1075 }
1076 }
1077
1078 // remember the found relationship
1079 if (Ty && !IgnoreKnownType) {
1080 // specify nested types if needed, otherwise return unchanged
1082 }
1083
1084 return Ty;
1085}
1086
1087// Re-create a type of the value if it has untyped pointer fields, also nested.
1088// Return the original value type if no corrections of untyped pointer
1089// information is found or needed.
1090Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1091 bool UnknownElemTypeI8) {
1092 std::unordered_set<Value *> Visited;
1093 return deduceNestedTypeHelper(U, U->getType(), Visited, UnknownElemTypeI8);
1094}
1095
1096Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
1097 User *U, Type *OrigTy, std::unordered_set<Value *> &Visited,
1098 bool UnknownElemTypeI8) {
1099 if (!U)
1100 return OrigTy;
1101
1102 // maybe already known
1103 if (Type *KnownTy = GR->findDeducedCompositeType(U))
1104 return KnownTy;
1105
1106 // maybe a cycle
1107 if (!Visited.insert(U).second)
1108 return OrigTy;
1109
1110 if (isa<StructType>(OrigTy)) {
1112 bool Change = false;
1113 for (unsigned i = 0; i < U->getNumOperands(); ++i) {
1114 Value *Op = U->getOperand(i);
1115 assert(Op && "Operands should not be null.");
1116 Type *OpTy = Op->getType();
1117 Type *Ty = OpTy;
1118 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
1119 if (Type *NestedTy =
1120 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
1121 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
1122 } else {
1123 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
1124 UnknownElemTypeI8);
1125 }
1126 Tys.push_back(Ty);
1127 Change |= Ty != OpTy;
1128 }
1129 if (Change) {
1130 Type *NewTy = StructType::create(Tys);
1131 GR->addDeducedCompositeType(U, NewTy);
1132 return NewTy;
1133 }
1134 } else if (auto *ArrTy = dyn_cast<ArrayType>(OrigTy)) {
1135 if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {
1136 Type *OpTy = ArrTy->getElementType();
1137 Type *Ty = OpTy;
1138 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
1139 if (Type *NestedTy =
1140 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
1141 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
1142 } else {
1143 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
1144 UnknownElemTypeI8);
1145 }
1146 if (Ty != OpTy) {
1147 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1148 GR->addDeducedCompositeType(U, NewTy);
1149 return NewTy;
1150 }
1151 }
1152 } else if (auto *VecTy = dyn_cast<VectorType>(OrigTy)) {
1153 if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {
1154 Type *OpTy = VecTy->getElementType();
1155 Type *Ty = OpTy;
1156 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
1157 if (Type *NestedTy =
1158 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
1159 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
1160 } else {
1161 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
1162 UnknownElemTypeI8);
1163 }
1164 if (Ty != OpTy) {
1165 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1167 return NewTy;
1168 }
1169 }
1170 }
1171
1172 return OrigTy;
1173}
1174
1175Type *SPIRVEmitIntrinsics::deduceElementType(Value *I, bool UnknownElemTypeI8) {
1176 if (Type *Ty = deduceElementTypeHelper(I, UnknownElemTypeI8))
1177 return Ty;
1178 if (!UnknownElemTypeI8)
1179 return nullptr;
1180 insertTodoType(I);
1181 return IntegerType::getInt8Ty(I->getContext());
1182}
1183
1185 Value *PointerOperand) {
1186 Type *PointeeTy = GR->findDeducedElementType(PointerOperand);
1187 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
1188 return nullptr;
1189 auto *PtrTy = dyn_cast<PointerType>(I->getType());
1190 if (!PtrTy)
1191 return I->getType();
1192 if (Type *NestedTy = GR->findDeducedElementType(I))
1193 return getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
1194 return nullptr;
1195}
1196
1197// Try to deduce element type for a call base. Returns false if this is an
1198// indirect function invocation, and true otherwise.
1199bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1200 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
1201 Type *&KnownElemTy, bool &Incomplete) {
1202 Function *CalledF = CI->getCalledFunction();
1203 if (!CalledF)
1204 return false;
1205 std::string DemangledName =
1207 if (DemangledName.length() > 0 &&
1208 !StringRef(DemangledName).starts_with("llvm.")) {
1209 const SPIRVSubtarget &ST = TM.getSubtarget<SPIRVSubtarget>(*CalledF);
1210 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1211 DemangledName, ST.getPreferredInstructionSet());
1212 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1213 for (unsigned i = 0, PtrCnt = 0; i < CI->arg_size() && PtrCnt < 2; ++i) {
1214 Value *Op = CI->getArgOperand(i);
1215 if (!isPointerTy(Op->getType()))
1216 continue;
1217 ++PtrCnt;
1218 if (Type *ElemTy = GR->findDeducedElementType(Op))
1219 KnownElemTy = ElemTy; // src will rewrite dest if both are defined
1220 Ops.push_back(std::make_pair(Op, i));
1221 }
1222 } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1223 if (CI->arg_size() == 0)
1224 return true;
1225 Value *Op = CI->getArgOperand(0);
1226 if (!isPointerTy(Op->getType()))
1227 return true;
1228 switch (Opcode) {
1229 case SPIRV::OpAtomicFAddEXT:
1230 case SPIRV::OpAtomicFMinEXT:
1231 case SPIRV::OpAtomicFMaxEXT:
1232 case SPIRV::OpAtomicLoad:
1233 case SPIRV::OpAtomicCompareExchangeWeak:
1234 case SPIRV::OpAtomicCompareExchange:
1235 case SPIRV::OpAtomicExchange:
1236 case SPIRV::OpAtomicIAdd:
1237 case SPIRV::OpAtomicISub:
1238 case SPIRV::OpAtomicOr:
1239 case SPIRV::OpAtomicXor:
1240 case SPIRV::OpAtomicAnd:
1241 case SPIRV::OpAtomicUMin:
1242 case SPIRV::OpAtomicUMax:
1243 case SPIRV::OpAtomicSMin:
1244 case SPIRV::OpAtomicSMax: {
1245 KnownElemTy = isPointerTy(CI->getType()) ? getAtomicElemTy(GR, CI, Op)
1246 : CI->getType();
1247 if (!KnownElemTy)
1248 return true;
1249 Incomplete = isTodoType(Op);
1250 Ops.push_back(std::make_pair(Op, 0));
1251 } break;
1252 case SPIRV::OpAtomicStore: {
1253 if (CI->arg_size() < 4)
1254 return true;
1255 Value *ValOp = CI->getArgOperand(3);
1256 KnownElemTy = isPointerTy(ValOp->getType())
1257 ? getAtomicElemTy(GR, CI, Op)
1258 : ValOp->getType();
1259 if (!KnownElemTy)
1260 return true;
1261 Incomplete = isTodoType(Op);
1262 Ops.push_back(std::make_pair(Op, 0));
1263 } break;
1264 }
1265 }
1266 }
1267 return true;
1268}
1269
1270// Try to deduce element type for a function pointer.
1271void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1272 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
1273 Type *&KnownElemTy, bool IsPostprocessing) {
1274 Value *Op = CI->getCalledOperand();
1275 if (!Op || !isPointerTy(Op->getType()))
1276 return;
1277 Ops.push_back(std::make_pair(Op, std::numeric_limits<unsigned>::max()));
1278 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1279 bool IsNewFTy = false, IsIncomplete = false;
1281 for (auto &&[ParmIdx, Arg] : llvm::enumerate(CI->args())) {
1282 Type *ArgTy = Arg->getType();
1283 if (ArgTy->isPointerTy()) {
1284 if (Type *ElemTy = GR->findDeducedElementType(Arg)) {
1285 IsNewFTy = true;
1286 ArgTy = getTypedPointerWrapper(ElemTy, getPointerAddressSpace(ArgTy));
1287 if (isTodoType(Arg))
1288 IsIncomplete = true;
1289 } else {
1290 IsIncomplete = true;
1291 }
1292 } else {
1293 ArgTy = FTy->getFunctionParamType(ParmIdx);
1294 }
1295 ArgTys.push_back(ArgTy);
1296 }
1297 Type *RetTy = FTy->getReturnType();
1298 if (CI->getType()->isPointerTy()) {
1299 if (Type *ElemTy = GR->findDeducedElementType(CI)) {
1300 IsNewFTy = true;
1301 RetTy =
1303 if (isTodoType(CI))
1304 IsIncomplete = true;
1305 } else {
1306 IsIncomplete = true;
1307 }
1308 }
1309 if (!IsPostprocessing && IsIncomplete)
1310 insertTodoType(Op);
1311 KnownElemTy =
1312 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1313}
1314
1315bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1316 Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1317 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,
1318 Type *&KnownElemTy, Value *Op, Function *F) {
1319 KnownElemTy = GR->findDeducedElementType(F);
1320 if (KnownElemTy)
1321 return false;
1322 if (Type *OpElemTy = GR->findDeducedElementType(Op)) {
1323 OpElemTy = normalizeType(OpElemTy);
1324 GR->addDeducedElementType(F, OpElemTy);
1325 GR->addReturnType(
1326 F, TypedPointerType::get(OpElemTy,
1327 getPointerAddressSpace(F->getReturnType())));
1328 // non-recursive update of types in function uses
1329 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(I, Op)};
1330 for (User *U : F->users()) {
1331 CallInst *CI = dyn_cast<CallInst>(U);
1332 if (!CI || CI->getCalledFunction() != F)
1333 continue;
1334 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(CI)) {
1335 if (Type *PrevElemTy = GR->findDeducedElementType(CI)) {
1336 GR->updateAssignType(AssignCI, CI,
1337 getNormalizedPoisonValue(OpElemTy));
1338 propagateElemType(CI, PrevElemTy, VisitedSubst);
1339 }
1340 }
1341 }
1342 // Non-recursive update of types in the function uncomplete returns.
1343 // This may happen just once per a function, the latch is a pair of
1344 // findDeducedElementType(F) / addDeducedElementType(F, ...).
1345 // With or without the latch it is a non-recursive call due to
1346 // IncompleteRets set to nullptr in this call.
1347 if (IncompleteRets)
1348 for (Instruction *IncompleteRetI : *IncompleteRets)
1349 deduceOperandElementType(IncompleteRetI, nullptr, AskOps,
1350 IsPostprocessing);
1351 } else if (IncompleteRets) {
1352 IncompleteRets->insert(I);
1353 }
1354 TypeValidated.insert(I);
1355 return true;
1356}
1357
1358// If the Instruction has Pointer operands with unresolved types, this function
1359// tries to deduce them. If the Instruction has Pointer operands with known
1360// types which differ from expected, this function tries to insert a bitcast to
1361// resolve the issue.
1362void SPIRVEmitIntrinsics::deduceOperandElementType(
1363 Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1364 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing) {
1366 Type *KnownElemTy = nullptr;
1367 bool Incomplete = false;
1368 // look for known basic patterns of type inference
1369 if (auto *Ref = dyn_cast<PHINode>(I)) {
1370 if (!isPointerTy(I->getType()) ||
1371 !(KnownElemTy = GR->findDeducedElementType(I)))
1372 return;
1373 Incomplete = isTodoType(I);
1374 for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {
1375 Value *Op = Ref->getIncomingValue(i);
1376 if (isPointerTy(Op->getType()))
1377 Ops.push_back(std::make_pair(Op, i));
1378 }
1379 } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {
1380 KnownElemTy = GR->findDeducedElementType(I);
1381 if (!KnownElemTy)
1382 return;
1383 Incomplete = isTodoType(I);
1384 Ops.push_back(std::make_pair(Ref->getPointerOperand(), 0));
1385 } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {
1386 if (!isPointerTy(I->getType()))
1387 return;
1388 KnownElemTy = GR->findDeducedElementType(I);
1389 if (!KnownElemTy)
1390 return;
1391 Incomplete = isTodoType(I);
1392 Ops.push_back(std::make_pair(Ref->getOperand(0), 0));
1393 } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
1394 if (GR->findDeducedElementType(Ref->getPointerOperand()))
1395 return;
1396 KnownElemTy = Ref->getSourceElementType();
1397 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1399 } else if (auto *Ref = dyn_cast<StructuredGEPInst>(I)) {
1400 if (GR->findDeducedElementType(Ref->getPointerOperand()))
1401 return;
1402 KnownElemTy = Ref->getBaseType();
1403 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1405 } else if (auto *Ref = dyn_cast<LoadInst>(I)) {
1406 KnownElemTy = I->getType();
1407 if (isUntypedPointerTy(KnownElemTy))
1408 return;
1409 Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
1410 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
1411 return;
1412 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1414 } else if (auto *Ref = dyn_cast<StoreInst>(I)) {
1415 if (!(KnownElemTy =
1416 reconstructType(Ref->getValueOperand(), false, IsPostprocessing)))
1417 return;
1418 Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
1419 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
1420 return;
1421 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1423 } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {
1424 KnownElemTy = isPointerTy(I->getType())
1425 ? getAtomicElemTy(GR, I, Ref->getPointerOperand())
1426 : I->getType();
1427 if (!KnownElemTy)
1428 return;
1429 Incomplete = isTodoType(Ref->getPointerOperand());
1430 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1432 } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {
1433 KnownElemTy = isPointerTy(I->getType())
1434 ? getAtomicElemTy(GR, I, Ref->getPointerOperand())
1435 : I->getType();
1436 if (!KnownElemTy)
1437 return;
1438 Incomplete = isTodoType(Ref->getPointerOperand());
1439 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1441 } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
1442 if (!isPointerTy(I->getType()) ||
1443 !(KnownElemTy = GR->findDeducedElementType(I)))
1444 return;
1445 Incomplete = isTodoType(I);
1446 for (unsigned i = 0; i < Ref->getNumOperands(); i++) {
1447 Value *Op = Ref->getOperand(i);
1448 if (isPointerTy(Op->getType()))
1449 Ops.push_back(std::make_pair(Op, i));
1450 }
1451 } else if (auto *Ref = dyn_cast<ReturnInst>(I)) {
1452 if (!isPointerTy(CurrF->getReturnType()))
1453 return;
1454 Value *Op = Ref->getReturnValue();
1455 if (!Op)
1456 return;
1457 if (deduceOperandElementTypeFunctionRet(I, IncompleteRets, AskOps,
1458 IsPostprocessing, KnownElemTy, Op,
1459 CurrF))
1460 return;
1461 Incomplete = isTodoType(CurrF);
1462 Ops.push_back(std::make_pair(Op, 0));
1463 } else if (auto *Ref = dyn_cast<ICmpInst>(I)) {
1464 if (!isPointerTy(Ref->getOperand(0)->getType()))
1465 return;
1466 Value *Op0 = Ref->getOperand(0);
1467 Value *Op1 = Ref->getOperand(1);
1468 bool Incomplete0 = isTodoType(Op0);
1469 bool Incomplete1 = isTodoType(Op1);
1470 Type *ElemTy1 = GR->findDeducedElementType(Op1);
1471 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1472 ? nullptr
1473 : GR->findDeducedElementType(Op0);
1474 if (ElemTy0) {
1475 KnownElemTy = ElemTy0;
1476 Incomplete = Incomplete0;
1477 Ops.push_back(std::make_pair(Op1, 1));
1478 } else if (ElemTy1) {
1479 KnownElemTy = ElemTy1;
1480 Incomplete = Incomplete1;
1481 Ops.push_back(std::make_pair(Op0, 0));
1482 }
1483 } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
1484 if (!CI->isIndirectCall())
1485 deduceOperandElementTypeCalledFunction(CI, Ops, KnownElemTy, Incomplete);
1486 else if (HaveFunPtrs)
1487 deduceOperandElementTypeFunctionPointer(CI, Ops, KnownElemTy,
1488 IsPostprocessing);
1489 }
1490
1491 // There is no enough info to deduce types or all is valid.
1492 if (!KnownElemTy || Ops.size() == 0)
1493 return;
1494
1495 LLVMContext &Ctx = CurrF->getContext();
1496 IRBuilder<> B(Ctx);
1497 for (auto &OpIt : Ops) {
1498 Value *Op = OpIt.first;
1499 if (AskOps && !AskOps->contains(Op))
1500 continue;
1501 Type *AskTy = nullptr;
1502 CallInst *AskCI = nullptr;
1503 if (IsPostprocessing && AskOps) {
1504 AskTy = GR->findDeducedElementType(Op);
1505 AskCI = GR->findAssignPtrTypeInstr(Op);
1506 assert(AskTy && AskCI);
1507 }
1508 Type *Ty = AskTy ? AskTy : GR->findDeducedElementType(Op);
1509 if (Ty == KnownElemTy)
1510 continue;
1511 Value *OpTyVal = getNormalizedPoisonValue(KnownElemTy);
1512 Type *OpTy = Op->getType();
1513 if (Op->hasUseList() &&
1514 (!Ty || AskTy || isUntypedPointerTy(Ty) || isTodoType(Op))) {
1515 Type *PrevElemTy = GR->findDeducedElementType(Op);
1516 GR->addDeducedElementType(Op, normalizeType(KnownElemTy));
1517 // check if KnownElemTy is complete
1518 if (!Incomplete)
1519 eraseTodoType(Op);
1520 else if (!IsPostprocessing)
1521 insertTodoType(Op);
1522 // check if there is existing Intrinsic::spv_assign_ptr_type instruction
1523 CallInst *AssignCI = AskCI ? AskCI : GR->findAssignPtrTypeInstr(Op);
1524 if (AssignCI == nullptr) {
1525 Instruction *User = dyn_cast<Instruction>(Op->use_begin()->get());
1526 setInsertPointSkippingPhis(B, User ? User->getNextNode() : I);
1527 CallInst *CI =
1528 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,
1529 {B.getInt32(getPointerAddressSpace(OpTy))}, B);
1530 GR->addAssignPtrTypeInstr(Op, CI);
1531 } else {
1532 GR->updateAssignType(AssignCI, Op, OpTyVal);
1533 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1534 std::make_pair(I, Op)};
1535 propagateElemTypeRec(Op, KnownElemTy, PrevElemTy, VisitedSubst);
1536 }
1537 } else {
1538 eraseTodoType(Op);
1539 CallInst *PtrCastI =
1540 buildSpvPtrcast(I->getParent()->getParent(), Op, KnownElemTy);
1541 if (OpIt.second == std::numeric_limits<unsigned>::max())
1542 dyn_cast<CallInst>(I)->setCalledOperand(PtrCastI);
1543 else
1544 I->setOperand(OpIt.second, PtrCastI);
1545 }
1546 }
1547 TypeValidated.insert(I);
1548}
1549
1550void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1551 Instruction *New,
1552 IRBuilder<> &B) {
1553 while (!Old->user_empty()) {
1554 auto *U = Old->user_back();
1555 if (isAssignTypeInstr(U)) {
1556 B.SetInsertPoint(U);
1557 SmallVector<Value *, 2> Args = {New, U->getOperand(1)};
1558 CallInst *AssignCI =
1559 B.CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);
1560 GR->addAssignPtrTypeInstr(New, AssignCI);
1561 U->eraseFromParent();
1562 } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||
1563 isa<CallInst>(U)) {
1564 U->replaceUsesOfWith(Old, New);
1565 // For a `llvm.spv.abort` call whose composite message argument was
1566 // rewritten to a value-id (i32), also retarget the call to a matching
1567 // intrinsic declaration so the IR verifier is satisfied. The SPIR-V
1568 // type of the value is tracked via the GlobalRegistry, so the selector
1569 // still emits OpAbortKHR with the original composite type.
1570 if (auto *CI = dyn_cast<CallInst>(U);
1571 CI && CI->getIntrinsicID() == Intrinsic::spv_abort) {
1572 Type *NewArgTy = New->getType();
1573 Type *ExpectedArgTy = CI->getFunctionType()->getParamType(0);
1574 if (NewArgTy != ExpectedArgTy) {
1575 Module *M = CI->getModule();
1577 M, Intrinsic::spv_abort, {NewArgTy});
1578 CI->setCalledFunction(NewF);
1579 }
1580 }
1581 } else if (auto *Phi = dyn_cast<PHINode>(U)) {
1582 if (Phi->getType() != New->getType()) {
1583 Phi->mutateType(New->getType());
1584 Phi->replaceUsesOfWith(Old, New);
1585 // Convert extractvalue users of the mutated PHI to spv_extractv
1587 for (User *PhiUser : Phi->users())
1588 if (auto *EV = dyn_cast<ExtractValueInst>(PhiUser))
1589 EVUsers.push_back(EV);
1590 for (ExtractValueInst *EV : EVUsers) {
1591 B.SetInsertPoint(EV);
1592 SmallVector<Value *> Args(EV->operand_values());
1593 for (unsigned Idx : EV->indices())
1594 Args.push_back(B.getInt32(Idx));
1595 auto *NewEV =
1596 B.CreateIntrinsic(Intrinsic::spv_extractv, {EV->getType()}, Args);
1597 EV->replaceAllUsesWith(NewEV);
1598 DeletedInstrs.insert(EV);
1599 EV->eraseFromParent();
1600 }
1601 } else {
1602 Phi->replaceUsesOfWith(Old, New);
1603 }
1604 } else {
1605 llvm_unreachable("illegal aggregate intrinsic user");
1606 }
1607 }
1608 New->copyMetadata(*Old);
1609 Old->eraseFromParent();
1610}
1611
1612void SPIRVEmitIntrinsics::preprocessUndefs(IRBuilder<> &B) {
1613 const SPIRVSubtarget *STI = TM.getSubtargetImpl(*CurrF);
1614 bool HasPoisonExt =
1615 STI->canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze);
1616 SmallVector<Instruction *, 16> Insts;
1617 for (auto &I : instructions(CurrF))
1618 Insts.push_back(&I);
1619
1620 for (Instruction *I : Insts) {
1621 bool BPrepared = false;
1622 for (auto &Op : I->operands()) {
1623 auto *AggrUndef = dyn_cast<UndefValue>(Op);
1624 if (!AggrUndef || !Op->getType()->isAggregateType())
1625 continue;
1626 if (HasPoisonExt && isa<PoisonValue>(AggrUndef))
1627 continue;
1628 if (isa<PoisonValue>(AggrUndef))
1629 LLVM_DEBUG(dbgs() << "SPV_KHR_poison_freeze is not enabled. Poison is "
1630 "lowered as undef\n");
1631
1632 if (!BPrepared) {
1634 BPrepared = true;
1635 }
1636 auto *IntrUndef = B.CreateIntrinsic(Intrinsic::spv_undef, {});
1637 I->replaceUsesOfWith(Op, IntrUndef);
1638 AggrConsts[IntrUndef] = AggrUndef;
1639 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1640 }
1641 }
1642}
1643
1644void SPIRVEmitIntrinsics::preprocessPoisons(IRBuilder<> &B) {
1645 const SPIRVSubtarget *STI = TM.getSubtargetImpl(*CurrF);
1646 if (!STI->canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze))
1647 return;
1648
1649 for (Instruction &I : instructions(CurrF)) {
1650 bool BPrepared = false;
1651 auto *Phi = dyn_cast<PHINode>(&I);
1652
1653 for (unsigned Idx = 0; Idx < I.getNumOperands(); ++Idx) {
1654 Value *Op = I.getOperand(Idx);
1656 if (!Poison || Op->getType()->isMetadataTy())
1657 continue;
1658
1659 Type *OpTy = Op->getType();
1660 Value *Replacement = nullptr;
1661 if (OpTy->isAggregateType()) {
1662 if (!BPrepared) {
1664 BPrepared = true;
1665 }
1666 auto *Call =
1667 B.CreateIntrinsic(Intrinsic::spv_poison, {B.getInt32Ty()}, {});
1668 AggrConsts[Call] = Poison;
1669 AggrConstTypes[Call] = OpTy;
1670 Replacement = Call;
1671 } else {
1672 if (Phi)
1673 B.SetInsertPoint(Phi->getIncomingBlock(Idx)->getTerminator());
1674 else if (!BPrepared) {
1676 BPrepared = true;
1677 }
1678 Replacement = B.CreateIntrinsic(Intrinsic::spv_poison, {OpTy}, {});
1679 }
1680 I.setOperand(Idx, Replacement);
1681 }
1682 }
1683}
1684
1685// Simplify addrspacecast(null) instructions to ConstantPointerNull of the
1686// target type. Casting null always yields null, and this avoids SPIR-V
1687// lowering issues where the null gets typed as an integer instead of a
1688// pointer.
1689void SPIRVEmitIntrinsics::simplifyNullAddrSpaceCasts() {
1690 for (Instruction &I : make_early_inc_range(instructions(CurrF)))
1691 if (auto *ASC = dyn_cast<AddrSpaceCastInst>(&I))
1692 if (isa<ConstantPointerNull>(ASC->getPointerOperand())) {
1693 ASC->replaceAllUsesWith(
1695 ASC->eraseFromParent();
1696 }
1697}
1698
1699void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
1700 const SPIRVSubtarget *STI = TM.getSubtargetImpl(*CurrF);
1701 bool HasPoisonExt =
1702 STI->canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze);
1703 std::queue<Instruction *> Worklist;
1704 for (auto &I : instructions(CurrF))
1705 Worklist.push(&I);
1706
1707 while (!Worklist.empty()) {
1708 auto *I = Worklist.front();
1709 bool IsPhi = isa<PHINode>(I), BPrepared = false;
1710 assert(I);
1711 bool KeepInst = false;
1712 for (const auto &Op : I->operands()) {
1713 Constant *AggrConst = nullptr;
1714 Type *ResTy = nullptr;
1715 if (auto *COp = dyn_cast<ConstantVector>(Op)) {
1716 AggrConst = COp;
1717 ResTy = COp->getType();
1718 } else if (auto *COp = dyn_cast<ConstantArray>(Op)) {
1719 AggrConst = COp;
1720 ResTy = B.getInt32Ty();
1721 } else if (auto *COp = dyn_cast<ConstantStruct>(Op)) {
1722 AggrConst = COp;
1723 ResTy = B.getInt32Ty();
1724 } else if (auto *COp = dyn_cast<ConstantDataArray>(Op)) {
1725 AggrConst = COp;
1726 ResTy = B.getInt32Ty();
1727 } else if (auto *COp = dyn_cast<ConstantAggregateZero>(Op)) {
1728 AggrConst = COp;
1729 ResTy = Op->getType()->isVectorTy() ? COp->getType() : B.getInt32Ty();
1730 }
1731 if (AggrConst) {
1732 auto PrepareInsert = [&]() {
1733 if (BPrepared)
1734 return;
1735 IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
1736 : B.SetInsertPoint(I);
1737 BPrepared = true;
1738 };
1740 if (auto *COp = dyn_cast<ConstantDataSequential>(Op))
1741 for (unsigned i = 0; i < COp->getNumElements(); ++i)
1742 Args.push_back(COp->getElementAsConstant(i));
1743 else
1744 for (Value *Op : AggrConst->operands()) {
1745 // Simplify addrspacecast(null) to null in the target address space
1746 // so that null pointers get the correct pointer type when lowered.
1747 if (auto *CE = dyn_cast<ConstantExpr>(Op);
1748 CE && CE->getOpcode() == Instruction::AddrSpaceCast &&
1749 isa<ConstantPointerNull>(CE->getOperand(0)))
1751 if (HasPoisonExt && isa<PoisonValue>(Op)) {
1752 PrepareInsert();
1753 Type *PoisonTy = Op->getType();
1754 if (PoisonTy->isAggregateType()) {
1755 auto *Call = B.CreateIntrinsic(Intrinsic::spv_poison,
1756 {B.getInt32Ty()}, {});
1757 AggrConsts[Call] = cast<PoisonValue>(Op);
1758 AggrConstTypes[Call] = PoisonTy;
1759 Op = Call;
1760 } else {
1761 Op = B.CreateIntrinsic(Intrinsic::spv_poison, {PoisonTy}, {});
1762 }
1763 }
1764 Args.push_back(Op);
1765 }
1766 PrepareInsert();
1767 auto *CI =
1768 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {Args});
1769 Worklist.push(CI);
1770 I->replaceUsesOfWith(Op, CI);
1771 KeepInst = true;
1772 AggrConsts[CI] = AggrConst;
1773 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst, false);
1774 }
1775 }
1776 if (!KeepInst)
1777 Worklist.pop();
1778 }
1779}
1780
1782 IRBuilder<> &B) {
1783 LLVMContext &Ctx = I->getContext();
1785 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
1786 {I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, {Node}))});
1787}
1788
1790 unsigned RoundingModeDeco,
1791 IRBuilder<> &B) {
1792 LLVMContext &Ctx = I->getContext();
1794 MDNode *RoundingModeNode = MDNode::get(
1795 Ctx,
1797 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1798 ConstantAsMetadata::get(ConstantInt::get(Int32Ty, RoundingModeDeco))});
1799 createDecorationIntrinsic(I, RoundingModeNode, B);
1800}
1801
1803 IRBuilder<> &B) {
1804 LLVMContext &Ctx = I->getContext();
1806 MDNode *SaturatedConversionNode =
1807 MDNode::get(Ctx, {ConstantAsMetadata::get(ConstantInt::get(
1808 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1809 createDecorationIntrinsic(I, SaturatedConversionNode, B);
1810}
1811
1816
1817Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
1818 if (!Call.isInlineAsm())
1819 return &Call;
1820
1821 LLVMContext &Ctx = CurrF->getContext();
1822 // TODO: this does not retain elementtype info for memory constraints, which
1823 // in turn means that we lower them into pointers to i8, rather than
1824 // pointers to elementtype; this can be fixed during reverse translation
1825 // but we should correct it here, possibly by tweaking the function
1826 // type to take TypedPointerType args.
1827 Constant *TyC = UndefValue::get(SPIRV::getOriginalFunctionType(Call));
1828 MDString *ConstraintString =
1829 MDString::get(Ctx, SPIRV::getOriginalAsmConstraints(Call));
1831 buildMD(TyC),
1832 MetadataAsValue::get(Ctx, MDNode::get(Ctx, ConstraintString))};
1833 for (unsigned OpIdx = 0; OpIdx < Call.arg_size(); OpIdx++)
1834 Args.push_back(Call.getArgOperand(OpIdx));
1835
1837 B.SetInsertPoint(&Call);
1838 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {Args});
1839 return &Call;
1840}
1841
1842// Use a tip about rounding mode to create a decoration.
1843void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1844 IRBuilder<> &B) {
1845 std::optional<RoundingMode> RM = FPI->getRoundingMode();
1846 if (!RM.has_value())
1847 return;
1848 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1849 switch (RM.value()) {
1850 default:
1851 // ignore unknown rounding modes
1852 break;
1853 case RoundingMode::NearestTiesToEven:
1854 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1855 break;
1856 case RoundingMode::TowardNegative:
1857 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1858 break;
1859 case RoundingMode::TowardPositive:
1860 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1861 break;
1862 case RoundingMode::TowardZero:
1863 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1864 break;
1865 case RoundingMode::Dynamic:
1866 case RoundingMode::NearestTiesToAway:
1867 // TODO: check if supported
1868 break;
1869 }
1870 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1871 return;
1872 // Convert the tip about rounding mode into a decoration record.
1873 createRoundingModeDecoration(FPI, RoundingModeDeco, B);
1874}
1875
1876Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
1877 BasicBlock *ParentBB = I.getParent();
1878 Function *F = ParentBB->getParent();
1879 IRBuilder<> B(ParentBB);
1880 B.SetInsertPoint(&I);
1881 SmallVector<Value *, 4> Args;
1883 Args.push_back(I.getCondition());
1884 BBCases.push_back(I.getDefaultDest());
1885 Args.push_back(BlockAddress::get(F, I.getDefaultDest()));
1886 for (auto &Case : I.cases()) {
1887 Args.push_back(Case.getCaseValue());
1888 BBCases.push_back(Case.getCaseSuccessor());
1889 Args.push_back(BlockAddress::get(F, Case.getCaseSuccessor()));
1890 }
1891 CallInst *NewI = B.CreateIntrinsic(Intrinsic::spv_switch,
1892 {I.getOperand(0)->getType()}, {Args});
1893 // remove switch to avoid its unneeded and undesirable unwrap into branches
1894 // and conditions
1895 replaceAllUsesWith(&I, NewI);
1896 I.eraseFromParent();
1897 // insert artificial and temporary instruction to preserve valid CFG,
1898 // it will be removed after IR translation pass
1899 B.SetInsertPoint(ParentBB);
1900 IndirectBrInst *BrI = B.CreateIndirectBr(
1901 Constant::getNullValue(PointerType::getUnqual(ParentBB->getContext())),
1902 BBCases.size());
1903 for (BasicBlock *BBCase : BBCases)
1904 BrI->addDestination(BBCase);
1905 return BrI;
1906}
1907
1909 return GEP->getNumIndices() > 0 && match(GEP->getOperand(1), m_Zero());
1910}
1911
1912Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &I) {
1913 auto *SGEP = dyn_cast<StructuredGEPInst>(&I);
1914 if (!SGEP)
1915 return &I;
1916
1917 IRBuilder<> B(I.getParent());
1918 B.SetInsertPoint(&I);
1919 SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
1920 SmallVector<Value *, 4> Args;
1921 Args.push_back(/* inBounds= */ B.getInt1(true));
1922 Args.push_back(I.getOperand(0));
1923 Args.push_back(/* zero index */ B.getInt32(0));
1924 for (unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1925 Args.push_back(SGEP->getIndexOperand(J));
1926
1927 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, Types, Args);
1928 replaceAllUsesWithAndErase(B, &I, NewI);
1929 return NewI;
1930}
1931
1932Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
1933 IRBuilder<> B(I.getParent());
1934 B.SetInsertPoint(&I);
1935
1937 // Logical SPIR-V cannot use the OpPtrAccessChain instruction. If the first
1938 // index of the GEP is not 0, then we need to try to adjust it.
1939 //
1940 // If the GEP is doing byte addressing, try to rebuild the full access chain
1941 // from the type of the pointer.
1942 if (getByteAddressingMultiplier(I.getSourceElementType())) {
1943 return buildLogicalAccessChainFromGEP(I);
1944 }
1945
1946 // Look for the array-to-pointer decay. If this is the pattern
1947 // we can adjust the types, and prepend a 0 to the indices.
1948 Value *PtrOp = I.getPointerOperand();
1949 Type *SrcElemTy = I.getSourceElementType();
1950 Type *DeducedPointeeTy = deduceElementType(PtrOp, true);
1951
1952 if (auto *ArrTy = dyn_cast<ArrayType>(DeducedPointeeTy)) {
1953 if (ArrTy->getElementType() == SrcElemTy) {
1954 SmallVector<Value *> NewIndices;
1955 Type *FirstIdxType = I.getOperand(1)->getType();
1956 NewIndices.push_back(ConstantInt::get(FirstIdxType, 0));
1957 for (Value *Idx : I.indices())
1958 NewIndices.push_back(Idx);
1959
1960 SmallVector<Type *, 2> Types = {I.getType(), I.getPointerOperandType()};
1961 SmallVector<Value *, 4> Args;
1962 Args.push_back(B.getInt1(I.isInBounds()));
1963 Args.push_back(I.getPointerOperand());
1964 Args.append(NewIndices.begin(), NewIndices.end());
1965
1966 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
1967 replaceAllUsesWithAndErase(B, &I, NewI);
1968 return NewI;
1969 }
1970 }
1971 }
1972
1973 SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
1974 SmallVector<Value *, 4> Args;
1975 Args.push_back(B.getInt1(I.isInBounds()));
1976 llvm::append_range(Args, I.operands());
1977 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
1978 replaceAllUsesWithAndErase(B, &I, NewI);
1979 return NewI;
1980}
1981
1982Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
1983 IRBuilder<> B(I.getParent());
1984 B.SetInsertPoint(&I);
1985 Value *Source = I.getOperand(0);
1986
1987 // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of
1988 // varying element types. In case of IR coming from older versions of LLVM
1989 // such bitcasts do not provide sufficient information, should be just skipped
1990 // here, and handled in insertPtrCastOrAssignTypeInstr.
1991 if (isPointerTy(I.getType())) {
1992 replaceAllUsesWith(&I, Source);
1993 I.eraseFromParent();
1994 return nullptr;
1995 }
1996
1997 SmallVector<Type *, 2> Types = {I.getType(), Source->getType()};
1998 SmallVector<Value *> Args(I.op_begin(), I.op_end());
1999 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});
2000 replaceAllUsesWithAndErase(B, &I, NewI);
2001 return NewI;
2002}
2003
2004void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
2005 TargetExtType *AssignedType, Value *V, IRBuilder<> &B) {
2006 Type *VTy = V->getType();
2007
2008 // A couple of sanity checks.
2009 assert((isPointerTy(VTy)) && "Expect a pointer type!");
2010 if (Type *ElemTy = getPointeeType(VTy))
2011 if (ElemTy != AssignedType)
2012 report_fatal_error("Unexpected pointer element type!");
2013
2014 CallInst *AssignCI = GR->findAssignPtrTypeInstr(V);
2015 if (!AssignCI) {
2016 GR->buildAssignType(B, AssignedType, V);
2017 return;
2018 }
2019
2020 Type *CurrentType =
2022 cast<MetadataAsValue>(AssignCI->getOperand(1))->getMetadata())
2023 ->getType();
2024 if (CurrentType == AssignedType)
2025 return;
2026
2027 // Builtin types cannot be redeclared or casted.
2028 if (CurrentType->isTargetExtTy())
2029 report_fatal_error("Type mismatch " + CurrentType->getTargetExtName() +
2030 "/" + AssignedType->getTargetExtName() +
2031 " for value " + V->getName(),
2032 false);
2033
2034 // Our previous guess about the type seems to be wrong, let's update
2035 // inferred type according to a new, more precise type information.
2036 GR->updateAssignType(AssignCI, V, getNormalizedPoisonValue(AssignedType));
2037}
2038
2039void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
2040 Instruction *I, Value *Pointer, Type *ExpectedElementType,
2041 unsigned OperandToReplace, IRBuilder<> &B) {
2042 TypeValidated.insert(I);
2043
2044 // Do not emit spv_ptrcast if Pointer's element type is ExpectedElementType
2045 Type *PointerElemTy = deduceElementTypeHelper(Pointer, false);
2046 if (PointerElemTy == ExpectedElementType ||
2047 isEquivalentTypes(PointerElemTy, ExpectedElementType))
2048 return;
2049
2051 Value *ExpectedElementVal = getNormalizedPoisonValue(ExpectedElementType);
2052 MetadataAsValue *VMD = buildMD(ExpectedElementVal);
2053 unsigned AddressSpace = getPointerAddressSpace(Pointer->getType());
2054 bool FirstPtrCastOrAssignPtrType = true;
2055
2056 // Do not emit new spv_ptrcast if equivalent one already exists or when
2057 // spv_assign_ptr_type already targets this pointer with the same element
2058 // type.
2059 if (Pointer->hasUseList()) {
2060 for (auto User : Pointer->users()) {
2061 auto *II = dyn_cast<IntrinsicInst>(User);
2062 if (!II ||
2063 (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2064 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2065 II->getOperand(0) != Pointer)
2066 continue;
2067
2068 // There is some spv_ptrcast/spv_assign_ptr_type already targeting this
2069 // pointer.
2070 FirstPtrCastOrAssignPtrType = false;
2071 if (II->getOperand(1) != VMD ||
2072 dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=
2074 continue;
2075
2076 // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the
2077 // same element type and address space.
2078 if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2079 return;
2080
2081 // This must be a spv_ptrcast, do not emit new if this one has the same BB
2082 // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.
2083 if (II->getParent() != I->getParent())
2084 continue;
2085
2086 I->setOperand(OperandToReplace, II);
2087 return;
2088 }
2089 }
2090
2091 if (isa<Instruction>(Pointer) || isa<Argument>(Pointer)) {
2092 if (FirstPtrCastOrAssignPtrType) {
2093 // If this would be the first spv_ptrcast, do not emit spv_ptrcast and
2094 // emit spv_assign_ptr_type instead.
2095 GR->buildAssignPtr(B, ExpectedElementType, Pointer);
2096 return;
2097 } else if (isTodoType(Pointer)) {
2098 eraseTodoType(Pointer);
2099 if (!isa<CallInst>(Pointer) && !isaGEP(Pointer) &&
2100 !isa<AllocaInst>(Pointer)) {
2101 // If this wouldn't be the first spv_ptrcast but existing type info is
2102 // uncomplete, update spv_assign_ptr_type arguments.
2103 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Pointer)) {
2104 Type *PrevElemTy = GR->findDeducedElementType(Pointer);
2105 assert(PrevElemTy);
2106 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2107 std::make_pair(I, Pointer)};
2108 GR->updateAssignType(AssignCI, Pointer, ExpectedElementVal);
2109 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2110 } else {
2111 GR->buildAssignPtr(B, ExpectedElementType, Pointer);
2112 }
2113 return;
2114 }
2115 }
2116 }
2117
2118 // Emit spv_ptrcast
2119 SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};
2120 SmallVector<Value *, 2> Args = {Pointer, VMD, B.getInt32(AddressSpace)};
2121 auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
2122 I->setOperand(OperandToReplace, PtrCastI);
2123 // We need to set up a pointee type for the newly created spv_ptrcast.
2124 GR->buildAssignPtr(B, ExpectedElementType, PtrCastI);
2125}
2126
2127void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
2128 IRBuilder<> &B) {
2129 // Handle basic instructions:
2130 StoreInst *SI = dyn_cast<StoreInst>(I);
2131 if (IsKernelArgInt8(CurrF, SI)) {
2132 replacePointerOperandWithPtrCast(
2133 I, SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->getContext()),
2134 0, B);
2135 }
2136 if (SI) {
2137 Value *Op = SI->getValueOperand();
2138 Value *Pointer = SI->getPointerOperand();
2139 Type *OpTy = Op->getType();
2140 if (auto *OpI = dyn_cast<Instruction>(Op)) {
2141 OpTy = restoreMutatedType(GR, OpI, OpTy);
2142 if (auto It = AggrConstTypes.find(OpI); It != AggrConstTypes.end())
2143 OpTy = It->second;
2144 }
2145 if (OpTy == Op->getType())
2146 OpTy = deduceElementTypeByValueDeep(OpTy, Op, false);
2147 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 1, B);
2148 return;
2149 }
2150 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
2151 Value *Pointer = LI->getPointerOperand();
2152 Type *OpTy = LI->getType();
2153 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
2154 if (Type *ElemTy = GR->findDeducedElementType(LI)) {
2155 OpTy = getTypedPointerWrapper(ElemTy, PtrTy->getAddressSpace());
2156 } else {
2157 Type *NewOpTy = OpTy;
2158 OpTy = deduceElementTypeByValueDeep(OpTy, LI, false);
2159 if (OpTy == NewOpTy)
2160 insertTodoType(Pointer);
2161 }
2162 }
2163 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 0, B);
2164 return;
2165 }
2166 if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
2167 Value *Pointer = GEPI->getPointerOperand();
2168 Type *OpTy = nullptr;
2169
2170 // Logical SPIR-V is not allowed to use Op*PtrAccessChain instructions. If
2171 // the first index is 0, then we can trivially lower to OpAccessChain. If
2172 // not we need to try to rewrite the GEP. We avoid adding a pointer cast at
2173 // this time, and will rewrite the GEP when visiting it.
2174 if (TM.getSubtargetImpl()->isLogicalSPIRV() && !isFirstIndexZero(GEPI)) {
2175 return;
2176 }
2177
2178 // In all cases, fall back to the GEP type if type scavenging failed.
2179 if (!OpTy)
2180 OpTy = GEPI->getSourceElementType();
2181
2182 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 0, B);
2183 if (isNestedPointer(OpTy))
2184 insertTodoType(Pointer);
2185 return;
2186 }
2187
2188 // TODO: review and merge with existing logics:
2189 // Handle calls to builtins (non-intrinsics):
2190 CallInst *CI = dyn_cast<CallInst>(I);
2191 if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||
2193 return;
2194
2195 // collect information about formal parameter types
2196 std::string DemangledName =
2198 Function *CalledF = CI->getCalledFunction();
2199 SmallVector<Type *, 4> CalledArgTys;
2200 bool HaveTypes = false;
2201 for (unsigned OpIdx = 0; OpIdx < CalledF->arg_size(); ++OpIdx) {
2202 Argument *CalledArg = CalledF->getArg(OpIdx);
2203 Type *ArgType = CalledArg->getType();
2204 if (!isPointerTy(ArgType)) {
2205 CalledArgTys.push_back(nullptr);
2206 } else if (Type *ArgTypeElem = getPointeeType(ArgType)) {
2207 CalledArgTys.push_back(ArgTypeElem);
2208 HaveTypes = true;
2209 } else {
2210 Type *ElemTy = GR->findDeducedElementType(CalledArg);
2211 if (!ElemTy && hasPointeeTypeAttr(CalledArg))
2212 ElemTy = getPointeeTypeByAttr(CalledArg);
2213 if (!ElemTy) {
2214 ElemTy = getPointeeTypeByCallInst(DemangledName, CalledF, OpIdx);
2215 if (ElemTy) {
2216 GR->addDeducedElementType(CalledArg, normalizeType(ElemTy));
2217 } else {
2218 for (User *U : CalledArg->users()) {
2219 if (Instruction *Inst = dyn_cast<Instruction>(U)) {
2220 if ((ElemTy = deduceElementTypeHelper(Inst, false)) != nullptr)
2221 break;
2222 }
2223 }
2224 }
2225 }
2226 HaveTypes |= ElemTy != nullptr;
2227 CalledArgTys.push_back(ElemTy);
2228 }
2229 }
2230
2231 if (DemangledName.empty() && !HaveTypes)
2232 return;
2233
2234 for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) {
2235 Value *ArgOperand = CI->getArgOperand(OpIdx);
2236 if (!isPointerTy(ArgOperand->getType()))
2237 continue;
2238
2239 // Constants (nulls/undefs) are handled in insertAssignPtrTypeIntrs()
2240 if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand)) {
2241 // However, we may have assumptions about the formal argument's type and
2242 // may have a need to insert a ptr cast for the actual parameter of this
2243 // call.
2244 Argument *CalledArg = CalledF->getArg(OpIdx);
2245 if (!GR->findDeducedElementType(CalledArg))
2246 continue;
2247 }
2248
2249 Type *ExpectedType =
2250 OpIdx < CalledArgTys.size() ? CalledArgTys[OpIdx] : nullptr;
2251 if (!ExpectedType && !DemangledName.empty())
2252 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2253 DemangledName, OpIdx, I->getContext());
2254 if (!ExpectedType || ExpectedType->isVoidTy())
2255 continue;
2256
2257 if (ExpectedType->isTargetExtTy() &&
2259 insertAssignPtrTypeTargetExt(cast<TargetExtType>(ExpectedType),
2260 ArgOperand, B);
2261 else
2262 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx, B);
2263 }
2264}
2265
2266Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {
2267 // If it's a <1 x Type> vector type, don't modify it. It's not a legal vector
2268 // type in LLT and IRTranslator will replace it by the scalar.
2269 if (isVector1(I.getType()))
2270 return &I;
2271
2272 SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),
2273 I.getOperand(1)->getType(),
2274 I.getOperand(2)->getType()};
2275 IRBuilder<> B(I.getParent());
2276 B.SetInsertPoint(&I);
2277 SmallVector<Value *> Args(I.op_begin(), I.op_end());
2278 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
2279 replaceAllUsesWithAndErase(B, &I, NewI);
2280 return NewI;
2281}
2282
2284SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {
2285 // If it's a <1 x Type> vector type, don't modify it. It's not a legal vector
2286 // type in LLT and IRTranslator will replace it by the scalar.
2287 if (isVector1(I.getVectorOperandType()))
2288 return &I;
2289
2290 IRBuilder<> B(I.getParent());
2291 B.SetInsertPoint(&I);
2292 SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(),
2293 I.getIndexOperand()->getType()};
2294 SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};
2295 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});
2296 replaceAllUsesWithAndErase(B, &I, NewI);
2297 return NewI;
2298}
2299
2300Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {
2301 IRBuilder<> B(I.getParent());
2302 B.SetInsertPoint(&I);
2303 SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()};
2305 Value *AggregateOp = I.getAggregateOperand();
2306 if (isa<UndefValue>(AggregateOp))
2307 Args.push_back(UndefValue::get(B.getInt32Ty()));
2308 else
2309 Args.push_back(AggregateOp);
2310 Args.push_back(I.getInsertedValueOperand());
2311 for (auto &Op : I.indices())
2312 Args.push_back(B.getInt32(Op));
2313 Instruction *NewI =
2314 B.CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args});
2315 replaceMemInstrUses(&I, NewI, B);
2316 return NewI;
2317}
2318
2319Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
2320 if (I.getAggregateOperand()->getType()->isAggregateType())
2321 return &I;
2322 IRBuilder<> B(I.getParent());
2323 B.SetInsertPoint(&I);
2324 SmallVector<Value *> Args(I.operands());
2325 for (auto &Op : I.indices())
2326 Args.push_back(B.getInt32(Op));
2327 auto *NewI =
2328 B.CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});
2329 replaceAllUsesWithAndErase(B, &I, NewI);
2330 return NewI;
2331}
2332
2333Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) {
2334 if (!I.getType()->isAggregateType())
2335 return &I;
2336 IRBuilder<> B(I.getParent());
2337 B.SetInsertPoint(&I);
2338 TrackConstants = false;
2339 const auto *TLI = TM.getSubtargetImpl()->getTargetLowering();
2341 TLI->getLoadMemOperandFlags(I, CurrF->getDataLayout());
2342
2343 unsigned IntrinsicId;
2344 SmallVector<Value *, 4> Args = {I.getPointerOperand(), B.getInt16(Flags)};
2345 if (!I.isAtomic()) {
2346 IntrinsicId = Intrinsic::spv_load;
2347 Args.push_back(B.getInt32(I.getAlign().value()));
2348 } else {
2349 IntrinsicId = Intrinsic::spv_atomic_load;
2350 Args.push_back(B.getInt8(static_cast<uint8_t>(I.getOrdering())));
2351 }
2352 CallInst *NewI =
2353 B.CreateIntrinsic(IntrinsicId, {I.getOperand(0)->getType()}, Args);
2354
2355 replaceMemInstrUses(&I, NewI, B);
2356 return NewI;
2357}
2358
2359Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {
2360 if (!AggrStores.contains(&I))
2361 return &I;
2362 IRBuilder<> B(I.getParent());
2363 B.SetInsertPoint(&I);
2364 TrackConstants = false;
2365 const auto *TLI = TM.getSubtargetImpl()->getTargetLowering();
2367 TLI->getStoreMemOperandFlags(I, CurrF->getDataLayout());
2368 auto *PtrOp = I.getPointerOperand();
2369
2370 if (I.getValueOperand()->getType()->isAggregateType()) {
2371 // It is possible that what used to be an ExtractValueInst has been replaced
2372 // with a call to the spv_extractv intrinsic, and that said call hasn't
2373 // had its return type replaced with i32 during the dedicated pass (because
2374 // it was emitted later); we have to handle this here, because IRTranslator
2375 // cannot deal with multi-register types at the moment.
2376 CallBase *CB = dyn_cast<CallBase>(I.getValueOperand());
2377 assert(CB && CB->getIntrinsicID() == Intrinsic::spv_extractv &&
2378 "Unexpected argument of aggregate type, should be spv_extractv!");
2379 CB->mutateType(B.getInt32Ty());
2380 }
2381
2382 unsigned IntrinsicId;
2383 SmallVector<Value *, 4> Args = {I.getValueOperand(), PtrOp,
2384 B.getInt16(Flags)};
2385 if (!I.isAtomic()) {
2386 IntrinsicId = Intrinsic::spv_store;
2387 Args.push_back(B.getInt32(I.getAlign().value()));
2388 } else {
2389 IntrinsicId = Intrinsic::spv_atomic_store;
2390 Args.push_back(B.getInt8(static_cast<uint8_t>(I.getOrdering())));
2391 }
2392 auto *NewI = B.CreateIntrinsic(
2393 IntrinsicId, {I.getValueOperand()->getType(), PtrOp->getType()}, Args);
2394 NewI->copyMetadata(I);
2395 I.eraseFromParent();
2396 return NewI;
2397}
2398
2399Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {
2400 Value *ArraySize = nullptr;
2401 if (I.isArrayAllocation()) {
2402 const SPIRVSubtarget *STI = TM.getSubtargetImpl(*I.getFunction());
2403 if (!STI->canUseExtension(
2404 SPIRV::Extension::SPV_INTEL_variable_length_array))
2406 "array allocation: this instruction requires the following "
2407 "SPIR-V extension: SPV_INTEL_variable_length_array",
2408 false);
2409 ArraySize = I.getArraySize();
2410 }
2411 IRBuilder<> B(I.getParent());
2412 B.SetInsertPoint(&I);
2413 TrackConstants = false;
2414 Type *PtrTy = I.getType();
2415 auto *NewI =
2416 ArraySize
2417 ? B.CreateIntrinsic(Intrinsic::spv_alloca_array,
2418 {PtrTy, ArraySize->getType()},
2419 {ArraySize, B.getInt32(I.getAlign().value())})
2420 : B.CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy},
2421 {B.getInt32(I.getAlign().value())});
2422 replaceAllUsesWithAndErase(B, &I, NewI);
2423 return NewI;
2424}
2425
2426Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
2427 assert(I.getType()->isAggregateType() && "Aggregate result is expected");
2428 IRBuilder<> B(I.getParent());
2429 B.SetInsertPoint(&I);
2430 SmallVector<Value *> Args(I.operands());
2431 Args.push_back(B.getInt32(
2432 static_cast<uint32_t>(getMemScope(I.getContext(), I.getSyncScopeID()))));
2433 // Per SPIR-V spec atomic ops must combine the ordering bits with the
2434 // storage-class bit.
2435 const SPIRVSubtarget &ST = TM.getSubtarget<SPIRVSubtarget>(*I.getFunction());
2436 unsigned AS = I.getPointerOperand()->getType()->getPointerAddressSpace();
2437 uint32_t ScSem = static_cast<uint32_t>(
2439 Args.push_back(B.getInt32(
2440 static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering())) | ScSem));
2441 Args.push_back(B.getInt32(
2442 static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering())) | ScSem));
2443 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
2444 {I.getPointerOperand()->getType()}, {Args});
2445 replaceMemInstrUses(&I, NewI, B);
2446 return NewI;
2447}
2448
2449static bool isAbortCall(const Instruction &I, const SPIRVSubtarget &ST) {
2450 auto *CI = dyn_cast<CallInst>(&I);
2451 if (!CI)
2452 return false;
2453 switch (CI->getIntrinsicID()) {
2454 case Intrinsic::spv_abort:
2455 return true;
2456 case Intrinsic::trap:
2457 case Intrinsic::ubsantrap:
2458 // When the extension is enabled, selection lowers these to OpAbortKHR.
2459 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2460 default:
2461 return false;
2462 }
2463}
2464
2465// The OpAbortKHR instruction itself is a block terminator, so we don't need to
2466// emit an extra OpUnreachable instruction.
2468 const SPIRVSubtarget &ST) {
2469 // Find a previous non-debug instruction.
2470 const Instruction *Prev = I.getPrevNode();
2471 while (Prev && Prev->isDebugOrPseudoInst())
2472 Prev = Prev->getPrevNode();
2473
2474 if (Prev && isAbortCall(*Prev, ST))
2475 return true;
2476
2478 *I.getParent(),
2479 [&ST](const Instruction &II) { return isAbortCall(II, ST); }) &&
2480 "abort-like call must be the last non-debug instruction before its "
2481 "block's terminator");
2482 return false;
2483}
2484
2485Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) {
2486 const SPIRVSubtarget &ST = TM.getSubtarget<SPIRVSubtarget>(*I.getFunction());
2487 if (precededByAbortIntrinsic(I, ST))
2488 return &I;
2489 IRBuilder<> B(&I);
2490 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2491 return &I;
2492}
2493
2494static bool
2495shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers,
2496 const GlobalVariable &GV,
2497 const Function *F) {
2498 // Skip special artificial variables.
2499 static const StringSet<> ArtificialGlobals{"llvm.global.annotations",
2500 "llvm.compiler.used", "llvm.used"};
2501
2502 if (ArtificialGlobals.contains(GV.getName()))
2503 return false;
2504
2505 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2506 if (UserFunctions.contains(F))
2507 return true;
2508
2509 // Do not emit the intrinsics in this function, it's going to be emitted on
2510 // the functions that reference it.
2511 if (!UserFunctions.empty())
2512 return false;
2513
2514 // Emit definitions for globals that are not referenced by any function on the
2515 // first function definition.
2516 const Module &M = *F->getParent();
2517 const Function &FirstDefinition = *M.getFunctionDefs().begin();
2518 return F == &FirstDefinition;
2519}
2520
2521Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(Type *AggrTy,
2522 IRBuilder<> &B) {
2523 auto MakeLeaf = [&](Type *ElemTy) -> Instruction * {
2524 auto *Leaf = B.CreateIntrinsic(Intrinsic::spv_undef, {});
2525 AggrConsts[Leaf] = PoisonValue::get(ElemTy);
2526 AggrConstTypes[Leaf] = ElemTy;
2527 return Leaf;
2528 };
2529 SmallVector<Value *, 4> Elems;
2530 if (auto *ArrTy = dyn_cast<ArrayType>(AggrTy)) {
2531 Elems.assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2532 } else {
2533 auto *StructTy = cast<StructType>(AggrTy);
2534 DenseMap<Type *, Instruction *> LeafByType;
2535 for (unsigned I = 0; I < StructTy->getNumElements(); ++I) {
2536 Type *ElemTy = StructTy->getContainedType(I);
2537 auto &Entry = LeafByType[ElemTy];
2538 if (!Entry)
2539 Entry = MakeLeaf(ElemTy);
2540 Elems.push_back(Entry);
2541 }
2542 }
2543 auto *Composite = B.CreateIntrinsic(Intrinsic::spv_const_composite,
2544 {B.getInt32Ty()}, Elems);
2545 AggrConsts[Composite] = PoisonValue::get(AggrTy);
2546 AggrConstTypes[Composite] = AggrTy;
2547 return Composite;
2548}
2549
2550void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2551 IRBuilder<> &B) {
2552
2553 if (!shouldEmitIntrinsicsForGlobalValue(GVUsers, GV, CurrF))
2554 return;
2555
2556 Constant *Init = nullptr;
2557 if (hasInitializer(&GV)) {
2558 // Deduce element type and store results in Global Registry.
2559 // Result is ignored, because TypedPointerType is not supported
2560 // by llvm IR general logic.
2561 deduceElementTypeHelper(&GV, false);
2562 Init = GV.getInitializer();
2563 Value *InitOp = Init;
2564 if (isa<UndefValue>(Init) && Init->getType()->isAggregateType()) {
2565 const SPIRVSubtarget *STI = TM.getSubtargetImpl();
2566 bool UsePoison =
2567 isa<PoisonValue>(Init) &&
2568 STI->canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze);
2569 if (UsePoison) {
2570 auto *Call =
2571 B.CreateIntrinsic(Intrinsic::spv_poison, {B.getInt32Ty()}, {});
2572 AggrConsts[Call] = cast<PoisonValue>(Init);
2573 AggrConstTypes[Call] = Init->getType();
2574 InitOp = Call;
2575 } else {
2576 InitOp = buildSpvUndefComposite(Init->getType(), B);
2577 }
2578 }
2579 Type *Ty = isAggrConstForceInt32(Init) ? B.getInt32Ty() : Init->getType();
2580 Constant *Const = isAggrConstForceInt32(Init) ? B.getInt32(1) : Init;
2581 auto *InitInst = B.CreateIntrinsic(Intrinsic::spv_init_global,
2582 {GV.getType(), Ty}, {&GV, Const});
2583 InitInst->setArgOperand(1, InitOp);
2584 }
2585 if (!Init && GV.use_empty())
2586 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);
2587}
2588
2589// Return true, if we can't decide what is the pointee type now and will get
2590// back to the question later. Return false is spv_assign_ptr_type is not needed
2591// or can be inserted immediately.
2592bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
2593 IRBuilder<> &B,
2594 bool UnknownElemTypeI8) {
2596 if (!isPointerTy(I->getType()) || !requireAssignType(I))
2597 return false;
2598
2600 if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {
2601 GR->buildAssignPtr(B, ElemTy, I);
2602 return false;
2603 }
2604 return true;
2605}
2606
2607void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
2608 IRBuilder<> &B) {
2609 // TODO: extend the list of functions with known result types
2610 static StringMap<unsigned> ResTypeWellKnown = {
2611 {"async_work_group_copy", WellKnownTypes::Event},
2612 {"async_work_group_strided_copy", WellKnownTypes::Event},
2613 {"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2614
2616
2617 bool IsKnown = false;
2618 if (auto *CI = dyn_cast<CallInst>(I)) {
2619 if (!CI->isIndirectCall() && !CI->isInlineAsm() &&
2620 CI->getCalledFunction() && !CI->getCalledFunction()->isIntrinsic()) {
2621 Function *CalledF = CI->getCalledFunction();
2622 std::string DemangledName =
2624 FPDecorationId DecorationId = FPDecorationId::NONE;
2625 if (DemangledName.length() > 0)
2626 DemangledName =
2627 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2628 auto ResIt = ResTypeWellKnown.find(DemangledName);
2629 if (ResIt != ResTypeWellKnown.end()) {
2630 IsKnown = true;
2632 switch (ResIt->second) {
2633 case WellKnownTypes::Event:
2634 GR->buildAssignType(
2635 B, TargetExtType::get(I->getContext(), "spirv.Event"), I);
2636 break;
2637 }
2638 }
2639 // check if a floating rounding mode or saturation info is present
2640 switch (DecorationId) {
2641 default:
2642 break;
2643 case FPDecorationId::SAT:
2645 break;
2646 case FPDecorationId::RTE:
2648 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE, B);
2649 break;
2650 case FPDecorationId::RTZ:
2652 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ, B);
2653 break;
2654 case FPDecorationId::RTP:
2656 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP, B);
2657 break;
2658 case FPDecorationId::RTN:
2660 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN, B);
2661 break;
2662 }
2663 }
2664 }
2665
2666 Type *Ty = I->getType();
2667 if (!IsKnown && !Ty->isVoidTy() && !isPointerTy(Ty) && requireAssignType(I)) {
2669 Type *TypeToAssign = Ty;
2670 if (auto *II = dyn_cast<IntrinsicInst>(I)) {
2671 if (isSpvAggrPlaceholder(II)) {
2672 auto It = AggrConstTypes.find(II);
2673 if (It == AggrConstTypes.end())
2674 report_fatal_error("Unknown composite intrinsic type");
2675 TypeToAssign = It->second;
2676 } else if (II->getIntrinsicID() == Intrinsic::spv_poison) {
2677 if (auto It = AggrConstTypes.find(II); It != AggrConstTypes.end())
2678 TypeToAssign = It->second;
2679 }
2680 } else if (auto It = AggrConstTypes.find(I); It != AggrConstTypes.end())
2681 TypeToAssign = It->second;
2682 TypeToAssign = restoreMutatedType(GR, I, TypeToAssign);
2683 GR->buildAssignType(B, TypeToAssign, I);
2684 }
2685 for (const auto &Op : I->operands()) {
2687 // Check GetElementPtrConstantExpr case.
2689 (isa<GEPOperator>(Op) ||
2690 (cast<ConstantExpr>(Op)->getOpcode() == CastInst::IntToPtr)))) {
2692 Type *OpTy = Op->getType();
2693 if (isa<UndefValue>(Op) && OpTy->isAggregateType()) {
2694 CallInst *AssignCI =
2695 buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,
2696 UndefValue::get(B.getInt32Ty()), {}, B);
2697 GR->addAssignPtrTypeInstr(Op, AssignCI);
2698 } else if (!isa<Instruction>(Op)) {
2699 Type *OpTy = Op->getType();
2700 Type *OpTyElem = getPointeeType(OpTy);
2701 if (OpTyElem) {
2702 GR->buildAssignPtr(B, OpTyElem, Op);
2703 } else if (isPointerTy(OpTy)) {
2704 Type *ElemTy = GR->findDeducedElementType(Op);
2705 GR->buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true),
2706 Op);
2707 } else {
2708 Value *OpTyVal = Op;
2709 if (OpTy->isTargetExtTy()) {
2710 // We need to do this in order to be consistent with how target ext
2711 // types are handled in `processInstrAfterVisit`
2712 OpTyVal = getNormalizedPoisonValue(OpTy);
2713 }
2714 CallInst *AssignCI =
2715 buildIntrWithMD(Intrinsic::spv_assign_type, {OpTy},
2716 getNormalizedPoisonValue(OpTy), OpTyVal, {}, B);
2717 GR->addAssignPtrTypeInstr(OpTyVal, AssignCI);
2718 }
2719 }
2720 }
2721 }
2722}
2723
2724bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2725 Instruction *Inst) {
2726 const SPIRVSubtarget *STI = TM.getSubtargetImpl(*Inst->getFunction());
2727 if (!STI->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2728 return false;
2729 // Add aliasing decorations to internal load and store intrinsics.
2730 // Do not attach them to store atomic or load atomic intrinsics / instructions
2731 // since the extension is inconsistent at the moment (we cannot add the
2732 // decoration to atomic stores because they do not have an id).
2733 return match(Inst,
2735}
2736
2737void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
2738 IRBuilder<> &B) {
2739 if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
2741 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
2742 {I, MetadataAsValue::get(I->getContext(), MD)});
2743 }
2744 // Lower alias.scope/noalias metadata
2745 {
2746 auto processMemAliasingDecoration = [&](unsigned Kind) {
2747 if (MDNode *AliasListMD = I->getMetadata(Kind)) {
2748 if (shouldTryToAddMemAliasingDecoration(I)) {
2749 uint32_t Dec = Kind == LLVMContext::MD_alias_scope
2750 ? SPIRV::Decoration::AliasScopeINTEL
2751 : SPIRV::Decoration::NoAliasINTEL;
2753 I, ConstantInt::get(B.getInt32Ty(), Dec),
2754 MetadataAsValue::get(I->getContext(), AliasListMD)};
2756 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2757 {I->getType()}, {Args});
2758 }
2759 }
2760 };
2761 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2762 processMemAliasingDecoration(LLVMContext::MD_noalias);
2763 }
2764 // MD_fpmath
2765 if (MDNode *MD = I->getMetadata(LLVMContext::MD_fpmath)) {
2766 const SPIRVSubtarget *STI = TM.getSubtargetImpl(*I->getFunction());
2767 bool AllowFPMaxError =
2768 STI->canUseExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
2769 if (!AllowFPMaxError)
2770 return;
2771
2773 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2774 {I->getType()},
2775 {I, MetadataAsValue::get(I->getContext(), MD)});
2776 }
2777 if (I->getModule()->getTargetTriple().getVendor() == Triple::AMD &&
2779 // If present, we encode AMDGPU atomic metadata as UserSemantic string
2780 // decorations, which will be parsed during reverse translation.
2781 auto &Ctx = B.getContext();
2782 auto *US = ConstantAsMetadata::get(
2783 ConstantInt::get(B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
2784
2786 if (I->hasMetadata("amdgpu.no.fine.grained.memory"))
2788 Ctx, {US, MDString::get(Ctx, "amdgpu.no.fine.grained.memory")}));
2789 if (I->hasMetadata("amdgpu.no.remote.memory"))
2791 Ctx, {US, MDString::get(Ctx, "amdgpu.no.remote.memory")}));
2792 if (I->hasMetadata("amdgpu.ignore.denormal.mode"))
2794 Ctx, {US, MDString::get(Ctx, "amdgpu.ignore.denormal.mode")}));
2795 if (!MDs.empty())
2796 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
2797 {I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
2798 }
2799}
2800
2802 const Module &M,
2804 &FPFastMathDefaultInfoMap,
2805 Function *F) {
2806 auto it = FPFastMathDefaultInfoMap.find(F);
2807 if (it != FPFastMathDefaultInfoMap.end())
2808 return it->second;
2809
2810 // If the map does not contain the entry, create a new one. Initialize it to
2811 // contain all 3 elements sorted by bit width of target type: {half, float,
2812 // double}.
2813 SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec;
2814 FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()),
2815 SPIRV::FPFastMathMode::None);
2816 FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()),
2817 SPIRV::FPFastMathMode::None);
2818 FPFastMathDefaultInfoVec.emplace_back(Type::getDoubleTy(M.getContext()),
2819 SPIRV::FPFastMathMode::None);
2820 return FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec);
2821}
2822
2824 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec,
2825 const Type *Ty) {
2826 size_t BitWidth = Ty->getScalarSizeInBits();
2827 int Index =
2829 BitWidth);
2830 assert(Index >= 0 && Index < 3 &&
2831 "Expected FPFastMathDefaultInfo for half, float, or double");
2832 assert(FPFastMathDefaultInfoVec.size() == 3 &&
2833 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2834 return FPFastMathDefaultInfoVec[Index];
2835}
2836
2837void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) {
2838 const SPIRVSubtarget *ST = TM.getSubtargetImpl();
2839 if (!ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2840 return;
2841
2842 // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
2843 // We need the entry point (function) as the key, and the target
2844 // type and flags as the value.
2845 // We also need to check ContractionOff and SignedZeroInfNanPreserve
2846 // execution modes, as they are now deprecated and must be replaced
2847 // with FPFastMathDefaultInfo.
2848 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
2849 if (!Node) {
2850 if (!M.getNamedMetadata("opencl.enable.FP_CONTRACT")) {
2851 // This requires emitting ContractionOff. However, because
2852 // ContractionOff is now deprecated, we need to replace it with
2853 // FPFastMathDefaultInfo with FP Fast Math Mode bitmask set to all 0.
2854 // We need to create the constant for that.
2855
2856 // Create constant instruction with the bitmask flags.
2857 Constant *InitValue =
2858 ConstantInt::get(Type::getInt32Ty(M.getContext()), 0);
2859 // TODO: Reuse constant if there is one already with the required
2860 // value.
2861 [[maybe_unused]] GlobalVariable *GV =
2862 new GlobalVariable(M, // Module
2863 Type::getInt32Ty(M.getContext()), // Type
2864 true, // isConstant
2866 InitValue // Initializer
2867 );
2868 }
2869 return;
2870 }
2871
2872 // The table maps function pointers to their default FP fast math info. It
2873 // can be assumed that the SmallVector is sorted by the bit width of the
2874 // type. The first element is the smallest bit width, and the last element
2875 // is the largest bit width, therefore, we will have {half, float, double}
2876 // in the order of their bit widths.
2877 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
2878 FPFastMathDefaultInfoMap;
2879
2880 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
2881 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
2882 assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");
2884 cast<ConstantAsMetadata>(MDN->getOperand(0))->getValue());
2885 const auto EM =
2887 cast<ConstantAsMetadata>(MDN->getOperand(1))->getValue())
2888 ->getZExtValue();
2889 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2890 assert(MDN->getNumOperands() == 4 &&
2891 "Expected 4 operands for FPFastMathDefault");
2892 const Type *T = cast<ValueAsMetadata>(MDN->getOperand(2))->getType();
2893 unsigned Flags =
2895 cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())
2896 ->getZExtValue();
2897 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2898 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
2899 SPIRV::FPFastMathDefaultInfo &Info =
2900 getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T);
2901 Info.FastMathFlags = Flags;
2902 Info.FPFastMathDefault = true;
2903 } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
2904 assert(MDN->getNumOperands() == 2 &&
2905 "Expected no operands for ContractionOff");
2906
2907 // We need to save this info for every possible FP type, i.e. {half,
2908 // float, double, fp128}.
2909 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2910 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
2911 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2912 Info.ContractionOff = true;
2913 }
2914 } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
2915 assert(MDN->getNumOperands() == 3 &&
2916 "Expected 1 operand for SignedZeroInfNanPreserve");
2917 unsigned TargetWidth =
2919 cast<ConstantAsMetadata>(MDN->getOperand(2))->getValue())
2920 ->getZExtValue();
2921 // We need to save this info only for the FP type with TargetWidth.
2922 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2923 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
2926 assert(Index >= 0 && Index < 3 &&
2927 "Expected FPFastMathDefaultInfo for half, float, or double");
2928 assert(FPFastMathDefaultInfoVec.size() == 3 &&
2929 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2930 FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;
2931 }
2932 }
2933
2934 std::unordered_map<unsigned, GlobalVariable *> GlobalVars;
2935 for (auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
2936 if (FPFastMathDefaultInfoVec.empty())
2937 continue;
2938
2939 for (const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2940 assert(Info.Ty && "Expected target type for FPFastMathDefaultInfo");
2941 // Skip if none of the execution modes was used.
2942 unsigned Flags = Info.FastMathFlags;
2943 if (Flags == SPIRV::FPFastMathMode::None && !Info.ContractionOff &&
2944 !Info.SignedZeroInfNanPreserve && !Info.FPFastMathDefault)
2945 continue;
2946
2947 // Check if flags are compatible.
2948 if (Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
2949 report_fatal_error("Conflicting FPFastMathFlags: ContractionOff "
2950 "and AllowContract");
2951
2952 if (Info.SignedZeroInfNanPreserve &&
2953 !(Flags &
2954 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2955 SPIRV::FPFastMathMode::NSZ))) {
2956 if (Info.FPFastMathDefault)
2957 report_fatal_error("Conflicting FPFastMathFlags: "
2958 "SignedZeroInfNanPreserve but at least one of "
2959 "NotNaN/NotInf/NSZ is enabled.");
2960 }
2961
2962 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
2963 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
2964 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
2965 report_fatal_error("Conflicting FPFastMathFlags: "
2966 "AllowTransform requires AllowReassoc and "
2967 "AllowContract to be set.");
2968 }
2969
2970 auto it = GlobalVars.find(Flags);
2971 GlobalVariable *GV = nullptr;
2972 if (it != GlobalVars.end()) {
2973 // Reuse existing global variable.
2974 GV = it->second;
2975 } else {
2976 // Create constant instruction with the bitmask flags.
2977 Constant *InitValue =
2978 ConstantInt::get(Type::getInt32Ty(M.getContext()), Flags);
2979 // TODO: Reuse constant if there is one already with the required
2980 // value.
2981 GV = new GlobalVariable(M, // Module
2982 Type::getInt32Ty(M.getContext()), // Type
2983 true, // isConstant
2985 InitValue // Initializer
2986 );
2987 GlobalVars[Flags] = GV;
2988 }
2989 }
2990 }
2991}
2992
2993void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
2994 IRBuilder<> &B) {
2995 auto *II = dyn_cast<IntrinsicInst>(I);
2996 bool IsConstComposite =
2997 II && II->getIntrinsicID() == Intrinsic::spv_const_composite;
2998 if (IsConstComposite && TrackConstants) {
3000 auto t = AggrConsts.find(I);
3001 assert(t != AggrConsts.end());
3002 auto *NewOp =
3003 buildIntrWithMD(Intrinsic::spv_track_constant,
3004 {II->getType(), II->getType()}, t->second, I, {}, B);
3005 replaceAllUsesWith(I, NewOp, false);
3006 NewOp->setArgOperand(0, I);
3007 }
3008 bool IsPhi = isa<PHINode>(I), BPrepared = false;
3009 for (const auto &Op : I->operands()) {
3010 if (isa<PHINode>(I) || isa<SwitchInst>(I) ||
3012 continue;
3013 unsigned OpNo = Op.getOperandNo();
3014 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3015 (!II->isBundleOperand(OpNo) &&
3016 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3017 continue;
3018
3019 if (!BPrepared) {
3020 IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
3021 : B.SetInsertPoint(I);
3022 BPrepared = true;
3023 }
3024 Type *OpTy = Op->getType();
3025 Type *OpElemTy = GR->findDeducedElementType(Op);
3026 Value *NewOp = Op;
3027 if (OpTy->isTargetExtTy()) {
3028 // Since this value is replaced by poison, we need to do the same in
3029 // `insertAssignTypeIntrs`.
3030 Value *OpTyVal = getNormalizedPoisonValue(OpTy);
3031 NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
3032 {OpTy, OpTyVal->getType()}, Op, OpTyVal, {}, B);
3033 }
3034 if (!IsConstComposite && isPointerTy(OpTy) && OpElemTy != nullptr &&
3035 OpElemTy != IntegerType::getInt8Ty(I->getContext())) {
3036 SmallVector<Type *, 2> Types = {OpTy, OpTy};
3037 SmallVector<Value *, 2> Args = {
3038 NewOp, buildMD(getNormalizedPoisonValue(OpElemTy)),
3039 B.getInt32(getPointerAddressSpace(OpTy))};
3040 CallInst *PtrCasted =
3041 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
3042 GR->buildAssignPtr(B, OpElemTy, PtrCasted);
3043 NewOp = PtrCasted;
3044 }
3045 if (NewOp != Op)
3046 I->setOperand(OpNo, NewOp);
3047 }
3048 if (Named.insert(I).second)
3049 emitAssignName(I, B);
3050}
3051
3052Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F,
3053 unsigned OpIdx) {
3054 std::unordered_set<Function *> FVisited;
3055 return deduceFunParamElementType(F, OpIdx, FVisited);
3056}
3057
3058Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
3059 Function *F, unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
3060 // maybe a cycle
3061 if (!FVisited.insert(F).second)
3062 return nullptr;
3063
3064 std::unordered_set<Value *> Visited;
3066 // search in function's call sites
3067 for (User *U : F->users()) {
3068 CallInst *CI = dyn_cast<CallInst>(U);
3069 if (!CI || OpIdx >= CI->arg_size())
3070 continue;
3071 Value *OpArg = CI->getArgOperand(OpIdx);
3072 if (!isPointerTy(OpArg->getType()))
3073 continue;
3074 // maybe we already know operand's element type
3075 if (Type *KnownTy = GR->findDeducedElementType(OpArg))
3076 return KnownTy;
3077 // try to deduce from the operand itself
3078 Visited.clear();
3079 if (Type *Ty = deduceElementTypeHelper(OpArg, Visited, false))
3080 return Ty;
3081 // search in actual parameter's users
3082 for (User *OpU : OpArg->users()) {
3084 if (!Inst || Inst == CI)
3085 continue;
3086 Visited.clear();
3087 if (Type *Ty = deduceElementTypeHelper(Inst, Visited, false))
3088 return Ty;
3089 }
3090 // check if it's a formal parameter of the outer function
3091 if (!CI->getParent() || !CI->getParent()->getParent())
3092 continue;
3093 Function *OuterF = CI->getParent()->getParent();
3094 if (FVisited.find(OuterF) != FVisited.end())
3095 continue;
3096 for (unsigned i = 0; i < OuterF->arg_size(); ++i) {
3097 if (OuterF->getArg(i) == OpArg) {
3098 Lookup.push_back(std::make_pair(OuterF, i));
3099 break;
3100 }
3101 }
3102 }
3103
3104 // search in function parameters
3105 for (auto &Pair : Lookup) {
3106 if (Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3107 return Ty;
3108 }
3109
3110 return nullptr;
3111}
3112
3113void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
3114 IRBuilder<> &B) {
3115 B.SetInsertPointPastAllocas(F);
3116 for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
3117 Argument *Arg = F->getArg(OpIdx);
3118 if (!isUntypedPointerTy(Arg->getType()))
3119 continue;
3120 Type *ElemTy = GR->findDeducedElementType(Arg);
3121 if (ElemTy)
3122 continue;
3123 if (hasPointeeTypeAttr(Arg) &&
3124 (ElemTy = getPointeeTypeByAttr(Arg)) != nullptr) {
3125 GR->buildAssignPtr(B, ElemTy, Arg);
3126 continue;
3127 }
3128 // search in function's call sites
3129 for (User *U : F->users()) {
3130 CallInst *CI = dyn_cast<CallInst>(U);
3131 if (!CI || OpIdx >= CI->arg_size())
3132 continue;
3133 Value *OpArg = CI->getArgOperand(OpIdx);
3134 if (!isPointerTy(OpArg->getType()))
3135 continue;
3136 // maybe we already know operand's element type
3137 if ((ElemTy = GR->findDeducedElementType(OpArg)) != nullptr)
3138 break;
3139 }
3140 if (ElemTy) {
3141 GR->buildAssignPtr(B, ElemTy, Arg);
3142 continue;
3143 }
3144 if (HaveFunPtrs) {
3145 for (User *U : Arg->users()) {
3146 CallInst *CI = dyn_cast<CallInst>(U);
3147 if (CI && !isa<IntrinsicInst>(CI) && CI->isIndirectCall() &&
3148 CI->getCalledOperand() == Arg &&
3149 CI->getParent()->getParent() == CurrF) {
3151 deduceOperandElementTypeFunctionPointer(CI, Ops, ElemTy, false);
3152 if (ElemTy) {
3153 GR->buildAssignPtr(B, ElemTy, Arg);
3154 break;
3155 }
3156 }
3157 }
3158 }
3159 }
3160}
3161
3162void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
3163 B.SetInsertPointPastAllocas(F);
3164 for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
3165 Argument *Arg = F->getArg(OpIdx);
3166 if (!isUntypedPointerTy(Arg->getType()))
3167 continue;
3168 Type *ElemTy = GR->findDeducedElementType(Arg);
3169 if (!ElemTy && (ElemTy = deduceFunParamElementType(F, OpIdx)) != nullptr) {
3170 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Arg)) {
3171 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3172 GR->updateAssignType(AssignCI, Arg, getNormalizedPoisonValue(ElemTy));
3173 propagateElemType(Arg, IntegerType::getInt8Ty(F->getContext()),
3174 VisitedSubst);
3175 } else {
3176 GR->buildAssignPtr(B, ElemTy, Arg);
3177 }
3178 }
3179 }
3180}
3181
3183 SPIRVGlobalRegistry *GR) {
3184 FunctionType *FTy = F->getFunctionType();
3185 bool IsNewFTy = false;
3187 for (Argument &Arg : F->args()) {
3188 Type *ArgTy = Arg.getType();
3189 if (ArgTy->isPointerTy())
3190 if (Type *ElemTy = GR->findDeducedElementType(&Arg)) {
3191 IsNewFTy = true;
3192 ArgTy = getTypedPointerWrapper(ElemTy, getPointerAddressSpace(ArgTy));
3193 }
3194 ArgTys.push_back(ArgTy);
3195 }
3196 return IsNewFTy
3197 ? FunctionType::get(FTy->getReturnType(), ArgTys, FTy->isVarArg())
3198 : FTy;
3199}
3200
3201bool SPIRVEmitIntrinsics::processFunctionPointers(Module &M) {
3202 SmallVector<Function *> Worklist;
3203 for (auto &F : M) {
3204 if (F.isIntrinsic())
3205 continue;
3206 if (F.isDeclaration()) {
3207 for (User *U : F.users()) {
3208 CallInst *CI = dyn_cast<CallInst>(U);
3209 if (!CI || CI->getCalledFunction() != &F) {
3210 Worklist.push_back(&F);
3211 break;
3212 }
3213 }
3214 } else {
3215 if (F.user_empty())
3216 continue;
3217 Type *FPElemTy = GR->findDeducedElementType(&F);
3218 if (!FPElemTy)
3219 FPElemTy = getFunctionPointerElemType(&F, GR);
3220 for (User *U : F.users()) {
3221 IntrinsicInst *II = dyn_cast<IntrinsicInst>(U);
3222 if (!II || II->arg_size() != 3 || II->getOperand(0) != &F)
3223 continue;
3224 if (II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3225 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3227 break;
3228 }
3229 }
3230 }
3231 }
3232 if (Worklist.empty())
3233 return false;
3234
3235 LLVMContext &Ctx = M.getContext();
3237 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", SF);
3238 IRBuilder<> IRB(BB);
3239
3240 for (Function *F : Worklist) {
3242 for (const auto &Arg : F->args())
3243 Args.push_back(getNormalizedPoisonValue(Arg.getType()));
3244 IRB.CreateCall(F, Args);
3245 }
3246 IRB.CreateRetVoid();
3247
3248 return true;
3249}
3250
3251// Apply types parsed from demangled function declarations.
3252void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) {
3253 DenseMap<Function *, CallInst *> Ptrcasts;
3254 for (auto It : FDeclPtrTys) {
3255 Function *F = It.first;
3256 for (auto *U : F->users()) {
3257 CallInst *CI = dyn_cast<CallInst>(U);
3258 if (!CI || CI->getCalledFunction() != F)
3259 continue;
3260 unsigned Sz = CI->arg_size();
3261 for (auto [Idx, ElemTy] : It.second) {
3262 if (Idx >= Sz)
3263 continue;
3264 Value *Param = CI->getArgOperand(Idx);
3265 if (GR->findDeducedElementType(Param) || isa<GlobalValue>(Param))
3266 continue;
3267 if (Argument *Arg = dyn_cast<Argument>(Param)) {
3268 if (!hasPointeeTypeAttr(Arg)) {
3269 B.SetInsertPointPastAllocas(Arg->getParent());
3270 B.SetCurrentDebugLocation(DebugLoc());
3271 GR->buildAssignPtr(B, ElemTy, Arg);
3272 }
3273 } else if (isaGEP(Param)) {
3274 replaceUsesOfWithSpvPtrcast(Param, normalizeType(ElemTy), CI,
3275 Ptrcasts);
3276 } else if (isa<Instruction>(Param)) {
3277 GR->addDeducedElementType(Param, normalizeType(ElemTy));
3278 // insertAssignTypeIntrs() will complete buildAssignPtr()
3279 } else {
3280 B.SetInsertPoint(CI->getParent()
3281 ->getParent()
3282 ->getEntryBlock()
3283 .getFirstNonPHIOrDbgOrAlloca());
3284 GR->buildAssignPtr(B, ElemTy, Param);
3285 }
3286 CallInst *Ref = dyn_cast<CallInst>(Param);
3287 if (!Ref)
3288 continue;
3289 Function *RefF = Ref->getCalledFunction();
3290 if (!RefF || !isPointerTy(RefF->getReturnType()) ||
3291 GR->findDeducedElementType(RefF))
3292 continue;
3293 ElemTy = normalizeType(ElemTy);
3294 GR->addDeducedElementType(RefF, ElemTy);
3295 GR->addReturnType(
3297 ElemTy, getPointerAddressSpace(RefF->getReturnType())));
3298 }
3299 }
3300 }
3301}
3302
3303GetElementPtrInst *
3304SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP) {
3305 // getelementptr [0 x T], P, 0 (zero), I -> getelementptr T, P, I.
3306 // If type is 0-length array and first index is 0 (zero), drop both the
3307 // 0-length array type and the first index. This is a common pattern in
3308 // the IR, e.g. when using a zero-length array as a placeholder for a
3309 // flexible array such as unbound arrays.
3310 assert(GEP && "GEP is null");
3311 Type *SrcTy = GEP->getSourceElementType();
3312 SmallVector<Value *, 8> Indices(GEP->indices());
3313 ArrayType *ArrTy = dyn_cast<ArrayType>(SrcTy);
3314 if (ArrTy && ArrTy->getNumElements() == 0 && match(Indices[0], m_Zero())) {
3315 Indices.erase(Indices.begin());
3316 SrcTy = ArrTy->getElementType();
3317 return GetElementPtrInst::Create(SrcTy, GEP->getPointerOperand(), Indices,
3318 GEP->getNoWrapFlags(), "",
3319 GEP->getIterator());
3320 }
3321 return nullptr;
3322}
3323
3324void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &F,
3325 IRBuilder<> &B) {
3326 const SPIRVSubtarget *ST = TM.getSubtargetImpl(F);
3327 // Shaders use SPIRVStructurizer which emits OpLoopMerge via spv_loop_merge.
3328 if (ST->isShader())
3329 return;
3330
3331 if (ST->canUseExtension(
3332 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3333 for (BasicBlock &BB : F) {
3335 MDNode *LoopMD = Term->getMetadata(LLVMContext::MD_loop);
3336 if (!LoopMD)
3337 continue;
3338
3339 SmallVector<unsigned, 1> Ops =
3341 unsigned LC = Ops[0];
3342 if (LC == SPIRV::LoopControl::None)
3343 continue;
3344
3345 // Emit intrinsic: loop control mask + optional parameters.
3346 B.SetInsertPoint(Term);
3347 SmallVector<Value *, 4> IntrArgs;
3348 for (unsigned Op : Ops)
3349 IntrArgs.push_back(B.getInt32(Op));
3350 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3351 }
3352 return;
3353 }
3354
3355 // For non-shader targets without the Intel extension, emit OpLoopMerge
3356 // using spv_loop_merge intrinsics, mirroring the structurizer approach.
3357 DominatorTree DT(F);
3358 LoopInfo LI(DT);
3359 if (LI.empty())
3360 return;
3361
3362 for (Loop *L : LI.getLoopsInPreorder()) {
3363 BasicBlock *Latch = L->getLoopLatch();
3364 if (!Latch)
3365 continue;
3366 BasicBlock *MergeBlock = L->getUniqueExitBlock();
3367 if (!MergeBlock)
3368 continue;
3369
3370 // Check for loop unroll metadata on the latch terminator.
3371 SmallVector<unsigned, 1> LoopControlOps =
3373 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3374 continue;
3375
3376 BasicBlock *Header = L->getHeader();
3377 B.SetInsertPoint(Header->getTerminator());
3378 auto *MergeAddress = BlockAddress::get(&F, MergeBlock);
3379 auto *ContinueAddress = BlockAddress::get(&F, Latch);
3380 SmallVector<Value *, 4> Args = {MergeAddress, ContinueAddress};
3381 for (unsigned Imm : LoopControlOps)
3382 Args.emplace_back(B.getInt32(Imm));
3383 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {Args});
3384 }
3385}
3386
3387bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3388 if (Func.isDeclaration())
3389 return false;
3390
3391 const SPIRVSubtarget &ST = TM.getSubtarget<SPIRVSubtarget>(Func);
3392 GR = ST.getSPIRVGlobalRegistry();
3393
3394 if (!CurrF)
3395 HaveFunPtrs =
3396 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3397
3398 CurrF = &Func;
3399 IRBuilder<> B(Func.getContext());
3400 AggrConsts.clear();
3401 AggrConstTypes.clear();
3402 AggrStores.clear();
3403 DeletedInstrs.clear();
3404
3405 processParamTypesByFunHeader(CurrF, B);
3406
3407 // Fix GEP result types ahead of inference, and simplify if possible.
3408 // Data structure for dead instructions that were simplified and replaced.
3409 SmallPtrSet<Instruction *, 4> DeadInsts;
3410 for (auto &I : instructions(Func)) {
3412 auto *SGEP = dyn_cast<StructuredGEPInst>(&I);
3413
3414 if ((!GEP && !SGEP) || GR->findDeducedElementType(&I))
3415 continue;
3416
3417 if (SGEP) {
3418 GR->addDeducedElementType(SGEP,
3419 normalizeType(SGEP->getResultElementType()));
3420 continue;
3421 }
3422
3423 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(GEP);
3424 if (NewGEP) {
3425 GEP->replaceAllUsesWith(NewGEP);
3426 DeadInsts.insert(GEP);
3427 GEP = NewGEP;
3428 }
3429 if (Type *GepTy = getGEPType(GEP))
3430 GR->addDeducedElementType(GEP, normalizeType(GepTy));
3431 }
3432 // Remove dead instructions that were simplified and replaced.
3433 for (auto *I : DeadInsts) {
3434 assert(I->use_empty() && "Dead instruction should not have any uses left");
3435 I->eraseFromParent();
3436 }
3437
3438 // StoreInst's operand type can be changed during the next
3439 // transformations, so we need to store it in the set. Also store already
3440 // transformed types.
3441 for (auto &I : instructions(Func)) {
3442 StoreInst *SI = dyn_cast<StoreInst>(&I);
3443 if (!SI)
3444 continue;
3445 Type *ElTy = SI->getValueOperand()->getType();
3446 if (ElTy->isAggregateType() || ElTy->isVectorTy())
3447 AggrStores.insert(&I);
3448 }
3449
3450 B.SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin());
3451 for (auto &GV : Func.getParent()->globals())
3452 processGlobalValue(GV, B);
3453
3454 preprocessUndefs(B);
3455 preprocessPoisons(B);
3456 simplifyNullAddrSpaceCasts();
3457 preprocessCompositeConstants(B);
3458
3459 for (BasicBlock &BB : Func)
3460 for (PHINode &Phi : BB.phis())
3461 if (Phi.getType()->isAggregateType()) {
3462 AggrConstTypes[&Phi] = Phi.getType();
3463 Phi.mutateType(B.getInt32Ty());
3464 }
3465
3466 preprocessBoolVectorBitcasts(Func);
3469
3470 applyDemangledPtrArgTypes(B);
3471
3472 // Pass forward: use operand to deduce instructions result.
3473 for (auto &I : Worklist) {
3474 // Don't emit intrinsincs for convergence intrinsics.
3475 if (isConvergenceIntrinsic(I))
3476 continue;
3477
3478 bool Postpone = insertAssignPtrTypeIntrs(I, B, false);
3479 // if Postpone is true, we can't decide on pointee type yet
3480 insertAssignTypeIntrs(I, B);
3481 insertPtrCastOrAssignTypeInstr(I, B);
3483 // if instruction requires a pointee type set, let's check if we know it
3484 // already, and force it to be i8 if not
3485 if (Postpone && !GR->findAssignPtrTypeInstr(I))
3486 insertAssignPtrTypeIntrs(I, B, true);
3487
3488 if (auto *FPI = dyn_cast<ConstrainedFPIntrinsic>(I))
3489 useRoundingMode(FPI, B);
3490 }
3491
3492 // Pass backward: use instructions results to specify/update/cast operands
3493 // where needed.
3494 SmallPtrSet<Instruction *, 4> IncompleteRets;
3495 for (auto &I : llvm::reverse(instructions(Func)))
3496 deduceOperandElementType(&I, &IncompleteRets);
3497
3498 // Pass forward for PHIs only, their operands are not preceed the
3499 // instruction in meaning of `instructions(Func)`.
3500 for (BasicBlock &BB : Func)
3501 for (PHINode &Phi : BB.phis())
3502 if (isPointerTy(Phi.getType()))
3503 deduceOperandElementType(&Phi, nullptr);
3504
3505 for (auto *I : Worklist) {
3506 if (DeletedInstrs.count(I))
3507 continue;
3508 TrackConstants = true;
3509 if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
3511 // Visitors return either the original/newly created instruction for
3512 // further processing, nullptr otherwise.
3513 I = visit(*I);
3514 if (!I)
3515 continue;
3516
3517 // Don't emit intrinsics for convergence operations.
3518 if (isConvergenceIntrinsic(I))
3519 continue;
3520
3522 processInstrAfterVisit(I, B);
3523 }
3524
3525 emitUnstructuredLoopControls(Func, B);
3526
3527 return true;
3528}
3529
3530// Try to deduce a better type for pointers to untyped ptr.
3531bool SPIRVEmitIntrinsics::postprocessTypes(Module &M) {
3532 if (!GR || TodoTypeSz == 0)
3533 return false;
3534
3535 unsigned SzTodo = TodoTypeSz;
3536 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3537 for (auto [Op, Enabled] : TodoType) {
3538 // TODO: add isa<CallInst>(Op) to continue
3539 if (!Enabled || isaGEP(Op))
3540 continue;
3541 CallInst *AssignCI = GR->findAssignPtrTypeInstr(Op);
3542 Type *KnownTy = GR->findDeducedElementType(Op);
3543 if (!KnownTy || !AssignCI)
3544 continue;
3545 assert(Op == AssignCI->getArgOperand(0));
3546 // Try to improve the type deduced after all Functions are processed.
3547 if (auto *CI = dyn_cast<Instruction>(Op)) {
3548 CurrF = CI->getParent()->getParent();
3549 std::unordered_set<Value *> Visited;
3550 if (Type *ElemTy = deduceElementTypeHelper(Op, Visited, false, true)) {
3551 if (ElemTy != KnownTy) {
3552 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3553 propagateElemType(CI, ElemTy, VisitedSubst);
3554 eraseTodoType(Op);
3555 continue;
3556 }
3557 }
3558 }
3559
3560 if (Op->hasUseList()) {
3561 for (User *U : Op->users()) {
3563 if (Inst && !isa<IntrinsicInst>(Inst))
3564 ToProcess[Inst].insert(Op);
3565 }
3566 }
3567 }
3568 if (TodoTypeSz == 0)
3569 return true;
3570
3571 for (auto &F : M) {
3572 CurrF = &F;
3573 SmallPtrSet<Instruction *, 4> IncompleteRets;
3574 for (auto &I : llvm::reverse(instructions(F))) {
3575 auto It = ToProcess.find(&I);
3576 if (It == ToProcess.end())
3577 continue;
3578 It->second.remove_if([this](Value *V) { return !isTodoType(V); });
3579 if (It->second.size() == 0)
3580 continue;
3581 deduceOperandElementType(&I, &IncompleteRets, &It->second, true);
3582 if (TodoTypeSz == 0)
3583 return true;
3584 }
3585 }
3586
3587 return SzTodo > TodoTypeSz;
3588}
3589
3590// Parse and store argument types of function declarations where needed.
3591void SPIRVEmitIntrinsics::parseFunDeclarations(Module &M) {
3592 for (auto &F : M) {
3593 if (!F.isDeclaration() || F.isIntrinsic())
3594 continue;
3595 // get the demangled name
3596 std::string DemangledName = getOclOrSpirvBuiltinDemangledName(F.getName());
3597 if (DemangledName.empty())
3598 continue;
3599 // allow only OpGroupAsyncCopy use case at the moment
3600 const SPIRVSubtarget &ST = TM.getSubtarget<SPIRVSubtarget>(F);
3601 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3602 DemangledName, ST.getPreferredInstructionSet());
3603 if (Opcode != SPIRV::OpGroupAsyncCopy)
3604 continue;
3605 // find pointer arguments
3606 SmallVector<unsigned> Idxs;
3607 for (unsigned OpIdx = 0; OpIdx < F.arg_size(); ++OpIdx) {
3608 Argument *Arg = F.getArg(OpIdx);
3609 if (isPointerTy(Arg->getType()) && !hasPointeeTypeAttr(Arg))
3610 Idxs.push_back(OpIdx);
3611 }
3612 if (!Idxs.size())
3613 continue;
3614 // parse function arguments
3615 LLVMContext &Ctx = F.getContext();
3617 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3618 if (!TypeStrs.size())
3619 continue;
3620 // find type info for pointer arguments
3621 for (unsigned Idx : Idxs) {
3622 if (Idx >= TypeStrs.size())
3623 continue;
3624 if (Type *ElemTy =
3625 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3627 !ElemTy->isTargetExtTy())
3628 FDeclPtrTys[&F].push_back(std::make_pair(Idx, ElemTy));
3629 }
3630 }
3631}
3632
3633bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &I) {
3634 const SPIRVSubtarget &ST = TM.getSubtarget<SPIRVSubtarget>(*I.getFunction());
3635
3636 if (I.getIntrinsicID() == Intrinsic::masked_gather) {
3637 if (!ST.canUseExtension(
3638 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3639 I.getContext().emitError(
3640 &I, "llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3641 "extension");
3642 // Replace with poison to allow compilation to continue and report error.
3643 I.replaceAllUsesWith(PoisonValue::get(I.getType()));
3644 I.eraseFromParent();
3645 return true;
3646 }
3647
3648 IRBuilder<> B(&I);
3649
3650 Value *Ptrs = I.getArgOperand(0);
3651 Value *Mask = I.getArgOperand(1);
3652 Value *Passthru = I.getArgOperand(2);
3653
3654 // Alignment is stored as a parameter attribute, not as a regular parameter.
3655 uint32_t Alignment = I.getParamAlign(0).valueOrOne().value();
3656
3657 SmallVector<Value *, 4> Args = {Ptrs, B.getInt32(Alignment), Mask,
3658 Passthru};
3659 SmallVector<Type *, 4> Types = {I.getType(), Ptrs->getType(),
3660 Mask->getType(), Passthru->getType()};
3661
3662 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3663 I.replaceAllUsesWith(NewI);
3664 I.eraseFromParent();
3665 return true;
3666 }
3667
3668 if (I.getIntrinsicID() == Intrinsic::masked_scatter) {
3669 if (!ST.canUseExtension(
3670 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3671 I.getContext().emitError(
3672 &I, "llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3673 "extension");
3674 // Erase the intrinsic to allow compilation to continue and report error.
3675 I.eraseFromParent();
3676 return true;
3677 }
3678
3679 IRBuilder<> B(&I);
3680
3681 Value *Values = I.getArgOperand(0);
3682 Value *Ptrs = I.getArgOperand(1);
3683 Value *Mask = I.getArgOperand(2);
3684
3685 // Alignment is stored as a parameter attribute on the ptrs parameter (arg
3686 // 1).
3687 uint32_t Alignment = I.getParamAlign(1).valueOrOne().value();
3688
3689 SmallVector<Value *, 4> Args = {Values, Ptrs, B.getInt32(Alignment), Mask};
3690 SmallVector<Type *, 3> Types = {Values->getType(), Ptrs->getType(),
3691 Mask->getType()};
3692
3693 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3694 I.eraseFromParent();
3695 return true;
3696 }
3697
3698 return false;
3699}
3700
3701// SPIR-V doesn't support bitcasts involving vector boolean type. Decompose such
3702// bitcasts into element-wise operations before building instructions
3703// worklist, so new instructions are properly visited and converted to
3704// SPIR-V intrinsics.
3705void SPIRVEmitIntrinsics::preprocessBoolVectorBitcasts(Function &F) {
3706 struct BoolVecBitcast {
3707 BitCastInst *BC;
3708 FixedVectorType *BoolVecTy;
3709 bool SrcIsBoolVec;
3710 };
3711
3712 auto getAsBoolVec = [](Type *Ty) -> FixedVectorType * {
3713 auto *VTy = dyn_cast<FixedVectorType>(Ty);
3714 return (VTy && VTy->getElementType()->isIntegerTy(1)) ? VTy : nullptr;
3715 };
3716
3718 for (auto &I : instructions(F)) {
3719 auto *BC = dyn_cast<BitCastInst>(&I);
3720 if (!BC)
3721 continue;
3722 if (auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3723 ToReplace.push_back({BC, BVTy, true});
3724 else if (auto *BVTy = getAsBoolVec(BC->getDestTy()))
3725 ToReplace.push_back({BC, BVTy, false});
3726 }
3727
3728 for (auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3729 IRBuilder<> B(BC);
3730 Value *Src = BC->getOperand(0);
3731 unsigned BoolVecN = BoolVecTy->getNumElements();
3732 // Use iN as the scalar intermediate type for the bool vector side.
3733 Type *IntTy = B.getIntNTy(BoolVecN);
3734
3735 // Convert source to scalar integer.
3736 Value *IntVal;
3737 if (SrcIsBoolVec) {
3738 // Extract each bool, zext, shift, and OR.
3739 IntVal = ConstantInt::get(IntTy, 0);
3740 for (unsigned I = 0; I < BoolVecN; ++I) {
3741 Value *Elem = B.CreateExtractElement(Src, B.getInt32(I));
3742 Value *Ext = B.CreateZExt(Elem, IntTy);
3743 if (I > 0)
3744 Ext = B.CreateShl(Ext, ConstantInt::get(IntTy, I));
3745 IntVal = B.CreateOr(IntVal, Ext);
3746 }
3747 } else {
3748 // Source is a non-bool type. If it's already a scalar integer, use it
3749 // directly, otherwise bitcast to iN first.
3750 IntVal = Src;
3751 if (!Src->getType()->isIntegerTy())
3752 IntVal = B.CreateBitCast(Src, IntTy);
3753 }
3754
3755 // Convert scalar integer to destination type.
3756 Value *Result;
3757 if (!SrcIsBoolVec) {
3758 // Test each bit with AND + icmp.
3759 Result = PoisonValue::get(BoolVecTy);
3760 for (unsigned I = 0; I < BoolVecN; ++I) {
3761 Value *Mask = ConstantInt::get(IntTy, APInt::getOneBitSet(BoolVecN, I));
3762 Value *And = B.CreateAnd(IntVal, Mask);
3763 Value *Cmp = B.CreateICmpNE(And, ConstantInt::get(IntTy, 0));
3764 Result = B.CreateInsertElement(Result, Cmp, B.getInt32(I));
3765 }
3766 } else {
3767 // Destination is a non-bool type. If it's a scalar integer, use IntVal
3768 // directly, otherwise bitcast from iN.
3769 Result = IntVal;
3770 if (!BC->getDestTy()->isIntegerTy())
3771 Result = B.CreateBitCast(IntVal, BC->getDestTy());
3772 }
3773
3774 BC->replaceAllUsesWith(Result);
3775 BC->eraseFromParent();
3776 }
3777}
3778
3779bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(Module &M) {
3780 bool Changed = false;
3781
3782 for (Function &F : make_early_inc_range(M)) {
3783 if (!F.isIntrinsic())
3784 continue;
3785 Intrinsic::ID IID = F.getIntrinsicID();
3786 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
3787 continue;
3788
3789 for (User *U : make_early_inc_range(F.users())) {
3790 if (auto *II = dyn_cast<IntrinsicInst>(U))
3791 Changed |= processMaskedMemIntrinsic(*II);
3792 }
3793
3794 if (F.use_empty())
3795 F.eraseFromParent();
3796 }
3797
3798 return Changed;
3799}
3800
3801bool SPIRVEmitIntrinsics::runOnModule(Module &M) {
3802 bool Changed = false;
3803
3804 Changed |= convertMaskedMemIntrinsics(M);
3805
3806 parseFunDeclarations(M);
3807 insertConstantsForFPFastMathDefault(M);
3808 GVUsers.init(M);
3809
3810 TodoType.clear();
3811 for (auto &F : M)
3813
3814 // Specify function parameters after all functions were processed.
3815 for (auto &F : M) {
3816 // check if function parameter types are set
3817 CurrF = &F;
3818 if (!F.isDeclaration() && !F.isIntrinsic()) {
3819 IRBuilder<> B(F.getContext());
3820 processParamTypes(&F, B);
3821 }
3822 }
3823
3824 CanTodoType = false;
3825 Changed |= postprocessTypes(M);
3826
3827 if (HaveFunPtrs)
3828 Changed |= processFunctionPointers(M);
3829
3830 return Changed;
3831}
3832
3833PreservedAnalyses
3835 SPIRVEmitIntrinsics Legacy(TM);
3836 if (Legacy.runOnModule(M))
3837 return PreservedAnalyses::none();
3838 return PreservedAnalyses::all();
3839}
3840
3842 return new SPIRVEmitIntrinsics(TM);
3843}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
always inline
Expand Atomic instructions
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void replaceAllUsesWith(Value *Old, Value *New, SmallPtrSet< BasicBlock *, 32 > &FreshBBs, bool IsHuge)
Replace all old uses with new ones, and push the updated BBs into FreshBBs.
static Type * getPointeeType(Value *Ptr, const DataLayout &DL)
This file defines the DenseSet and SmallDenseSet classes.
static bool runOnFunction(Function &F, bool PostInlining)
Hexagon Common GEP
iv Induction Variable Users
Definition IVUsers.cpp:48
static Value * getOpcode(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
#define T
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static unsigned getNumElements(Type *Ty)
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrConstForceInt32(const Value *V)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, DenseMap< Function *, SPIRV::FPFastMathDefaultInfoVector > &FPFastMathDefaultInfoMap, Function *F)
static Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static void emitAssignName(Instruction *I, IRBuilder<> &B)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void createRoundingModeDecoration(Instruction *I, unsigned RoundingModeDeco, IRBuilder<> &B)
static void createDecorationIntrinsic(Instruction *I, MDNode *Node, IRBuilder<> &B)
static SPIRV::FPFastMathDefaultInfo & getFPFastMathDefaultInfo(SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty)
static bool isAbortCall(const Instruction &I, const SPIRVSubtarget &ST)
static cl::opt< bool > SpirvEmitOpNames("spirv-emit-op-names", cl::desc("Emit OpName for all instructions"), cl::init(false))
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool isSpvAggrPlaceholder(const Value *V)
static bool precededByAbortIntrinsic(const UnreachableInst &I, const SPIRVSubtarget &ST)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
StringSet - A set-like wrapper for the StringMap.
DEMANGLE_NAMESPACE_BEGIN bool starts_with(std::string_view self, char C) noexcept
#define LLVM_DEBUG(...)
Definition Debug.h:119
static SymbolRef::Type getType(const Symbol *Sym)
Definition TapiFile.cpp:39
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:240
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
const Function * getParent() const
Definition Argument.h:44
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
Definition BasicBlock.h:530
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
static LLVM_ABI BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned arg_size() const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static ConstantAsMetadata * get(Constant *C)
Definition Metadata.h:537
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI std::optional< RoundingMode > getRoundingMode() const
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:178
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:254
iterator end()
Definition DenseMap.h:85
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:239
Type * getParamType(unsigned i) const
Parameter type accessors.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
Definition Function.cpp:362
iterator begin()
Definition Function.h:853
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
Definition Function.h:251
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:358
size_t arg_size() const
Definition Function.h:901
Type * getReturnType() const
Returns the type of the ret val.
Definition Function.h:216
Argument * getArg(unsigned i) const
Definition Function.h:886
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static LLVM_ABI Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static unsigned getPointerOperandIndex()
PointerType * getType() const
Global values are always pointers.
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2858
LLVM_ABI void addDestination(BasicBlock *Dest)
Add a destination.
Base class for instruction visitors.
Definition InstVisitor.h:78
LLVM_ABI bool isDebugOrPseudoInst() const LLVM_READONLY
Return true if the instruction is a DbgInfoIntrinsic or PseudoProbeInst.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
static unsigned getPointerOperandIndex()
Metadata node.
Definition Metadata.h:1080
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1444
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1572
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1450
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Definition Metadata.cpp:614
Flags
Flags values. These may be or'd together.
static LLVM_ABI MetadataAsValue * get(LLVMContext &Context, Metadata *MD)
Definition Metadata.cpp:110
Metadata * getMetadata() const
Definition Metadata.h:202
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg)
Type * findDeducedCompositeType(const Value *Val)
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld=true)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator end()
Definition StringMap.h:224
iterator find(StringRef Key)
Definition StringMap.h:237
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
StringSet - A wrapper for StringMap that provides set-like functionality.
Definition StringSet.h:25
bool contains(StringRef key) const
Check if the set contains the given key.
Definition StringSet.h:60
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition Type.cpp:685
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
Definition Type.cpp:974
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:288
bool isArrayTy() const
True if this is an instance of ArrayType.
Definition Type.h:279
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:282
Type * getArrayElementType() const
Definition Type.h:425
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:307
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:276
bool isTargetExtTy() const
Return true if this is a target extension type.
Definition Type.h:205
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition Type.h:319
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:287
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
Definition Type.h:397
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:286
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:284
bool isVoidTy() const
Return true if this is 'void'.
Definition Type.h:141
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
This function has undefined behavior.
op_range operands()
Definition User.h:267
void setOperand(unsigned i, Value *Val)
Definition User.h:212
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Definition User.cpp:25
Value * getOperand(unsigned i) const
Definition User.h:207
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
user_iterator user_begin()
Definition Value.h:402
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
Definition Value.cpp:393
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:549
iterator_range< user_iterator > users()
Definition Value.h:426
bool use_empty() const
Definition Value.h:346
user_iterator user_end()
Definition Value.h:410
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
Definition Value.h:806
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:318
bool user_empty() const
Definition Value.h:389
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:212
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:185
const ParentTy * getParent() const
Definition ilist_node.h:34
CallInst * Call
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ Entry
Definition COFF.h:862
@ SPIR_KERNEL
Used for SPIR kernel functions.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
IntrinsicID_match m_Intrinsic()
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_Value()
Match an arbitrary value and ignore it.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
@ CE
Windows NT (Windows on ARM)
Definition MCAsmInfo.h:50
initializer< Ty > init(const Ty &Val)
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
Definition RDFGraph.h:390
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:315
@ Offset
Definition DWP.cpp:558
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
ModulePass * createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
Definition SPIRVUtils.h:406
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2553
unsigned getPointerAddressSpace(const Type *T)
Definition SPIRVUtils.h:377
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
Definition InstrProf.h:328
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2207
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
FPDecorationId
Definition SPIRVUtils.h:550
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
bool isNestedPointer(const Type *Ty)
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
Definition SPIRVUtils.h:516
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
auto reverse(ContainerTy &&C)
Definition STLExtras.h:407
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
Definition SPIRVUtils.h:401
bool isVector1(Type *Ty)
Definition SPIRVUtils.h:494
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool isPointerTy(const Type *T)
Definition SPIRVUtils.h:371
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1752
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
@ Ref
The access may reference the value stored in memory.
Definition ModRef.h:32
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
Definition SPIRVUtils.h:390
bool hasPointeeTypeAttr(Argument *Arg)
Definition SPIRVUtils.h:385
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
Definition SPIRVUtils.h:456
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Definition iterator.h:368
bool hasInitializer(const GlobalVariable *GV)
Definition SPIRVUtils.h:352
Type * normalizeType(Type *Ty)
Definition SPIRVUtils.h:502
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
Definition DWP.h:31
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
PoisonValue * getNormalizedPoisonValue(Type *Ty)
Definition SPIRVUtils.h:512
bool isUntypedPointerTy(const Type *T)
Definition SPIRVUtils.h:366
Type * reconstitutePeeledArrayType(Type *Ty)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)
Definition SPIRVUtils.h:148