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