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