LLVM 22.0.0git
SPIRVEmitIntrinsics.cpp
Go to the documentation of this file.
1//===-- SPIRVEmitIntrinsics.cpp - emit SPIRV intrinsics ---------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The pass emits SPIRV intrinsics keeping essential high-level information for
10// the translation of LLVM IR to SPIR-V.
11//
12//===----------------------------------------------------------------------===//
13
14#include "SPIRV.h"
15#include "SPIRVBuiltins.h"
16#include "SPIRVSubtarget.h"
17#include "SPIRVTargetMachine.h"
18#include "SPIRVUtils.h"
19#include "llvm/ADT/DenseSet.h"
20#include "llvm/IR/IRBuilder.h"
22#include "llvm/IR/InstVisitor.h"
23#include "llvm/IR/IntrinsicsSPIRV.h"
27
28#include <queue>
29#include <unordered_set>
30
31// This pass performs the following transformation on LLVM IR level required
32// for the following translation to SPIR-V:
33// - replaces direct usages of aggregate constants with target-specific
34// intrinsics;
35// - replaces aggregates-related instructions (extract/insert, ld/st, etc)
36// with a target-specific intrinsics;
37// - emits intrinsics for the global variable initializers since IRTranslator
38// doesn't handle them and it's not very convenient to translate them
39// ourselves;
40// - emits intrinsics to keep track of the string names assigned to the values;
41// - emits intrinsics to keep track of constants (this is necessary to have an
42// LLVM IR constant after the IRTranslation is completed) for their further
43// deduplication;
44// - emits intrinsics to keep track of original LLVM types of the values
45// to be able to emit proper SPIR-V types eventually.
46//
47// TODO: consider removing spv.track.constant in favor of spv.assign.type.
48
49using namespace llvm;
50
51namespace llvm::SPIRV {
52#define GET_BuiltinGroup_DECL
53#include "SPIRVGenTables.inc"
54} // namespace llvm::SPIRV
55
56namespace {
57
58class SPIRVEmitIntrinsics
59 : public ModulePass,
60 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
61 SPIRVTargetMachine *TM = nullptr;
62 SPIRVGlobalRegistry *GR = nullptr;
63 Function *CurrF = nullptr;
64 bool TrackConstants = true;
65 bool HaveFunPtrs = false;
68 DenseSet<Instruction *> AggrStores;
69 std::unordered_set<Value *> Named;
70
71 // map of function declarations to <pointer arg index => element type>
73
74 // a register of Instructions that don't have a complete type definition
75 bool CanTodoType = true;
76 unsigned TodoTypeSz = 0;
78 void insertTodoType(Value *Op) {
79 // TODO: add isa<CallInst>(Op) to no-insert
80 if (CanTodoType && !isa<GetElementPtrInst>(Op)) {
81 auto It = TodoType.try_emplace(Op, true);
82 if (It.second)
83 ++TodoTypeSz;
84 }
85 }
86 void eraseTodoType(Value *Op) {
87 auto It = TodoType.find(Op);
88 if (It != TodoType.end() && It->second) {
89 It->second = false;
90 --TodoTypeSz;
91 }
92 }
93 bool isTodoType(Value *Op) {
94 if (isa<GetElementPtrInst>(Op))
95 return false;
96 auto It = TodoType.find(Op);
97 return It != TodoType.end() && It->second;
98 }
99 // a register of Instructions that were visited by deduceOperandElementType()
100 // to validate operand types with an instruction
101 std::unordered_set<Instruction *> TypeValidated;
102
103 // well known result types of builtins
104 enum WellKnownTypes { Event };
105
106 // deduce element type of untyped pointers
107 Type *deduceElementType(Value *I, bool UnknownElemTypeI8);
108 Type *deduceElementTypeHelper(Value *I, bool UnknownElemTypeI8);
109 Type *deduceElementTypeHelper(Value *I, std::unordered_set<Value *> &Visited,
110 bool UnknownElemTypeI8,
111 bool IgnoreKnownType = false);
112 Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
113 bool UnknownElemTypeI8);
114 Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
115 std::unordered_set<Value *> &Visited,
116 bool UnknownElemTypeI8);
117 Type *deduceElementTypeByUsersDeep(Value *Op,
118 std::unordered_set<Value *> &Visited,
119 bool UnknownElemTypeI8);
120 void maybeAssignPtrType(Type *&Ty, Value *I, Type *RefTy,
121 bool UnknownElemTypeI8);
122
123 // deduce nested types of composites
124 Type *deduceNestedTypeHelper(User *U, bool UnknownElemTypeI8);
125 Type *deduceNestedTypeHelper(User *U, Type *Ty,
126 std::unordered_set<Value *> &Visited,
127 bool UnknownElemTypeI8);
128
129 // deduce Types of operands of the Instruction if possible
130 void deduceOperandElementType(Instruction *I,
131 SmallPtrSet<Instruction *, 4> *IncompleteRets,
132 const SmallPtrSet<Value *, 4> *AskOps = nullptr,
133 bool IsPostprocessing = false);
134
135 void preprocessCompositeConstants(IRBuilder<> &B);
136 void preprocessUndefs(IRBuilder<> &B);
137
138 Type *reconstructType(Value *Op, bool UnknownElemTypeI8,
139 bool IsPostprocessing);
140
141 void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
142 void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);
143 bool insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B,
144 bool UnknownElemTypeI8);
145 void insertAssignTypeIntrs(Instruction *I, IRBuilder<> &B);
146 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType, Value *V,
147 IRBuilder<> &B);
148 void replacePointerOperandWithPtrCast(Instruction *I, Value *Pointer,
149 Type *ExpectedElementType,
150 unsigned OperandToReplace,
151 IRBuilder<> &B);
152 void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
153 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
155 void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
156 void processParamTypes(Function *F, IRBuilder<> &B);
157 void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
158 Type *deduceFunParamElementType(Function *F, unsigned OpIdx);
159 Type *deduceFunParamElementType(Function *F, unsigned OpIdx,
160 std::unordered_set<Function *> &FVisited);
161
162 bool deduceOperandElementTypeCalledFunction(
163 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
164 Type *&KnownElemTy, bool &Incomplete);
165 void deduceOperandElementTypeFunctionPointer(
166 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
167 Type *&KnownElemTy, bool IsPostprocessing);
168 bool deduceOperandElementTypeFunctionRet(
170 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,
171 Type *&KnownElemTy, Value *Op, Function *F);
172
173 CallInst *buildSpvPtrcast(Function *F, Value *Op, Type *ElemTy);
174 void replaceUsesOfWithSpvPtrcast(Value *Op, Type *ElemTy, Instruction *I,
176 void propagateElemType(Value *Op, Type *ElemTy,
177 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
178 void
179 propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,
180 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
181 void propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,
182 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
183 std::unordered_set<Value *> &Visited,
185
186 void replaceAllUsesWith(Value *Src, Value *Dest, bool DeleteOld = true);
187 void replaceAllUsesWithAndErase(IRBuilder<> &B, Instruction *Src,
188 Instruction *Dest, bool DeleteOld = true);
189
190 void applyDemangledPtrArgTypes(IRBuilder<> &B);
191
192 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP);
193
194 bool runOnFunction(Function &F);
195 bool postprocessTypes(Module &M);
196 bool processFunctionPointers(Module &M);
197 void parseFunDeclarations(Module &M);
198
199 void useRoundingMode(ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
200
201 // Tries to walk the type accessed by the given GEP instruction.
202 // For each nested type access, one of the 2 callbacks is called:
203 // - OnLiteralIndexing when the index is a known constant value.
204 // Parameters:
205 // PointedType: the pointed type resulting of this indexing.
206 // If the parent type is an array, this is the index in the array.
207 // If the parent type is a struct, this is the field index.
208 // Index: index of the element in the parent type.
209 // - OnDynamnicIndexing when the index is a non-constant value.
210 // This callback is only called when indexing into an array.
211 // Parameters:
212 // ElementType: the type of the elements stored in the parent array.
213 // Offset: the Value* containing the byte offset into the array.
214 // Return true if an error occured during the walk, false otherwise.
215 bool walkLogicalAccessChain(
217 const std::function<void(Type *PointedType, uint64_t Index)>
218 &OnLiteralIndexing,
219 const std::function<void(Type *ElementType, Value *Offset)>
220 &OnDynamicIndexing);
221
222 // Returns the type accessed using the given GEP instruction by relying
223 // on the GEP type.
224 // FIXME: GEP types are not supposed to be used to retrieve the pointed
225 // type. This must be fixed.
226 Type *getGEPType(GetElementPtrInst *GEP);
227
228 // Returns the type accessed using the given GEP instruction by walking
229 // the source type using the GEP indices.
230 // FIXME: without help from the frontend, this method cannot reliably retrieve
231 // the stored type, nor can robustly determine the depth of the type
232 // we are accessing.
233 Type *getGEPTypeLogical(GetElementPtrInst *GEP);
234
235 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &GEP);
236
237public:
238 static char ID;
239 SPIRVEmitIntrinsics(SPIRVTargetMachine *TM = nullptr)
240 : ModulePass(ID), TM(TM) {}
255
256 StringRef getPassName() const override { return "SPIRV emit intrinsics"; }
257
258 bool runOnModule(Module &M) override;
259
260 void getAnalysisUsage(AnalysisUsage &AU) const override {
262 }
263};
264
265bool isConvergenceIntrinsic(const Instruction *I) {
266 const auto *II = dyn_cast<IntrinsicInst>(I);
267 if (!II)
268 return false;
269
270 return II->getIntrinsicID() == Intrinsic::experimental_convergence_entry ||
271 II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||
272 II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor;
273}
274
275bool expectIgnoredInIRTranslation(const Instruction *I) {
276 const auto *II = dyn_cast<IntrinsicInst>(I);
277 if (!II)
278 return false;
279 switch (II->getIntrinsicID()) {
280 case Intrinsic::invariant_start:
281 case Intrinsic::spv_resource_handlefrombinding:
282 case Intrinsic::spv_resource_getpointer:
283 return true;
284 default:
285 return false;
286 }
287}
288
289// Returns the source pointer from `I` ignoring intermediate ptrcast.
290Value *getPointerRoot(Value *I) {
291 if (auto *II = dyn_cast<IntrinsicInst>(I)) {
292 if (II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
293 Value *V = II->getArgOperand(0);
294 return getPointerRoot(V);
295 }
296 }
297 return I;
298}
299
300} // namespace
301
302char SPIRVEmitIntrinsics::ID = 0;
303
304INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics",
305 false, false)
306
307static inline bool isAssignTypeInstr(const Instruction *I) {
308 return isa<IntrinsicInst>(I) &&
309 cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type;
310}
311
313 return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) ||
314 isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I);
315}
316
317static bool isAggrConstForceInt32(const Value *V) {
318 return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||
319 isa<ConstantDataArray>(V) ||
320 (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
321}
322
324 if (isa<PHINode>(I))
325 B.SetInsertPoint(I->getParent()->getFirstNonPHIOrDbgOrAlloca());
326 else
327 B.SetInsertPoint(I);
328}
329
331 B.SetCurrentDebugLocation(I->getDebugLoc());
332 if (I->getType()->isVoidTy())
333 B.SetInsertPoint(I->getNextNode());
334 else
335 B.SetInsertPoint(*I->getInsertionPointAfterDef());
336}
337
339 if (const auto *Intr = dyn_cast<IntrinsicInst>(I)) {
340 switch (Intr->getIntrinsicID()) {
341 case Intrinsic::invariant_start:
342 case Intrinsic::invariant_end:
343 return false;
344 }
345 }
346 return true;
347}
348
349static inline void reportFatalOnTokenType(const Instruction *I) {
350 if (I->getType()->isTokenTy())
351 report_fatal_error("A token is encountered but SPIR-V without extensions "
352 "does not support token type",
353 false);
354}
355
357 if (!I->hasName() || I->getType()->isAggregateType() ||
358 expectIgnoredInIRTranslation(I))
359 return;
362 LLVMContext &Ctx = I->getContext();
363 std::vector<Value *> Args = {
365 Ctx, MDNode::get(Ctx, MDString::get(Ctx, I->getName())))};
366 B.CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);
367}
368
369void SPIRVEmitIntrinsics::replaceAllUsesWith(Value *Src, Value *Dest,
370 bool DeleteOld) {
371 GR->replaceAllUsesWith(Src, Dest, DeleteOld);
372 // Update uncomplete type records if any
373 if (isTodoType(Src)) {
374 if (DeleteOld)
375 eraseTodoType(Src);
376 insertTodoType(Dest);
377 }
378}
379
380void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(IRBuilder<> &B,
381 Instruction *Src,
382 Instruction *Dest,
383 bool DeleteOld) {
384 replaceAllUsesWith(Src, Dest, DeleteOld);
385 std::string Name = Src->hasName() ? Src->getName().str() : "";
386 Src->eraseFromParent();
387 if (!Name.empty()) {
388 Dest->setName(Name);
389 if (Named.insert(Dest).second)
390 emitAssignName(Dest, B);
391 }
392}
393
395 return SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&
396 isPointerTy(SI->getValueOperand()->getType()) &&
397 isa<Argument>(SI->getValueOperand());
398}
399
400// Maybe restore original function return type.
402 Type *Ty) {
403 CallInst *CI = dyn_cast<CallInst>(I);
404 if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||
406 return Ty;
407 if (Type *OriginalTy = GR->findMutated(CI->getCalledFunction()))
408 return OriginalTy;
409 return Ty;
410}
411
412// Reconstruct type with nested element types according to deduced type info.
413// Return nullptr if no detailed type info is available.
414Type *SPIRVEmitIntrinsics::reconstructType(Value *Op, bool UnknownElemTypeI8,
415 bool IsPostprocessing) {
416 Type *Ty = Op->getType();
417 if (auto *OpI = dyn_cast<Instruction>(Op))
418 Ty = restoreMutatedType(GR, OpI, Ty);
419 if (!isUntypedPointerTy(Ty))
420 return Ty;
421 // try to find the pointee type
422 if (Type *NestedTy = GR->findDeducedElementType(Op))
424 // not a pointer according to the type info (e.g., Event object)
425 CallInst *CI = GR->findAssignPtrTypeInstr(Op);
426 if (CI) {
427 MetadataAsValue *MD = cast<MetadataAsValue>(CI->getArgOperand(1));
428 return cast<ConstantAsMetadata>(MD->getMetadata())->getType();
429 }
430 if (UnknownElemTypeI8) {
431 if (!IsPostprocessing)
432 insertTodoType(Op);
433 return getTypedPointerWrapper(IntegerType::getInt8Ty(Op->getContext()),
435 }
436 return nullptr;
437}
438
439CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,
440 Type *ElemTy) {
441 IRBuilder<> B(Op->getContext());
442 if (auto *OpI = dyn_cast<Instruction>(Op)) {
443 // spv_ptrcast's argument Op denotes an instruction that generates
444 // a value, and we may use getInsertionPointAfterDef()
446 } else if (auto *OpA = dyn_cast<Argument>(Op)) {
447 B.SetInsertPointPastAllocas(OpA->getParent());
448 B.SetCurrentDebugLocation(DebugLoc());
449 } else {
450 B.SetInsertPoint(F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
451 }
452 Type *OpTy = Op->getType();
453 SmallVector<Type *, 2> Types = {OpTy, OpTy};
455 B.getInt32(getPointerAddressSpace(OpTy))};
456 CallInst *PtrCasted =
457 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
458 GR->buildAssignPtr(B, ElemTy, PtrCasted);
459 return PtrCasted;
460}
461
462void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
463 Value *Op, Type *ElemTy, Instruction *I,
465 Function *F = I->getParent()->getParent();
466 CallInst *PtrCastedI = nullptr;
467 auto It = Ptrcasts.find(F);
468 if (It == Ptrcasts.end()) {
469 PtrCastedI = buildSpvPtrcast(F, Op, ElemTy);
470 Ptrcasts[F] = PtrCastedI;
471 } else {
472 PtrCastedI = It->second;
473 }
474 I->replaceUsesOfWith(Op, PtrCastedI);
475}
476
477void SPIRVEmitIntrinsics::propagateElemType(
478 Value *Op, Type *ElemTy,
479 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
481 SmallVector<User *> Users(Op->users());
482 for (auto *U : Users) {
483 if (!isa<Instruction>(U) || isSpvIntrinsic(U))
484 continue;
485 if (!VisitedSubst.insert(std::make_pair(U, Op)).second)
486 continue;
487 Instruction *UI = dyn_cast<Instruction>(U);
488 // If the instruction was validated already, we need to keep it valid by
489 // keeping current Op type.
490 if (isa<GetElementPtrInst>(UI) ||
491 TypeValidated.find(UI) != TypeValidated.end())
492 replaceUsesOfWithSpvPtrcast(Op, ElemTy, UI, Ptrcasts);
493 }
494}
495
496void SPIRVEmitIntrinsics::propagateElemTypeRec(
497 Value *Op, Type *PtrElemTy, Type *CastElemTy,
498 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
499 std::unordered_set<Value *> Visited;
501 propagateElemTypeRec(Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
502 std::move(Ptrcasts));
503}
504
505void SPIRVEmitIntrinsics::propagateElemTypeRec(
506 Value *Op, Type *PtrElemTy, Type *CastElemTy,
507 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
508 std::unordered_set<Value *> &Visited,
510 if (!Visited.insert(Op).second)
511 return;
512 SmallVector<User *> Users(Op->users());
513 for (auto *U : Users) {
514 if (!isa<Instruction>(U) || isSpvIntrinsic(U))
515 continue;
516 if (!VisitedSubst.insert(std::make_pair(U, Op)).second)
517 continue;
518 Instruction *UI = dyn_cast<Instruction>(U);
519 // If the instruction was validated already, we need to keep it valid by
520 // keeping current Op type.
521 if (isa<GetElementPtrInst>(UI) ||
522 TypeValidated.find(UI) != TypeValidated.end())
523 replaceUsesOfWithSpvPtrcast(Op, CastElemTy, UI, Ptrcasts);
524 }
525}
526
527// Set element pointer type to the given value of ValueTy and tries to
528// specify this type further (recursively) by Operand value, if needed.
529
530Type *
531SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
532 bool UnknownElemTypeI8) {
533 std::unordered_set<Value *> Visited;
534 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
535 UnknownElemTypeI8);
536}
537
538Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
539 Type *ValueTy, Value *Operand, std::unordered_set<Value *> &Visited,
540 bool UnknownElemTypeI8) {
541 Type *Ty = ValueTy;
542 if (Operand) {
543 if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
544 if (Type *NestedTy =
545 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
546 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
547 } else {
548 Ty = deduceNestedTypeHelper(dyn_cast<User>(Operand), Ty, Visited,
549 UnknownElemTypeI8);
550 }
551 }
552 return Ty;
553}
554
555// Traverse User instructions to deduce an element pointer type of the operand.
556Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
557 Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {
558 if (!Op || !isPointerTy(Op->getType()) || isa<ConstantPointerNull>(Op) ||
559 isa<UndefValue>(Op))
560 return nullptr;
561
562 if (auto ElemTy = getPointeeType(Op->getType()))
563 return ElemTy;
564
565 // maybe we already know operand's element type
566 if (Type *KnownTy = GR->findDeducedElementType(Op))
567 return KnownTy;
568
569 for (User *OpU : Op->users()) {
570 if (Instruction *Inst = dyn_cast<Instruction>(OpU)) {
571 if (Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
572 return Ty;
573 }
574 }
575 return nullptr;
576}
577
578// Implements what we know in advance about intrinsics and builtin calls
579// TODO: consider feasibility of this particular case to be generalized by
580// encoding knowledge about intrinsics and builtin calls by corresponding
581// specification rules
583 Function *CalledF, unsigned OpIdx) {
584 if ((DemangledName.starts_with("__spirv_ocl_printf(") ||
585 DemangledName.starts_with("printf(")) &&
586 OpIdx == 0)
587 return IntegerType::getInt8Ty(CalledF->getContext());
588 return nullptr;
589}
590
591// Deduce and return a successfully deduced Type of the Instruction,
592// or nullptr otherwise.
593Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
594 bool UnknownElemTypeI8) {
595 std::unordered_set<Value *> Visited;
596 return deduceElementTypeHelper(I, Visited, UnknownElemTypeI8);
597}
598
599void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,
600 bool UnknownElemTypeI8) {
601 if (isUntypedPointerTy(RefTy)) {
602 if (!UnknownElemTypeI8)
603 return;
604 insertTodoType(Op);
605 }
606 Ty = RefTy;
607}
608
609bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
611 const std::function<void(Type *, uint64_t)> &OnLiteralIndexing,
612 const std::function<void(Type *, Value *)> &OnDynamicIndexing) {
613 // We only rewrite i8* GEP. Other should be left as-is.
614 // Valid i8* GEP must always have a single index.
615 assert(GEP.getSourceElementType() ==
616 IntegerType::getInt8Ty(CurrF->getContext()));
617 assert(GEP.getNumIndices() == 1);
618
619 auto &DL = CurrF->getDataLayout();
620 Value *Src = getPointerRoot(GEP.getPointerOperand());
621 Type *CurType = deduceElementType(Src, true);
622
623 Value *Operand = *GEP.idx_begin();
624 ConstantInt *CI = dyn_cast<ConstantInt>(Operand);
625 if (!CI) {
626 ArrayType *AT = dyn_cast<ArrayType>(CurType);
627 // Operand is not constant. Either we have an array and accept it, or we
628 // give up.
629 if (AT)
630 OnDynamicIndexing(AT->getElementType(), Operand);
631 return AT == nullptr;
632 }
633
634 assert(CI);
636
637 do {
638 if (ArrayType *AT = dyn_cast<ArrayType>(CurType)) {
639 uint32_t EltTypeSize = DL.getTypeSizeInBits(AT->getElementType()) / 8;
640 assert(Offset < AT->getNumElements() * EltTypeSize);
641 uint64_t Index = Offset / EltTypeSize;
642 Offset = Offset - (Index * EltTypeSize);
643 CurType = AT->getElementType();
644 OnLiteralIndexing(CurType, Index);
645 } else if (StructType *ST = dyn_cast<StructType>(CurType)) {
646 uint32_t StructSize = DL.getTypeSizeInBits(ST) / 8;
647 assert(Offset < StructSize);
648 (void)StructSize;
649 const auto &STL = DL.getStructLayout(ST);
650 unsigned Element = STL->getElementContainingOffset(Offset);
651 Offset -= STL->getElementOffset(Element);
652 CurType = ST->getElementType(Element);
653 OnLiteralIndexing(CurType, Element);
654 } else {
655 // Vector type indexing should not use GEP.
656 // So if we have an index left, something is wrong. Giving up.
657 return true;
658 }
659 } while (Offset > 0);
660
661 return false;
662}
663
665SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &GEP) {
666 auto &DL = CurrF->getDataLayout();
667 IRBuilder<> B(GEP.getParent());
668 B.SetInsertPoint(&GEP);
669
670 std::vector<Value *> Indices;
671 Indices.push_back(ConstantInt::get(
672 IntegerType::getInt32Ty(CurrF->getContext()), 0, /* Signed= */ false));
673 walkLogicalAccessChain(
674 GEP,
675 [&Indices, &B](Type *EltType, uint64_t Index) {
676 Indices.push_back(
677 ConstantInt::get(B.getInt64Ty(), Index, /* Signed= */ false));
678 },
679 [&Indices, &B, &DL](Type *EltType, Value *Offset) {
680 uint32_t EltTypeSize = DL.getTypeSizeInBits(EltType) / 8;
681 Value *Index = B.CreateUDiv(
682 Offset, ConstantInt::get(Offset->getType(), EltTypeSize,
683 /* Signed= */ false));
684 Indices.push_back(Index);
685 });
686
687 SmallVector<Type *, 2> Types = {GEP.getType(), GEP.getOperand(0)->getType()};
689 Args.push_back(B.getInt1(GEP.isInBounds()));
690 Args.push_back(GEP.getOperand(0));
691 llvm::append_range(Args, Indices);
692 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
693 replaceAllUsesWithAndErase(B, &GEP, NewI);
694 return NewI;
695}
696
697Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *GEP) {
698
699 Type *CurType = GEP->getResultElementType();
700
701 bool Interrupted = walkLogicalAccessChain(
702 *GEP, [&CurType](Type *EltType, uint64_t Index) { CurType = EltType; },
703 [&CurType](Type *EltType, Value *Index) { CurType = EltType; });
704
705 return Interrupted ? GEP->getResultElementType() : CurType;
706}
707
708Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *Ref) {
709 if (Ref->getSourceElementType() ==
710 IntegerType::getInt8Ty(CurrF->getContext()) &&
711 TM->getSubtargetImpl()->isLogicalSPIRV()) {
712 return getGEPTypeLogical(Ref);
713 }
714
715 Type *Ty = nullptr;
716 // TODO: not sure if GetElementPtrInst::getTypeAtIndex() does anything
717 // useful here
718 if (isNestedPointer(Ref->getSourceElementType())) {
719 Ty = Ref->getSourceElementType();
720 for (Use &U : drop_begin(Ref->indices()))
721 Ty = GetElementPtrInst::getTypeAtIndex(Ty, U.get());
722 } else {
723 Ty = Ref->getResultElementType();
724 }
725 return Ty;
726}
727
728Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
729 Value *I, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8,
730 bool IgnoreKnownType) {
731 // allow to pass nullptr as an argument
732 if (!I)
733 return nullptr;
734
735 // maybe already known
736 if (!IgnoreKnownType)
737 if (Type *KnownTy = GR->findDeducedElementType(I))
738 return KnownTy;
739
740 // maybe a cycle
741 if (!Visited.insert(I).second)
742 return nullptr;
743
744 // fallback value in case when we fail to deduce a type
745 Type *Ty = nullptr;
746 // look for known basic patterns of type inference
747 if (auto *Ref = dyn_cast<AllocaInst>(I)) {
748 maybeAssignPtrType(Ty, I, Ref->getAllocatedType(), UnknownElemTypeI8);
749 } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
750 Ty = getGEPType(Ref);
751 } else if (auto *Ref = dyn_cast<LoadInst>(I)) {
752 Value *Op = Ref->getPointerOperand();
753 Type *KnownTy = GR->findDeducedElementType(Op);
754 if (!KnownTy)
755 KnownTy = Op->getType();
756 if (Type *ElemTy = getPointeeType(KnownTy))
757 maybeAssignPtrType(Ty, I, ElemTy, UnknownElemTypeI8);
758 } else if (auto *Ref = dyn_cast<GlobalValue>(I)) {
759 Ty = deduceElementTypeByValueDeep(
760 Ref->getValueType(),
761 Ref->getNumOperands() > 0 ? Ref->getOperand(0) : nullptr, Visited,
762 UnknownElemTypeI8);
763 } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {
764 Type *RefTy = deduceElementTypeHelper(Ref->getPointerOperand(), Visited,
765 UnknownElemTypeI8);
766 maybeAssignPtrType(Ty, I, RefTy, UnknownElemTypeI8);
767 } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {
768 if (Type *Src = Ref->getSrcTy(), *Dest = Ref->getDestTy();
769 isPointerTy(Src) && isPointerTy(Dest))
770 Ty = deduceElementTypeHelper(Ref->getOperand(0), Visited,
771 UnknownElemTypeI8);
772 } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {
773 Value *Op = Ref->getNewValOperand();
774 if (isPointerTy(Op->getType()))
775 Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
776 } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {
777 Value *Op = Ref->getValOperand();
778 if (isPointerTy(Op->getType()))
779 Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
780 } else if (auto *Ref = dyn_cast<PHINode>(I)) {
781 Type *BestTy = nullptr;
782 unsigned MaxN = 1;
784 for (int i = Ref->getNumIncomingValues() - 1; i >= 0; --i) {
785 Ty = deduceElementTypeByUsersDeep(Ref->getIncomingValue(i), Visited,
786 UnknownElemTypeI8);
787 if (!Ty)
788 continue;
789 auto It = PhiTys.try_emplace(Ty, 1);
790 if (!It.second) {
791 ++It.first->second;
792 if (It.first->second > MaxN) {
793 MaxN = It.first->second;
794 BestTy = Ty;
795 }
796 }
797 }
798 if (BestTy)
799 Ty = BestTy;
800 } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
801 for (Value *Op : {Ref->getTrueValue(), Ref->getFalseValue()}) {
802 Ty = deduceElementTypeByUsersDeep(Op, Visited, UnknownElemTypeI8);
803 if (Ty)
804 break;
805 }
806 } else if (auto *CI = dyn_cast<CallInst>(I)) {
807 static StringMap<unsigned> ResTypeByArg = {
808 {"to_global", 0},
809 {"to_local", 0},
810 {"to_private", 0},
811 {"__spirv_GenericCastToPtr_ToGlobal", 0},
812 {"__spirv_GenericCastToPtr_ToLocal", 0},
813 {"__spirv_GenericCastToPtr_ToPrivate", 0},
814 {"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
815 {"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
816 {"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
817 // TODO: maybe improve performance by caching demangled names
818
819 auto *II = dyn_cast<IntrinsicInst>(I);
820 if (II && II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
821 auto *HandleType = cast<TargetExtType>(II->getOperand(0)->getType());
822 if (HandleType->getTargetExtName() == "spirv.Image" ||
823 HandleType->getTargetExtName() == "spirv.SignedImage") {
824 for (User *U : II->users()) {
825 Ty = cast<Instruction>(U)->getAccessType();
826 if (Ty)
827 break;
828 }
829 } else if (HandleType->getTargetExtName() == "spirv.VulkanBuffer") {
830 // This call is supposed to index into an array
831 Ty = HandleType->getTypeParameter(0);
832 if (Ty->isArrayTy())
833 Ty = Ty->getArrayElementType();
834 else {
835 TargetExtType *BufferTy = cast<TargetExtType>(Ty);
836 assert(BufferTy->getTargetExtName() == "spirv.Layout");
837 Ty = BufferTy->getTypeParameter(0);
838 assert(Ty && Ty->isStructTy());
839 uint32_t Index = cast<ConstantInt>(II->getOperand(1))->getZExtValue();
840 Ty = cast<StructType>(Ty)->getElementType(Index);
841 }
842 } else {
843 llvm_unreachable("Unknown handle type for spv_resource_getpointer.");
844 }
845 } else if (II && II->getIntrinsicID() ==
846 Intrinsic::spv_generic_cast_to_ptr_explicit) {
847 Ty = deduceElementTypeHelper(CI->getArgOperand(0), Visited,
848 UnknownElemTypeI8);
849 } else if (Function *CalledF = CI->getCalledFunction()) {
850 std::string DemangledName =
851 getOclOrSpirvBuiltinDemangledName(CalledF->getName());
852 if (DemangledName.length() > 0)
853 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
854 auto AsArgIt = ResTypeByArg.find(DemangledName);
855 if (AsArgIt != ResTypeByArg.end())
856 Ty = deduceElementTypeHelper(CI->getArgOperand(AsArgIt->second),
857 Visited, UnknownElemTypeI8);
858 else if (Type *KnownRetTy = GR->findDeducedElementType(CalledF))
859 Ty = KnownRetTy;
860 }
861 }
862
863 // remember the found relationship
864 if (Ty && !IgnoreKnownType) {
865 // specify nested types if needed, otherwise return unchanged
866 GR->addDeducedElementType(I, normalizeType(Ty));
867 }
868
869 return Ty;
870}
871
872// Re-create a type of the value if it has untyped pointer fields, also nested.
873// Return the original value type if no corrections of untyped pointer
874// information is found or needed.
875Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
876 bool UnknownElemTypeI8) {
877 std::unordered_set<Value *> Visited;
878 return deduceNestedTypeHelper(U, U->getType(), Visited, UnknownElemTypeI8);
879}
880
881Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
882 User *U, Type *OrigTy, std::unordered_set<Value *> &Visited,
883 bool UnknownElemTypeI8) {
884 if (!U)
885 return OrigTy;
886
887 // maybe already known
888 if (Type *KnownTy = GR->findDeducedCompositeType(U))
889 return KnownTy;
890
891 // maybe a cycle
892 if (!Visited.insert(U).second)
893 return OrigTy;
894
895 if (isa<StructType>(OrigTy)) {
897 bool Change = false;
898 for (unsigned i = 0; i < U->getNumOperands(); ++i) {
899 Value *Op = U->getOperand(i);
900 assert(Op && "Operands should not be null.");
901 Type *OpTy = Op->getType();
902 Type *Ty = OpTy;
903 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
904 if (Type *NestedTy =
905 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
906 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
907 } else {
908 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
909 UnknownElemTypeI8);
910 }
911 Tys.push_back(Ty);
912 Change |= Ty != OpTy;
913 }
914 if (Change) {
915 Type *NewTy = StructType::create(Tys);
916 GR->addDeducedCompositeType(U, NewTy);
917 return NewTy;
918 }
919 } else if (auto *ArrTy = dyn_cast<ArrayType>(OrigTy)) {
920 if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {
921 Type *OpTy = ArrTy->getElementType();
922 Type *Ty = OpTy;
923 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
924 if (Type *NestedTy =
925 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
926 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
927 } else {
928 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
929 UnknownElemTypeI8);
930 }
931 if (Ty != OpTy) {
932 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
933 GR->addDeducedCompositeType(U, NewTy);
934 return NewTy;
935 }
936 }
937 } else if (auto *VecTy = dyn_cast<VectorType>(OrigTy)) {
938 if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {
939 Type *OpTy = VecTy->getElementType();
940 Type *Ty = OpTy;
941 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
942 if (Type *NestedTy =
943 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
944 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
945 } else {
946 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
947 UnknownElemTypeI8);
948 }
949 if (Ty != OpTy) {
950 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
951 GR->addDeducedCompositeType(U, normalizeType(NewTy));
952 return NewTy;
953 }
954 }
955 }
956
957 return OrigTy;
958}
959
960Type *SPIRVEmitIntrinsics::deduceElementType(Value *I, bool UnknownElemTypeI8) {
961 if (Type *Ty = deduceElementTypeHelper(I, UnknownElemTypeI8))
962 return Ty;
963 if (!UnknownElemTypeI8)
964 return nullptr;
965 insertTodoType(I);
966 return IntegerType::getInt8Ty(I->getContext());
967}
968
970 Value *PointerOperand) {
971 Type *PointeeTy = GR->findDeducedElementType(PointerOperand);
972 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
973 return nullptr;
974 auto *PtrTy = dyn_cast<PointerType>(I->getType());
975 if (!PtrTy)
976 return I->getType();
977 if (Type *NestedTy = GR->findDeducedElementType(I))
978 return getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
979 return nullptr;
980}
981
982// Try to deduce element type for a call base. Returns false if this is an
983// indirect function invocation, and true otherwise.
984bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
985 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
986 Type *&KnownElemTy, bool &Incomplete) {
987 Function *CalledF = CI->getCalledFunction();
988 if (!CalledF)
989 return false;
990 std::string DemangledName =
992 if (DemangledName.length() > 0 &&
993 !StringRef(DemangledName).starts_with("llvm.")) {
994 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(*CalledF);
995 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
996 DemangledName, ST.getPreferredInstructionSet());
997 if (Opcode == SPIRV::OpGroupAsyncCopy) {
998 for (unsigned i = 0, PtrCnt = 0; i < CI->arg_size() && PtrCnt < 2; ++i) {
999 Value *Op = CI->getArgOperand(i);
1000 if (!isPointerTy(Op->getType()))
1001 continue;
1002 ++PtrCnt;
1003 if (Type *ElemTy = GR->findDeducedElementType(Op))
1004 KnownElemTy = ElemTy; // src will rewrite dest if both are defined
1005 Ops.push_back(std::make_pair(Op, i));
1006 }
1007 } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1008 if (CI->arg_size() == 0)
1009 return true;
1010 Value *Op = CI->getArgOperand(0);
1011 if (!isPointerTy(Op->getType()))
1012 return true;
1013 switch (Opcode) {
1014 case SPIRV::OpAtomicFAddEXT:
1015 case SPIRV::OpAtomicFMinEXT:
1016 case SPIRV::OpAtomicFMaxEXT:
1017 case SPIRV::OpAtomicLoad:
1018 case SPIRV::OpAtomicCompareExchangeWeak:
1019 case SPIRV::OpAtomicCompareExchange:
1020 case SPIRV::OpAtomicExchange:
1021 case SPIRV::OpAtomicIAdd:
1022 case SPIRV::OpAtomicISub:
1023 case SPIRV::OpAtomicOr:
1024 case SPIRV::OpAtomicXor:
1025 case SPIRV::OpAtomicAnd:
1026 case SPIRV::OpAtomicUMin:
1027 case SPIRV::OpAtomicUMax:
1028 case SPIRV::OpAtomicSMin:
1029 case SPIRV::OpAtomicSMax: {
1030 KnownElemTy = isPointerTy(CI->getType()) ? getAtomicElemTy(GR, CI, Op)
1031 : CI->getType();
1032 if (!KnownElemTy)
1033 return true;
1034 Incomplete = isTodoType(Op);
1035 Ops.push_back(std::make_pair(Op, 0));
1036 } break;
1037 case SPIRV::OpAtomicStore: {
1038 if (CI->arg_size() < 4)
1039 return true;
1040 Value *ValOp = CI->getArgOperand(3);
1041 KnownElemTy = isPointerTy(ValOp->getType())
1042 ? getAtomicElemTy(GR, CI, Op)
1043 : ValOp->getType();
1044 if (!KnownElemTy)
1045 return true;
1046 Incomplete = isTodoType(Op);
1047 Ops.push_back(std::make_pair(Op, 0));
1048 } break;
1049 }
1050 }
1051 }
1052 return true;
1053}
1054
1055// Try to deduce element type for a function pointer.
1056void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1057 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
1058 Type *&KnownElemTy, bool IsPostprocessing) {
1059 Value *Op = CI->getCalledOperand();
1060 if (!Op || !isPointerTy(Op->getType()))
1061 return;
1062 Ops.push_back(std::make_pair(Op, std::numeric_limits<unsigned>::max()));
1063 FunctionType *FTy = CI->getFunctionType();
1064 bool IsNewFTy = false, IsIncomplete = false;
1066 for (Value *Arg : CI->args()) {
1067 Type *ArgTy = Arg->getType();
1068 if (ArgTy->isPointerTy()) {
1069 if (Type *ElemTy = GR->findDeducedElementType(Arg)) {
1070 IsNewFTy = true;
1071 ArgTy = getTypedPointerWrapper(ElemTy, getPointerAddressSpace(ArgTy));
1072 if (isTodoType(Arg))
1073 IsIncomplete = true;
1074 } else {
1075 IsIncomplete = true;
1076 }
1077 }
1078 ArgTys.push_back(ArgTy);
1079 }
1080 Type *RetTy = FTy->getReturnType();
1081 if (CI->getType()->isPointerTy()) {
1082 if (Type *ElemTy = GR->findDeducedElementType(CI)) {
1083 IsNewFTy = true;
1084 RetTy =
1086 if (isTodoType(CI))
1087 IsIncomplete = true;
1088 } else {
1089 IsIncomplete = true;
1090 }
1091 }
1092 if (!IsPostprocessing && IsIncomplete)
1093 insertTodoType(Op);
1094 KnownElemTy =
1095 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1096}
1097
1098bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1100 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,
1101 Type *&KnownElemTy, Value *Op, Function *F) {
1102 KnownElemTy = GR->findDeducedElementType(F);
1103 if (KnownElemTy)
1104 return false;
1105 if (Type *OpElemTy = GR->findDeducedElementType(Op)) {
1106 OpElemTy = normalizeType(OpElemTy);
1107 GR->addDeducedElementType(F, OpElemTy);
1108 GR->addReturnType(
1109 F, TypedPointerType::get(OpElemTy,
1110 getPointerAddressSpace(F->getReturnType())));
1111 // non-recursive update of types in function uses
1112 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(I, Op)};
1113 for (User *U : F->users()) {
1114 CallInst *CI = dyn_cast<CallInst>(U);
1115 if (!CI || CI->getCalledFunction() != F)
1116 continue;
1117 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(CI)) {
1118 if (Type *PrevElemTy = GR->findDeducedElementType(CI)) {
1119 GR->updateAssignType(AssignCI, CI,
1120 getNormalizedPoisonValue(OpElemTy));
1121 propagateElemType(CI, PrevElemTy, VisitedSubst);
1122 }
1123 }
1124 }
1125 // Non-recursive update of types in the function uncomplete returns.
1126 // This may happen just once per a function, the latch is a pair of
1127 // findDeducedElementType(F) / addDeducedElementType(F, ...).
1128 // With or without the latch it is a non-recursive call due to
1129 // IncompleteRets set to nullptr in this call.
1130 if (IncompleteRets)
1131 for (Instruction *IncompleteRetI : *IncompleteRets)
1132 deduceOperandElementType(IncompleteRetI, nullptr, AskOps,
1133 IsPostprocessing);
1134 } else if (IncompleteRets) {
1135 IncompleteRets->insert(I);
1136 }
1137 TypeValidated.insert(I);
1138 return true;
1139}
1140
1141// If the Instruction has Pointer operands with unresolved types, this function
1142// tries to deduce them. If the Instruction has Pointer operands with known
1143// types which differ from expected, this function tries to insert a bitcast to
1144// resolve the issue.
1145void SPIRVEmitIntrinsics::deduceOperandElementType(
1147 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing) {
1149 Type *KnownElemTy = nullptr;
1150 bool Incomplete = false;
1151 // look for known basic patterns of type inference
1152 if (auto *Ref = dyn_cast<PHINode>(I)) {
1153 if (!isPointerTy(I->getType()) ||
1154 !(KnownElemTy = GR->findDeducedElementType(I)))
1155 return;
1156 Incomplete = isTodoType(I);
1157 for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {
1158 Value *Op = Ref->getIncomingValue(i);
1159 if (isPointerTy(Op->getType()))
1160 Ops.push_back(std::make_pair(Op, i));
1161 }
1162 } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {
1163 KnownElemTy = GR->findDeducedElementType(I);
1164 if (!KnownElemTy)
1165 return;
1166 Incomplete = isTodoType(I);
1167 Ops.push_back(std::make_pair(Ref->getPointerOperand(), 0));
1168 } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {
1169 if (!isPointerTy(I->getType()))
1170 return;
1171 KnownElemTy = GR->findDeducedElementType(I);
1172 if (!KnownElemTy)
1173 return;
1174 Incomplete = isTodoType(I);
1175 Ops.push_back(std::make_pair(Ref->getOperand(0), 0));
1176 } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
1177 if (GR->findDeducedElementType(Ref->getPointerOperand()))
1178 return;
1179 KnownElemTy = Ref->getSourceElementType();
1180 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1182 } else if (auto *Ref = dyn_cast<LoadInst>(I)) {
1183 KnownElemTy = I->getType();
1184 if (isUntypedPointerTy(KnownElemTy))
1185 return;
1186 Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
1187 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
1188 return;
1189 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1191 } else if (auto *Ref = dyn_cast<StoreInst>(I)) {
1192 if (!(KnownElemTy =
1193 reconstructType(Ref->getValueOperand(), false, IsPostprocessing)))
1194 return;
1195 Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
1196 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
1197 return;
1198 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1200 } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {
1201 KnownElemTy = isPointerTy(I->getType())
1202 ? getAtomicElemTy(GR, I, Ref->getPointerOperand())
1203 : I->getType();
1204 if (!KnownElemTy)
1205 return;
1206 Incomplete = isTodoType(Ref->getPointerOperand());
1207 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1209 } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {
1210 KnownElemTy = isPointerTy(I->getType())
1211 ? getAtomicElemTy(GR, I, Ref->getPointerOperand())
1212 : I->getType();
1213 if (!KnownElemTy)
1214 return;
1215 Incomplete = isTodoType(Ref->getPointerOperand());
1216 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1218 } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
1219 if (!isPointerTy(I->getType()) ||
1220 !(KnownElemTy = GR->findDeducedElementType(I)))
1221 return;
1222 Incomplete = isTodoType(I);
1223 for (unsigned i = 0; i < Ref->getNumOperands(); i++) {
1224 Value *Op = Ref->getOperand(i);
1225 if (isPointerTy(Op->getType()))
1226 Ops.push_back(std::make_pair(Op, i));
1227 }
1228 } else if (auto *Ref = dyn_cast<ReturnInst>(I)) {
1229 if (!isPointerTy(CurrF->getReturnType()))
1230 return;
1231 Value *Op = Ref->getReturnValue();
1232 if (!Op)
1233 return;
1234 if (deduceOperandElementTypeFunctionRet(I, IncompleteRets, AskOps,
1235 IsPostprocessing, KnownElemTy, Op,
1236 CurrF))
1237 return;
1238 Incomplete = isTodoType(CurrF);
1239 Ops.push_back(std::make_pair(Op, 0));
1240 } else if (auto *Ref = dyn_cast<ICmpInst>(I)) {
1241 if (!isPointerTy(Ref->getOperand(0)->getType()))
1242 return;
1243 Value *Op0 = Ref->getOperand(0);
1244 Value *Op1 = Ref->getOperand(1);
1245 bool Incomplete0 = isTodoType(Op0);
1246 bool Incomplete1 = isTodoType(Op1);
1247 Type *ElemTy1 = GR->findDeducedElementType(Op1);
1248 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1249 ? nullptr
1250 : GR->findDeducedElementType(Op0);
1251 if (ElemTy0) {
1252 KnownElemTy = ElemTy0;
1253 Incomplete = Incomplete0;
1254 Ops.push_back(std::make_pair(Op1, 1));
1255 } else if (ElemTy1) {
1256 KnownElemTy = ElemTy1;
1257 Incomplete = Incomplete1;
1258 Ops.push_back(std::make_pair(Op0, 0));
1259 }
1260 } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
1261 if (!CI->isIndirectCall())
1262 deduceOperandElementTypeCalledFunction(CI, Ops, KnownElemTy, Incomplete);
1263 else if (HaveFunPtrs)
1264 deduceOperandElementTypeFunctionPointer(CI, Ops, KnownElemTy,
1265 IsPostprocessing);
1266 }
1267
1268 // There is no enough info to deduce types or all is valid.
1269 if (!KnownElemTy || Ops.size() == 0)
1270 return;
1271
1272 LLVMContext &Ctx = CurrF->getContext();
1273 IRBuilder<> B(Ctx);
1274 for (auto &OpIt : Ops) {
1275 Value *Op = OpIt.first;
1276 if (AskOps && !AskOps->contains(Op))
1277 continue;
1278 Type *AskTy = nullptr;
1279 CallInst *AskCI = nullptr;
1280 if (IsPostprocessing && AskOps) {
1281 AskTy = GR->findDeducedElementType(Op);
1282 AskCI = GR->findAssignPtrTypeInstr(Op);
1283 assert(AskTy && AskCI);
1284 }
1285 Type *Ty = AskTy ? AskTy : GR->findDeducedElementType(Op);
1286 if (Ty == KnownElemTy)
1287 continue;
1288 Value *OpTyVal = getNormalizedPoisonValue(KnownElemTy);
1289 Type *OpTy = Op->getType();
1290 if (Op->hasUseList() &&
1291 (!Ty || AskTy || isUntypedPointerTy(Ty) || isTodoType(Op))) {
1292 Type *PrevElemTy = GR->findDeducedElementType(Op);
1293 GR->addDeducedElementType(Op, normalizeType(KnownElemTy));
1294 // check if KnownElemTy is complete
1295 if (!Incomplete)
1296 eraseTodoType(Op);
1297 else if (!IsPostprocessing)
1298 insertTodoType(Op);
1299 // check if there is existing Intrinsic::spv_assign_ptr_type instruction
1300 CallInst *AssignCI = AskCI ? AskCI : GR->findAssignPtrTypeInstr(Op);
1301 if (AssignCI == nullptr) {
1302 Instruction *User = dyn_cast<Instruction>(Op->use_begin()->get());
1303 setInsertPointSkippingPhis(B, User ? User->getNextNode() : I);
1304 CallInst *CI =
1305 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,
1306 {B.getInt32(getPointerAddressSpace(OpTy))}, B);
1307 GR->addAssignPtrTypeInstr(Op, CI);
1308 } else {
1309 GR->updateAssignType(AssignCI, Op, OpTyVal);
1311 std::make_pair(I, Op)};
1312 propagateElemTypeRec(Op, KnownElemTy, PrevElemTy, VisitedSubst);
1313 }
1314 } else {
1315 eraseTodoType(Op);
1316 CallInst *PtrCastI =
1317 buildSpvPtrcast(I->getParent()->getParent(), Op, KnownElemTy);
1318 if (OpIt.second == std::numeric_limits<unsigned>::max())
1319 dyn_cast<CallInst>(I)->setCalledOperand(PtrCastI);
1320 else
1321 I->setOperand(OpIt.second, PtrCastI);
1322 }
1323 }
1324 TypeValidated.insert(I);
1325}
1326
1327void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1328 Instruction *New,
1329 IRBuilder<> &B) {
1330 while (!Old->user_empty()) {
1331 auto *U = Old->user_back();
1332 if (isAssignTypeInstr(U)) {
1333 B.SetInsertPoint(U);
1334 SmallVector<Value *, 2> Args = {New, U->getOperand(1)};
1335 CallInst *AssignCI =
1336 B.CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);
1337 GR->addAssignPtrTypeInstr(New, AssignCI);
1338 U->eraseFromParent();
1339 } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||
1340 isa<CallInst>(U)) {
1341 U->replaceUsesOfWith(Old, New);
1342 } else {
1343 llvm_unreachable("illegal aggregate intrinsic user");
1344 }
1345 }
1346 New->copyMetadata(*Old);
1347 Old->eraseFromParent();
1348}
1349
1350void SPIRVEmitIntrinsics::preprocessUndefs(IRBuilder<> &B) {
1351 std::queue<Instruction *> Worklist;
1352 for (auto &I : instructions(CurrF))
1353 Worklist.push(&I);
1354
1355 while (!Worklist.empty()) {
1356 Instruction *I = Worklist.front();
1357 bool BPrepared = false;
1358 Worklist.pop();
1359
1360 for (auto &Op : I->operands()) {
1361 auto *AggrUndef = dyn_cast<UndefValue>(Op);
1362 if (!AggrUndef || !Op->getType()->isAggregateType())
1363 continue;
1364
1365 if (!BPrepared) {
1367 BPrepared = true;
1368 }
1369 auto *IntrUndef = B.CreateIntrinsic(Intrinsic::spv_undef, {});
1370 Worklist.push(IntrUndef);
1371 I->replaceUsesOfWith(Op, IntrUndef);
1372 AggrConsts[IntrUndef] = AggrUndef;
1373 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1374 }
1375 }
1376}
1377
1378void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
1379 std::queue<Instruction *> Worklist;
1380 for (auto &I : instructions(CurrF))
1381 Worklist.push(&I);
1382
1383 while (!Worklist.empty()) {
1384 auto *I = Worklist.front();
1385 bool IsPhi = isa<PHINode>(I), BPrepared = false;
1386 assert(I);
1387 bool KeepInst = false;
1388 for (const auto &Op : I->operands()) {
1389 Constant *AggrConst = nullptr;
1390 Type *ResTy = nullptr;
1391 if (auto *COp = dyn_cast<ConstantVector>(Op)) {
1392 AggrConst = cast<Constant>(COp);
1393 ResTy = COp->getType();
1394 } else if (auto *COp = dyn_cast<ConstantArray>(Op)) {
1395 AggrConst = cast<Constant>(COp);
1396 ResTy = B.getInt32Ty();
1397 } else if (auto *COp = dyn_cast<ConstantStruct>(Op)) {
1398 AggrConst = cast<Constant>(COp);
1399 ResTy = B.getInt32Ty();
1400 } else if (auto *COp = dyn_cast<ConstantDataArray>(Op)) {
1401 AggrConst = cast<Constant>(COp);
1402 ResTy = B.getInt32Ty();
1403 } else if (auto *COp = dyn_cast<ConstantAggregateZero>(Op)) {
1404 AggrConst = cast<Constant>(COp);
1405 ResTy = Op->getType()->isVectorTy() ? COp->getType() : B.getInt32Ty();
1406 }
1407 if (AggrConst) {
1409 if (auto *COp = dyn_cast<ConstantDataSequential>(Op))
1410 for (unsigned i = 0; i < COp->getNumElements(); ++i)
1411 Args.push_back(COp->getElementAsConstant(i));
1412 else
1413 llvm::append_range(Args, AggrConst->operands());
1414 if (!BPrepared) {
1415 IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
1416 : B.SetInsertPoint(I);
1417 BPrepared = true;
1418 }
1419 auto *CI =
1420 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {Args});
1421 Worklist.push(CI);
1422 I->replaceUsesOfWith(Op, CI);
1423 KeepInst = true;
1424 AggrConsts[CI] = AggrConst;
1425 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst, false);
1426 }
1427 }
1428 if (!KeepInst)
1429 Worklist.pop();
1430 }
1431}
1432
1434 IRBuilder<> &B) {
1435 LLVMContext &Ctx = I->getContext();
1437 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
1438 {I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, {Node}))});
1439}
1440
1442 unsigned RoundingModeDeco,
1443 IRBuilder<> &B) {
1444 LLVMContext &Ctx = I->getContext();
1445 Type *Int32Ty = Type::getInt32Ty(Ctx);
1446 MDNode *RoundingModeNode = MDNode::get(
1447 Ctx,
1449 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1450 ConstantAsMetadata::get(ConstantInt::get(Int32Ty, RoundingModeDeco))});
1451 createDecorationIntrinsic(I, RoundingModeNode, B);
1452}
1453
1455 IRBuilder<> &B) {
1456 LLVMContext &Ctx = I->getContext();
1457 Type *Int32Ty = Type::getInt32Ty(Ctx);
1458 MDNode *SaturatedConversionNode =
1459 MDNode::get(Ctx, {ConstantAsMetadata::get(ConstantInt::get(
1460 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1461 createDecorationIntrinsic(I, SaturatedConversionNode, B);
1462}
1463
1465 if (auto *CI = dyn_cast<CallInst>(I)) {
1466 if (Function *Fu = CI->getCalledFunction()) {
1467 if (Fu->isIntrinsic()) {
1468 unsigned const int IntrinsicId = Fu->getIntrinsicID();
1469 switch (IntrinsicId) {
1470 case Intrinsic::fptosi_sat:
1471 case Intrinsic::fptoui_sat:
1473 break;
1474 default:
1475 break;
1476 }
1477 }
1478 }
1479 }
1480}
1481
1482Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
1483 if (!Call.isInlineAsm())
1484 return &Call;
1485
1486 const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
1487 LLVMContext &Ctx = CurrF->getContext();
1488
1489 Constant *TyC = UndefValue::get(IA->getFunctionType());
1490 MDString *ConstraintString = MDString::get(Ctx, IA->getConstraintString());
1492 buildMD(TyC),
1493 MetadataAsValue::get(Ctx, MDNode::get(Ctx, ConstraintString))};
1494 for (unsigned OpIdx = 0; OpIdx < Call.arg_size(); OpIdx++)
1495 Args.push_back(Call.getArgOperand(OpIdx));
1496
1497 IRBuilder<> B(Call.getParent());
1498 B.SetInsertPoint(&Call);
1499 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {Args});
1500 return &Call;
1501}
1502
1503// Use a tip about rounding mode to create a decoration.
1504void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1505 IRBuilder<> &B) {
1506 std::optional<RoundingMode> RM = FPI->getRoundingMode();
1507 if (!RM.has_value())
1508 return;
1509 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1510 switch (RM.value()) {
1511 default:
1512 // ignore unknown rounding modes
1513 break;
1514 case RoundingMode::NearestTiesToEven:
1515 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1516 break;
1517 case RoundingMode::TowardNegative:
1518 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1519 break;
1520 case RoundingMode::TowardPositive:
1521 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1522 break;
1523 case RoundingMode::TowardZero:
1524 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1525 break;
1526 case RoundingMode::Dynamic:
1527 case RoundingMode::NearestTiesToAway:
1528 // TODO: check if supported
1529 break;
1530 }
1531 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1532 return;
1533 // Convert the tip about rounding mode into a decoration record.
1534 createRoundingModeDecoration(FPI, RoundingModeDeco, B);
1535}
1536
1537Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
1538 BasicBlock *ParentBB = I.getParent();
1539 IRBuilder<> B(ParentBB);
1540 B.SetInsertPoint(&I);
1543 for (auto &Op : I.operands()) {
1544 if (Op.get()->getType()->isSized()) {
1545 Args.push_back(Op);
1546 } else if (BasicBlock *BB = dyn_cast<BasicBlock>(Op.get())) {
1547 BBCases.push_back(BB);
1548 Args.push_back(BlockAddress::get(BB->getParent(), BB));
1549 } else {
1550 report_fatal_error("Unexpected switch operand");
1551 }
1552 }
1553 CallInst *NewI = B.CreateIntrinsic(Intrinsic::spv_switch,
1554 {I.getOperand(0)->getType()}, {Args});
1555 // remove switch to avoid its unneeded and undesirable unwrap into branches
1556 // and conditions
1557 replaceAllUsesWith(&I, NewI);
1558 I.eraseFromParent();
1559 // insert artificial and temporary instruction to preserve valid CFG,
1560 // it will be removed after IR translation pass
1561 B.SetInsertPoint(ParentBB);
1562 IndirectBrInst *BrI = B.CreateIndirectBr(
1563 Constant::getNullValue(PointerType::getUnqual(ParentBB->getContext())),
1564 BBCases.size());
1565 for (BasicBlock *BBCase : BBCases)
1566 BrI->addDestination(BBCase);
1567 return BrI;
1568}
1569
1570Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
1571 if (I.getSourceElementType() == IntegerType::getInt8Ty(CurrF->getContext()) &&
1572 TM->getSubtargetImpl()->isLogicalSPIRV()) {
1573 Instruction *Result = buildLogicalAccessChainFromGEP(I);
1574 if (Result)
1575 return Result;
1576 }
1577
1578 IRBuilder<> B(I.getParent());
1579 B.SetInsertPoint(&I);
1580 SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
1582 Args.push_back(B.getInt1(I.isInBounds()));
1583 llvm::append_range(Args, I.operands());
1584 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
1585 replaceAllUsesWithAndErase(B, &I, NewI);
1586 return NewI;
1587}
1588
1589Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
1590 IRBuilder<> B(I.getParent());
1591 B.SetInsertPoint(&I);
1592 Value *Source = I.getOperand(0);
1593
1594 // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of
1595 // varying element types. In case of IR coming from older versions of LLVM
1596 // such bitcasts do not provide sufficient information, should be just skipped
1597 // here, and handled in insertPtrCastOrAssignTypeInstr.
1598 if (isPointerTy(I.getType())) {
1599 replaceAllUsesWith(&I, Source);
1600 I.eraseFromParent();
1601 return nullptr;
1602 }
1603
1604 SmallVector<Type *, 2> Types = {I.getType(), Source->getType()};
1605 SmallVector<Value *> Args(I.op_begin(), I.op_end());
1606 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});
1607 replaceAllUsesWithAndErase(B, &I, NewI);
1608 return NewI;
1609}
1610
1611void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
1612 TargetExtType *AssignedType, Value *V, IRBuilder<> &B) {
1613 Type *VTy = V->getType();
1614
1615 // A couple of sanity checks.
1616 assert((isPointerTy(VTy)) && "Expect a pointer type!");
1617 if (Type *ElemTy = getPointeeType(VTy))
1618 if (ElemTy != AssignedType)
1619 report_fatal_error("Unexpected pointer element type!");
1620
1621 CallInst *AssignCI = GR->findAssignPtrTypeInstr(V);
1622 if (!AssignCI) {
1623 GR->buildAssignType(B, AssignedType, V);
1624 return;
1625 }
1626
1627 Type *CurrentType =
1628 dyn_cast<ConstantAsMetadata>(
1629 cast<MetadataAsValue>(AssignCI->getOperand(1))->getMetadata())
1630 ->getType();
1631 if (CurrentType == AssignedType)
1632 return;
1633
1634 // Builtin types cannot be redeclared or casted.
1635 if (CurrentType->isTargetExtTy())
1636 report_fatal_error("Type mismatch " + CurrentType->getTargetExtName() +
1637 "/" + AssignedType->getTargetExtName() +
1638 " for value " + V->getName(),
1639 false);
1640
1641 // Our previous guess about the type seems to be wrong, let's update
1642 // inferred type according to a new, more precise type information.
1643 GR->updateAssignType(AssignCI, V, getNormalizedPoisonValue(AssignedType));
1644}
1645
1646void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
1647 Instruction *I, Value *Pointer, Type *ExpectedElementType,
1648 unsigned OperandToReplace, IRBuilder<> &B) {
1649 TypeValidated.insert(I);
1650
1651 // Do not emit spv_ptrcast if Pointer's element type is ExpectedElementType
1652 Type *PointerElemTy = deduceElementTypeHelper(Pointer, false);
1653 if (PointerElemTy == ExpectedElementType ||
1654 isEquivalentTypes(PointerElemTy, ExpectedElementType))
1655 return;
1656
1658 Value *ExpectedElementVal = getNormalizedPoisonValue(ExpectedElementType);
1659 MetadataAsValue *VMD = buildMD(ExpectedElementVal);
1660 unsigned AddressSpace = getPointerAddressSpace(Pointer->getType());
1661 bool FirstPtrCastOrAssignPtrType = true;
1662
1663 // Do not emit new spv_ptrcast if equivalent one already exists or when
1664 // spv_assign_ptr_type already targets this pointer with the same element
1665 // type.
1666 if (Pointer->hasUseList()) {
1667 for (auto User : Pointer->users()) {
1668 auto *II = dyn_cast<IntrinsicInst>(User);
1669 if (!II ||
1670 (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
1671 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
1672 II->getOperand(0) != Pointer)
1673 continue;
1674
1675 // There is some spv_ptrcast/spv_assign_ptr_type already targeting this
1676 // pointer.
1677 FirstPtrCastOrAssignPtrType = false;
1678 if (II->getOperand(1) != VMD ||
1679 dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=
1681 continue;
1682
1683 // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the
1684 // same element type and address space.
1685 if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)
1686 return;
1687
1688 // This must be a spv_ptrcast, do not emit new if this one has the same BB
1689 // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.
1690 if (II->getParent() != I->getParent())
1691 continue;
1692
1693 I->setOperand(OperandToReplace, II);
1694 return;
1695 }
1696 }
1697
1698 if (isa<Instruction>(Pointer) || isa<Argument>(Pointer)) {
1699 if (FirstPtrCastOrAssignPtrType) {
1700 // If this would be the first spv_ptrcast, do not emit spv_ptrcast and
1701 // emit spv_assign_ptr_type instead.
1702 GR->buildAssignPtr(B, ExpectedElementType, Pointer);
1703 return;
1704 } else if (isTodoType(Pointer)) {
1705 eraseTodoType(Pointer);
1706 if (!isa<CallInst>(Pointer) && !isa<GetElementPtrInst>(Pointer)) {
1707 // If this wouldn't be the first spv_ptrcast but existing type info is
1708 // uncomplete, update spv_assign_ptr_type arguments.
1709 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Pointer)) {
1710 Type *PrevElemTy = GR->findDeducedElementType(Pointer);
1711 assert(PrevElemTy);
1713 std::make_pair(I, Pointer)};
1714 GR->updateAssignType(AssignCI, Pointer, ExpectedElementVal);
1715 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
1716 } else {
1717 GR->buildAssignPtr(B, ExpectedElementType, Pointer);
1718 }
1719 return;
1720 }
1721 }
1722 }
1723
1724 // Emit spv_ptrcast
1725 SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};
1727 auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
1728 I->setOperand(OperandToReplace, PtrCastI);
1729 // We need to set up a pointee type for the newly created spv_ptrcast.
1730 GR->buildAssignPtr(B, ExpectedElementType, PtrCastI);
1731}
1732
1733void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
1734 IRBuilder<> &B) {
1735 // Handle basic instructions:
1736 StoreInst *SI = dyn_cast<StoreInst>(I);
1737 if (IsKernelArgInt8(CurrF, SI)) {
1738 replacePointerOperandWithPtrCast(
1739 I, SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->getContext()),
1740 0, B);
1741 }
1742 if (SI) {
1743 Value *Op = SI->getValueOperand();
1744 Value *Pointer = SI->getPointerOperand();
1745 Type *OpTy = Op->getType();
1746 if (auto *OpI = dyn_cast<Instruction>(Op))
1747 OpTy = restoreMutatedType(GR, OpI, OpTy);
1748 if (OpTy == Op->getType())
1749 OpTy = deduceElementTypeByValueDeep(OpTy, Op, false);
1750 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 1, B);
1751 return;
1752 }
1753 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
1754 Value *Pointer = LI->getPointerOperand();
1755 Type *OpTy = LI->getType();
1756 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
1757 if (Type *ElemTy = GR->findDeducedElementType(LI)) {
1758 OpTy = getTypedPointerWrapper(ElemTy, PtrTy->getAddressSpace());
1759 } else {
1760 Type *NewOpTy = OpTy;
1761 OpTy = deduceElementTypeByValueDeep(OpTy, LI, false);
1762 if (OpTy == NewOpTy)
1763 insertTodoType(Pointer);
1764 }
1765 }
1766 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 0, B);
1767 return;
1768 }
1769 if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
1770 Value *Pointer = GEPI->getPointerOperand();
1771 Type *OpTy = nullptr;
1772
1773 // Knowing the accessed type is mandatory for logical SPIR-V. Sadly,
1774 // the GEP source element type should not be used for this purpose, and
1775 // the alternative type-scavenging method is not working.
1776 // Physical SPIR-V can work around this, but not logical, hence still
1777 // try to rely on the broken type scavenging for logical.
1778 bool IsRewrittenGEP =
1779 GEPI->getSourceElementType() == IntegerType::getInt8Ty(I->getContext());
1780 if (IsRewrittenGEP && TM->getSubtargetImpl()->isLogicalSPIRV()) {
1781 Value *Src = getPointerRoot(Pointer);
1782 OpTy = GR->findDeducedElementType(Src);
1783 }
1784
1785 // In all cases, fall back to the GEP type if type scavenging failed.
1786 if (!OpTy)
1787 OpTy = GEPI->getSourceElementType();
1788
1789 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 0, B);
1790 if (isNestedPointer(OpTy))
1791 insertTodoType(Pointer);
1792 return;
1793 }
1794
1795 // TODO: review and merge with existing logics:
1796 // Handle calls to builtins (non-intrinsics):
1797 CallInst *CI = dyn_cast<CallInst>(I);
1798 if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||
1800 return;
1801
1802 // collect information about formal parameter types
1803 std::string DemangledName =
1805 Function *CalledF = CI->getCalledFunction();
1806 SmallVector<Type *, 4> CalledArgTys;
1807 bool HaveTypes = false;
1808 for (unsigned OpIdx = 0; OpIdx < CalledF->arg_size(); ++OpIdx) {
1809 Argument *CalledArg = CalledF->getArg(OpIdx);
1810 Type *ArgType = CalledArg->getType();
1811 if (!isPointerTy(ArgType)) {
1812 CalledArgTys.push_back(nullptr);
1813 } else if (Type *ArgTypeElem = getPointeeType(ArgType)) {
1814 CalledArgTys.push_back(ArgTypeElem);
1815 HaveTypes = true;
1816 } else {
1817 Type *ElemTy = GR->findDeducedElementType(CalledArg);
1818 if (!ElemTy && hasPointeeTypeAttr(CalledArg))
1819 ElemTy = getPointeeTypeByAttr(CalledArg);
1820 if (!ElemTy) {
1821 ElemTy = getPointeeTypeByCallInst(DemangledName, CalledF, OpIdx);
1822 if (ElemTy) {
1823 GR->addDeducedElementType(CalledArg, normalizeType(ElemTy));
1824 } else {
1825 for (User *U : CalledArg->users()) {
1826 if (Instruction *Inst = dyn_cast<Instruction>(U)) {
1827 if ((ElemTy = deduceElementTypeHelper(Inst, false)) != nullptr)
1828 break;
1829 }
1830 }
1831 }
1832 }
1833 HaveTypes |= ElemTy != nullptr;
1834 CalledArgTys.push_back(ElemTy);
1835 }
1836 }
1837
1838 if (DemangledName.empty() && !HaveTypes)
1839 return;
1840
1841 for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) {
1842 Value *ArgOperand = CI->getArgOperand(OpIdx);
1843 if (!isPointerTy(ArgOperand->getType()))
1844 continue;
1845
1846 // Constants (nulls/undefs) are handled in insertAssignPtrTypeIntrs()
1847 if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand)) {
1848 // However, we may have assumptions about the formal argument's type and
1849 // may have a need to insert a ptr cast for the actual parameter of this
1850 // call.
1851 Argument *CalledArg = CalledF->getArg(OpIdx);
1852 if (!GR->findDeducedElementType(CalledArg))
1853 continue;
1854 }
1855
1856 Type *ExpectedType =
1857 OpIdx < CalledArgTys.size() ? CalledArgTys[OpIdx] : nullptr;
1858 if (!ExpectedType && !DemangledName.empty())
1860 DemangledName, OpIdx, I->getContext());
1861 if (!ExpectedType || ExpectedType->isVoidTy())
1862 continue;
1863
1864 if (ExpectedType->isTargetExtTy() &&
1865 !isTypedPointerWrapper(cast<TargetExtType>(ExpectedType)))
1866 insertAssignPtrTypeTargetExt(cast<TargetExtType>(ExpectedType),
1867 ArgOperand, B);
1868 else
1869 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx, B);
1870 }
1871}
1872
1873Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {
1874 // If it's a <1 x Type> vector type, don't modify it. It's not a legal vector
1875 // type in LLT and IRTranslator will replace it by the scalar.
1876 if (isVector1(I.getType()))
1877 return &I;
1878
1879 SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),
1880 I.getOperand(1)->getType(),
1881 I.getOperand(2)->getType()};
1882 IRBuilder<> B(I.getParent());
1883 B.SetInsertPoint(&I);
1884 SmallVector<Value *> Args(I.op_begin(), I.op_end());
1885 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
1886 replaceAllUsesWithAndErase(B, &I, NewI);
1887 return NewI;
1888}
1889
1891SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {
1892 // If it's a <1 x Type> vector type, don't modify it. It's not a legal vector
1893 // type in LLT and IRTranslator will replace it by the scalar.
1894 if (isVector1(I.getVectorOperandType()))
1895 return &I;
1896
1897 IRBuilder<> B(I.getParent());
1898 B.SetInsertPoint(&I);
1899 SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(),
1900 I.getIndexOperand()->getType()};
1901 SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};
1902 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});
1903 replaceAllUsesWithAndErase(B, &I, NewI);
1904 return NewI;
1905}
1906
1907Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {
1908 IRBuilder<> B(I.getParent());
1909 B.SetInsertPoint(&I);
1910 SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()};
1912 for (auto &Op : I.operands())
1913 if (isa<UndefValue>(Op))
1914 Args.push_back(UndefValue::get(B.getInt32Ty()));
1915 else
1916 Args.push_back(Op);
1917 for (auto &Op : I.indices())
1918 Args.push_back(B.getInt32(Op));
1919 Instruction *NewI =
1920 B.CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args});
1921 replaceMemInstrUses(&I, NewI, B);
1922 return NewI;
1923}
1924
1925Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
1926 if (I.getAggregateOperand()->getType()->isAggregateType())
1927 return &I;
1928 IRBuilder<> B(I.getParent());
1929 B.SetInsertPoint(&I);
1930 SmallVector<Value *> Args(I.operands());
1931 for (auto &Op : I.indices())
1932 Args.push_back(B.getInt32(Op));
1933 auto *NewI =
1934 B.CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});
1935 replaceAllUsesWithAndErase(B, &I, NewI);
1936 return NewI;
1937}
1938
1939Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) {
1940 if (!I.getType()->isAggregateType())
1941 return &I;
1942 IRBuilder<> B(I.getParent());
1943 B.SetInsertPoint(&I);
1944 TrackConstants = false;
1945 const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
1947 TLI->getLoadMemOperandFlags(I, CurrF->getDataLayout());
1948 auto *NewI =
1949 B.CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()},
1950 {I.getPointerOperand(), B.getInt16(Flags),
1951 B.getInt8(I.getAlign().value())});
1952 replaceMemInstrUses(&I, NewI, B);
1953 return NewI;
1954}
1955
1956Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {
1957 if (!AggrStores.contains(&I))
1958 return &I;
1959 IRBuilder<> B(I.getParent());
1960 B.SetInsertPoint(&I);
1961 TrackConstants = false;
1962 const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
1964 TLI->getStoreMemOperandFlags(I, CurrF->getDataLayout());
1965 auto *PtrOp = I.getPointerOperand();
1966 auto *NewI = B.CreateIntrinsic(
1967 Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()},
1968 {I.getValueOperand(), PtrOp, B.getInt16(Flags),
1969 B.getInt8(I.getAlign().value())});
1970 NewI->copyMetadata(I);
1971 I.eraseFromParent();
1972 return NewI;
1973}
1974
1975Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {
1976 Value *ArraySize = nullptr;
1977 if (I.isArrayAllocation()) {
1978 const SPIRVSubtarget *STI = TM->getSubtargetImpl(*I.getFunction());
1979 if (!STI->canUseExtension(
1980 SPIRV::Extension::SPV_INTEL_variable_length_array))
1982 "array allocation: this instruction requires the following "
1983 "SPIR-V extension: SPV_INTEL_variable_length_array",
1984 false);
1985 ArraySize = I.getArraySize();
1986 }
1987 IRBuilder<> B(I.getParent());
1988 B.SetInsertPoint(&I);
1989 TrackConstants = false;
1990 Type *PtrTy = I.getType();
1991 auto *NewI =
1992 ArraySize
1993 ? B.CreateIntrinsic(Intrinsic::spv_alloca_array,
1994 {PtrTy, ArraySize->getType()},
1995 {ArraySize, B.getInt8(I.getAlign().value())})
1996 : B.CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy},
1997 {B.getInt8(I.getAlign().value())});
1998 replaceAllUsesWithAndErase(B, &I, NewI);
1999 return NewI;
2000}
2001
2002Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
2003 assert(I.getType()->isAggregateType() && "Aggregate result is expected");
2004 IRBuilder<> B(I.getParent());
2005 B.SetInsertPoint(&I);
2006 SmallVector<Value *> Args(I.operands());
2007 Args.push_back(B.getInt32(
2008 static_cast<uint32_t>(getMemScope(I.getContext(), I.getSyncScopeID()))));
2009 Args.push_back(B.getInt32(
2010 static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering()))));
2011 Args.push_back(B.getInt32(
2012 static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering()))));
2013 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
2014 {I.getPointerOperand()->getType()}, {Args});
2015 replaceMemInstrUses(&I, NewI, B);
2016 return NewI;
2017}
2018
2019Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) {
2020 IRBuilder<> B(I.getParent());
2021 B.SetInsertPoint(&I);
2022 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2023 return &I;
2024}
2025
2026void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2027 IRBuilder<> &B) {
2028 // Skip special artifical variable llvm.global.annotations.
2029 if (GV.getName() == "llvm.global.annotations")
2030 return;
2031 Constant *Init = nullptr;
2032 if (hasInitializer(&GV)) {
2033 // Deduce element type and store results in Global Registry.
2034 // Result is ignored, because TypedPointerType is not supported
2035 // by llvm IR general logic.
2036 deduceElementTypeHelper(&GV, false);
2037 Init = GV.getInitializer();
2038 Type *Ty = isAggrConstForceInt32(Init) ? B.getInt32Ty() : Init->getType();
2039 Constant *Const = isAggrConstForceInt32(Init) ? B.getInt32(1) : Init;
2040 auto *InitInst = B.CreateIntrinsic(Intrinsic::spv_init_global,
2041 {GV.getType(), Ty}, {&GV, Const});
2042 InitInst->setArgOperand(1, Init);
2043 }
2044 if (!Init && GV.use_empty())
2045 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);
2046}
2047
2048// Return true, if we can't decide what is the pointee type now and will get
2049// back to the question later. Return false is spv_assign_ptr_type is not needed
2050// or can be inserted immediately.
2051bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
2052 IRBuilder<> &B,
2053 bool UnknownElemTypeI8) {
2055 if (!isPointerTy(I->getType()) || !requireAssignType(I))
2056 return false;
2057
2059 if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {
2060 GR->buildAssignPtr(B, ElemTy, I);
2061 return false;
2062 }
2063 return true;
2064}
2065
2066void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
2067 IRBuilder<> &B) {
2068 // TODO: extend the list of functions with known result types
2069 static StringMap<unsigned> ResTypeWellKnown = {
2070 {"async_work_group_copy", WellKnownTypes::Event},
2071 {"async_work_group_strided_copy", WellKnownTypes::Event},
2072 {"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2073
2075
2076 bool IsKnown = false;
2077 if (auto *CI = dyn_cast<CallInst>(I)) {
2078 if (!CI->isIndirectCall() && !CI->isInlineAsm() &&
2079 CI->getCalledFunction() && !CI->getCalledFunction()->isIntrinsic()) {
2080 Function *CalledF = CI->getCalledFunction();
2081 std::string DemangledName =
2083 FPDecorationId DecorationId = FPDecorationId::NONE;
2084 if (DemangledName.length() > 0)
2085 DemangledName =
2086 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2087 auto ResIt = ResTypeWellKnown.find(DemangledName);
2088 if (ResIt != ResTypeWellKnown.end()) {
2089 IsKnown = true;
2091 switch (ResIt->second) {
2092 case WellKnownTypes::Event:
2093 GR->buildAssignType(
2094 B, TargetExtType::get(I->getContext(), "spirv.Event"), I);
2095 break;
2096 }
2097 }
2098 // check if a floating rounding mode or saturation info is present
2099 switch (DecorationId) {
2100 default:
2101 break;
2102 case FPDecorationId::SAT:
2104 break;
2105 case FPDecorationId::RTE:
2107 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE, B);
2108 break;
2109 case FPDecorationId::RTZ:
2111 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ, B);
2112 break;
2113 case FPDecorationId::RTP:
2115 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP, B);
2116 break;
2117 case FPDecorationId::RTN:
2119 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN, B);
2120 break;
2121 }
2122 }
2123 }
2124
2125 Type *Ty = I->getType();
2126 if (!IsKnown && !Ty->isVoidTy() && !isPointerTy(Ty) && requireAssignType(I)) {
2128 Type *TypeToAssign = Ty;
2129 if (auto *II = dyn_cast<IntrinsicInst>(I)) {
2130 if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
2131 II->getIntrinsicID() == Intrinsic::spv_undef) {
2132 auto It = AggrConstTypes.find(II);
2133 if (It == AggrConstTypes.end())
2134 report_fatal_error("Unknown composite intrinsic type");
2135 TypeToAssign = It->second;
2136 }
2137 }
2138 TypeToAssign = restoreMutatedType(GR, I, TypeToAssign);
2139 GR->buildAssignType(B, TypeToAssign, I);
2140 }
2141 for (const auto &Op : I->operands()) {
2142 if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
2143 // Check GetElementPtrConstantExpr case.
2144 (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) {
2146 Type *OpTy = Op->getType();
2147 if (isa<UndefValue>(Op) && OpTy->isAggregateType()) {
2148 CallInst *AssignCI =
2149 buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,
2150 UndefValue::get(B.getInt32Ty()), {}, B);
2151 GR->addAssignPtrTypeInstr(Op, AssignCI);
2152 } else if (!isa<Instruction>(Op)) {
2153 Type *OpTy = Op->getType();
2154 Type *OpTyElem = getPointeeType(OpTy);
2155 if (OpTyElem) {
2156 GR->buildAssignPtr(B, OpTyElem, Op);
2157 } else if (isPointerTy(OpTy)) {
2158 Type *ElemTy = GR->findDeducedElementType(Op);
2159 GR->buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true),
2160 Op);
2161 } else {
2162 Value *OpTyVal = Op;
2163 if (OpTy->isTargetExtTy()) {
2164 // We need to do this in order to be consistent with how target ext
2165 // types are handled in `processInstrAfterVisit`
2166 OpTyVal = getNormalizedPoisonValue(OpTy);
2167 }
2168 CallInst *AssignCI =
2169 buildIntrWithMD(Intrinsic::spv_assign_type, {OpTy},
2170 getNormalizedPoisonValue(OpTy), OpTyVal, {}, B);
2171 GR->addAssignPtrTypeInstr(OpTyVal, AssignCI);
2172 }
2173 }
2174 }
2175 }
2176}
2177
2178bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2179 Instruction *Inst) {
2180 const SPIRVSubtarget *STI = TM->getSubtargetImpl(*Inst->getFunction());
2181 if (!STI->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2182 return false;
2183 // Add aliasing decorations to internal load and store intrinsics
2184 // and atomic instructions, skipping atomic store as it won't have ID to
2185 // attach the decoration.
2186 CallInst *CI = dyn_cast<CallInst>(Inst);
2187 if (!CI)
2188 return false;
2189 if (Function *Fun = CI->getCalledFunction()) {
2190 if (Fun->isIntrinsic()) {
2191 switch (Fun->getIntrinsicID()) {
2192 case Intrinsic::spv_load:
2193 case Intrinsic::spv_store:
2194 return true;
2195 default:
2196 return false;
2197 }
2198 }
2200 const std::string Prefix = "__spirv_Atomic";
2201 const bool IsAtomic = Name.find(Prefix) == 0;
2202
2203 if (!Fun->getReturnType()->isVoidTy() && IsAtomic)
2204 return true;
2205 }
2206 return false;
2207}
2208
2209void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
2210 IRBuilder<> &B) {
2211 if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
2213 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
2214 {I, MetadataAsValue::get(I->getContext(), MD)});
2215 }
2216 // Lower alias.scope/noalias metadata
2217 {
2218 auto processMemAliasingDecoration = [&](unsigned Kind) {
2219 if (MDNode *AliasListMD = I->getMetadata(Kind)) {
2220 if (shouldTryToAddMemAliasingDecoration(I)) {
2221 uint32_t Dec = Kind == LLVMContext::MD_alias_scope
2222 ? SPIRV::Decoration::AliasScopeINTEL
2223 : SPIRV::Decoration::NoAliasINTEL;
2225 I, ConstantInt::get(B.getInt32Ty(), Dec),
2226 MetadataAsValue::get(I->getContext(), AliasListMD)};
2228 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2229 {I->getType()}, {Args});
2230 }
2231 }
2232 };
2233 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2234 processMemAliasingDecoration(LLVMContext::MD_noalias);
2235 }
2236 // MD_fpmath
2237 if (MDNode *MD = I->getMetadata(LLVMContext::MD_fpmath)) {
2238 const SPIRVSubtarget *STI = TM->getSubtargetImpl(*I->getFunction());
2239 bool AllowFPMaxError =
2240 STI->canUseExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
2241 if (!AllowFPMaxError)
2242 return;
2243
2245 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2246 {I->getType()},
2247 {I, MetadataAsValue::get(I->getContext(), MD)});
2248 }
2249}
2250
2251void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
2252 IRBuilder<> &B) {
2253 auto *II = dyn_cast<IntrinsicInst>(I);
2254 bool IsConstComposite =
2255 II && II->getIntrinsicID() == Intrinsic::spv_const_composite;
2256 if (IsConstComposite && TrackConstants) {
2258 auto t = AggrConsts.find(I);
2259 assert(t != AggrConsts.end());
2260 auto *NewOp =
2261 buildIntrWithMD(Intrinsic::spv_track_constant,
2262 {II->getType(), II->getType()}, t->second, I, {}, B);
2263 replaceAllUsesWith(I, NewOp, false);
2264 NewOp->setArgOperand(0, I);
2265 }
2266 bool IsPhi = isa<PHINode>(I), BPrepared = false;
2267 for (const auto &Op : I->operands()) {
2268 if (isa<PHINode>(I) || isa<SwitchInst>(I) ||
2269 !(isa<ConstantData>(Op) || isa<ConstantExpr>(Op)))
2270 continue;
2271 unsigned OpNo = Op.getOperandNo();
2272 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
2273 (II->paramHasAttr(OpNo, Attribute::ImmArg))))
2274 continue;
2275
2276 if (!BPrepared) {
2277 IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
2278 : B.SetInsertPoint(I);
2279 BPrepared = true;
2280 }
2281 Type *OpTy = Op->getType();
2282 Type *OpElemTy = GR->findDeducedElementType(Op);
2283 Value *NewOp = Op;
2284 if (OpTy->isTargetExtTy()) {
2285 // Since this value is replaced by poison, we need to do the same in
2286 // `insertAssignTypeIntrs`.
2287 Value *OpTyVal = getNormalizedPoisonValue(OpTy);
2288 NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
2289 {OpTy, OpTyVal->getType()}, Op, OpTyVal, {}, B);
2290 }
2291 if (!IsConstComposite && isPointerTy(OpTy) && OpElemTy != nullptr &&
2292 OpElemTy != IntegerType::getInt8Ty(I->getContext())) {
2293 SmallVector<Type *, 2> Types = {OpTy, OpTy};
2295 NewOp, buildMD(getNormalizedPoisonValue(OpElemTy)),
2296 B.getInt32(getPointerAddressSpace(OpTy))};
2297 CallInst *PtrCasted =
2298 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
2299 GR->buildAssignPtr(B, OpElemTy, PtrCasted);
2300 NewOp = PtrCasted;
2301 }
2302 if (NewOp != Op)
2303 I->setOperand(OpNo, NewOp);
2304 }
2305 if (Named.insert(I).second)
2306 emitAssignName(I, B);
2307}
2308
2309Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F,
2310 unsigned OpIdx) {
2311 std::unordered_set<Function *> FVisited;
2312 return deduceFunParamElementType(F, OpIdx, FVisited);
2313}
2314
2315Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
2316 Function *F, unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
2317 // maybe a cycle
2318 if (!FVisited.insert(F).second)
2319 return nullptr;
2320
2321 std::unordered_set<Value *> Visited;
2323 // search in function's call sites
2324 for (User *U : F->users()) {
2325 CallInst *CI = dyn_cast<CallInst>(U);
2326 if (!CI || OpIdx >= CI->arg_size())
2327 continue;
2328 Value *OpArg = CI->getArgOperand(OpIdx);
2329 if (!isPointerTy(OpArg->getType()))
2330 continue;
2331 // maybe we already know operand's element type
2332 if (Type *KnownTy = GR->findDeducedElementType(OpArg))
2333 return KnownTy;
2334 // try to deduce from the operand itself
2335 Visited.clear();
2336 if (Type *Ty = deduceElementTypeHelper(OpArg, Visited, false))
2337 return Ty;
2338 // search in actual parameter's users
2339 for (User *OpU : OpArg->users()) {
2340 Instruction *Inst = dyn_cast<Instruction>(OpU);
2341 if (!Inst || Inst == CI)
2342 continue;
2343 Visited.clear();
2344 if (Type *Ty = deduceElementTypeHelper(Inst, Visited, false))
2345 return Ty;
2346 }
2347 // check if it's a formal parameter of the outer function
2348 if (!CI->getParent() || !CI->getParent()->getParent())
2349 continue;
2350 Function *OuterF = CI->getParent()->getParent();
2351 if (FVisited.find(OuterF) != FVisited.end())
2352 continue;
2353 for (unsigned i = 0; i < OuterF->arg_size(); ++i) {
2354 if (OuterF->getArg(i) == OpArg) {
2355 Lookup.push_back(std::make_pair(OuterF, i));
2356 break;
2357 }
2358 }
2359 }
2360
2361 // search in function parameters
2362 for (auto &Pair : Lookup) {
2363 if (Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
2364 return Ty;
2365 }
2366
2367 return nullptr;
2368}
2369
2370void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
2371 IRBuilder<> &B) {
2372 B.SetInsertPointPastAllocas(F);
2373 for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
2374 Argument *Arg = F->getArg(OpIdx);
2375 if (!isUntypedPointerTy(Arg->getType()))
2376 continue;
2377 Type *ElemTy = GR->findDeducedElementType(Arg);
2378 if (ElemTy)
2379 continue;
2380 if (hasPointeeTypeAttr(Arg) &&
2381 (ElemTy = getPointeeTypeByAttr(Arg)) != nullptr) {
2382 GR->buildAssignPtr(B, ElemTy, Arg);
2383 continue;
2384 }
2385 // search in function's call sites
2386 for (User *U : F->users()) {
2387 CallInst *CI = dyn_cast<CallInst>(U);
2388 if (!CI || OpIdx >= CI->arg_size())
2389 continue;
2390 Value *OpArg = CI->getArgOperand(OpIdx);
2391 if (!isPointerTy(OpArg->getType()))
2392 continue;
2393 // maybe we already know operand's element type
2394 if ((ElemTy = GR->findDeducedElementType(OpArg)) != nullptr)
2395 break;
2396 }
2397 if (ElemTy) {
2398 GR->buildAssignPtr(B, ElemTy, Arg);
2399 continue;
2400 }
2401 if (HaveFunPtrs) {
2402 for (User *U : Arg->users()) {
2403 CallInst *CI = dyn_cast<CallInst>(U);
2404 if (CI && !isa<IntrinsicInst>(CI) && CI->isIndirectCall() &&
2405 CI->getCalledOperand() == Arg &&
2406 CI->getParent()->getParent() == CurrF) {
2408 deduceOperandElementTypeFunctionPointer(CI, Ops, ElemTy, false);
2409 if (ElemTy) {
2410 GR->buildAssignPtr(B, ElemTy, Arg);
2411 break;
2412 }
2413 }
2414 }
2415 }
2416 }
2417}
2418
2419void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
2420 B.SetInsertPointPastAllocas(F);
2421 for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
2422 Argument *Arg = F->getArg(OpIdx);
2423 if (!isUntypedPointerTy(Arg->getType()))
2424 continue;
2425 Type *ElemTy = GR->findDeducedElementType(Arg);
2426 if (!ElemTy && (ElemTy = deduceFunParamElementType(F, OpIdx)) != nullptr) {
2427 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Arg)) {
2429 GR->updateAssignType(AssignCI, Arg, getNormalizedPoisonValue(ElemTy));
2430 propagateElemType(Arg, IntegerType::getInt8Ty(F->getContext()),
2431 VisitedSubst);
2432 } else {
2433 GR->buildAssignPtr(B, ElemTy, Arg);
2434 }
2435 }
2436 }
2437}
2438
2440 SPIRVGlobalRegistry *GR) {
2441 FunctionType *FTy = F->getFunctionType();
2442 bool IsNewFTy = false;
2444 for (Argument &Arg : F->args()) {
2445 Type *ArgTy = Arg.getType();
2446 if (ArgTy->isPointerTy())
2447 if (Type *ElemTy = GR->findDeducedElementType(&Arg)) {
2448 IsNewFTy = true;
2449 ArgTy = getTypedPointerWrapper(ElemTy, getPointerAddressSpace(ArgTy));
2450 }
2451 ArgTys.push_back(ArgTy);
2452 }
2453 return IsNewFTy
2454 ? FunctionType::get(FTy->getReturnType(), ArgTys, FTy->isVarArg())
2455 : FTy;
2456}
2457
2458bool SPIRVEmitIntrinsics::processFunctionPointers(Module &M) {
2459 SmallVector<Function *> Worklist;
2460 for (auto &F : M) {
2461 if (F.isIntrinsic())
2462 continue;
2463 if (F.isDeclaration()) {
2464 for (User *U : F.users()) {
2465 CallInst *CI = dyn_cast<CallInst>(U);
2466 if (!CI || CI->getCalledFunction() != &F) {
2467 Worklist.push_back(&F);
2468 break;
2469 }
2470 }
2471 } else {
2472 if (F.user_empty())
2473 continue;
2474 Type *FPElemTy = GR->findDeducedElementType(&F);
2475 if (!FPElemTy)
2476 FPElemTy = getFunctionPointerElemType(&F, GR);
2477 for (User *U : F.users()) {
2478 IntrinsicInst *II = dyn_cast<IntrinsicInst>(U);
2479 if (!II || II->arg_size() != 3 || II->getOperand(0) != &F)
2480 continue;
2481 if (II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
2482 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
2483 GR->updateAssignType(II, &F, getNormalizedPoisonValue(FPElemTy));
2484 break;
2485 }
2486 }
2487 }
2488 }
2489 if (Worklist.empty())
2490 return false;
2491
2492 std::string ServiceFunName = SPIRV_BACKEND_SERVICE_FUN_NAME;
2493 if (!getVacantFunctionName(M, ServiceFunName))
2495 "cannot allocate a name for the internal service function");
2496 LLVMContext &Ctx = M.getContext();
2497 Function *SF =
2498 Function::Create(FunctionType::get(Type::getVoidTy(Ctx), {}, false),
2499 GlobalValue::PrivateLinkage, ServiceFunName, M);
2501 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", SF);
2502 IRBuilder<> IRB(BB);
2503
2504 for (Function *F : Worklist) {
2506 for (const auto &Arg : F->args())
2507 Args.push_back(getNormalizedPoisonValue(Arg.getType()));
2508 IRB.CreateCall(F, Args);
2509 }
2510 IRB.CreateRetVoid();
2511
2512 return true;
2513}
2514
2515// Apply types parsed from demangled function declarations.
2516void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) {
2518 for (auto It : FDeclPtrTys) {
2519 Function *F = It.first;
2520 for (auto *U : F->users()) {
2521 CallInst *CI = dyn_cast<CallInst>(U);
2522 if (!CI || CI->getCalledFunction() != F)
2523 continue;
2524 unsigned Sz = CI->arg_size();
2525 for (auto [Idx, ElemTy] : It.second) {
2526 if (Idx >= Sz)
2527 continue;
2528 Value *Param = CI->getArgOperand(Idx);
2529 if (GR->findDeducedElementType(Param) || isa<GlobalValue>(Param))
2530 continue;
2531 if (Argument *Arg = dyn_cast<Argument>(Param)) {
2532 if (!hasPointeeTypeAttr(Arg)) {
2533 B.SetInsertPointPastAllocas(Arg->getParent());
2534 B.SetCurrentDebugLocation(DebugLoc());
2535 GR->buildAssignPtr(B, ElemTy, Arg);
2536 }
2537 } else if (isa<GetElementPtrInst>(Param)) {
2538 replaceUsesOfWithSpvPtrcast(Param, normalizeType(ElemTy), CI,
2539 Ptrcasts);
2540 } else if (isa<Instruction>(Param)) {
2541 GR->addDeducedElementType(Param, normalizeType(ElemTy));
2542 // insertAssignTypeIntrs() will complete buildAssignPtr()
2543 } else {
2544 B.SetInsertPoint(CI->getParent()
2545 ->getParent()
2546 ->getEntryBlock()
2547 .getFirstNonPHIOrDbgOrAlloca());
2548 GR->buildAssignPtr(B, ElemTy, Param);
2549 }
2550 CallInst *Ref = dyn_cast<CallInst>(Param);
2551 if (!Ref)
2552 continue;
2553 Function *RefF = Ref->getCalledFunction();
2554 if (!RefF || !isPointerTy(RefF->getReturnType()) ||
2555 GR->findDeducedElementType(RefF))
2556 continue;
2557 ElemTy = normalizeType(ElemTy);
2558 GR->addDeducedElementType(RefF, ElemTy);
2559 GR->addReturnType(
2561 ElemTy, getPointerAddressSpace(RefF->getReturnType())));
2562 }
2563 }
2564 }
2565}
2566
2568SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP) {
2569 // getelementptr [0 x T], P, 0 (zero), I -> getelementptr T, P, I.
2570 // If type is 0-length array and first index is 0 (zero), drop both the
2571 // 0-length array type and the first index. This is a common pattern in the
2572 // IR, e.g. when using a zero-length array as a placeholder for a flexible
2573 // array such as unbound arrays.
2574 assert(GEP && "GEP is null");
2575 Type *SrcTy = GEP->getSourceElementType();
2576 SmallVector<Value *, 8> Indices(GEP->indices());
2577 ArrayType *ArrTy = dyn_cast<ArrayType>(SrcTy);
2578 if (ArrTy && ArrTy->getNumElements() == 0 &&
2580 IRBuilder<> Builder(GEP);
2581 Indices.erase(Indices.begin());
2582 SrcTy = ArrTy->getElementType();
2583 Value *NewGEP = Builder.CreateGEP(SrcTy, GEP->getPointerOperand(), Indices,
2584 "", GEP->getNoWrapFlags());
2585 assert(llvm::isa<GetElementPtrInst>(NewGEP) && "NewGEP should be a GEP");
2586 return cast<GetElementPtrInst>(NewGEP);
2587 }
2588 return nullptr;
2589}
2590
2591bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
2592 if (Func.isDeclaration())
2593 return false;
2594
2595 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(Func);
2596 GR = ST.getSPIRVGlobalRegistry();
2597
2598 if (!CurrF)
2599 HaveFunPtrs =
2600 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
2601
2602 CurrF = &Func;
2603 IRBuilder<> B(Func.getContext());
2604 AggrConsts.clear();
2605 AggrConstTypes.clear();
2606 AggrStores.clear();
2607
2608 // Fix GEP result types ahead of inference, and simplify if possible.
2609 // Data structure for dead instructions that were simplified and replaced.
2611 for (auto &I : instructions(Func)) {
2612 auto *Ref = dyn_cast<GetElementPtrInst>(&I);
2613 if (!Ref || GR->findDeducedElementType(Ref))
2614 continue;
2615
2616 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(Ref);
2617 if (NewGEP) {
2618 Ref->replaceAllUsesWith(NewGEP);
2620 DeadInsts.insert(Ref);
2621
2622 Ref = NewGEP;
2623 }
2624 if (Type *GepTy = getGEPType(Ref))
2625 GR->addDeducedElementType(Ref, normalizeType(GepTy));
2626 }
2627 // Remove dead instructions that were simplified and replaced.
2628 for (auto *I : DeadInsts) {
2629 assert(I->use_empty() && "Dead instruction should not have any uses left");
2630 I->eraseFromParent();
2631 }
2632
2633 processParamTypesByFunHeader(CurrF, B);
2634
2635 // StoreInst's operand type can be changed during the next transformations,
2636 // so we need to store it in the set. Also store already transformed types.
2637 for (auto &I : instructions(Func)) {
2638 StoreInst *SI = dyn_cast<StoreInst>(&I);
2639 if (!SI)
2640 continue;
2641 Type *ElTy = SI->getValueOperand()->getType();
2642 if (ElTy->isAggregateType() || ElTy->isVectorTy())
2643 AggrStores.insert(&I);
2644 }
2645
2646 B.SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin());
2647 for (auto &GV : Func.getParent()->globals())
2648 processGlobalValue(GV, B);
2649
2650 preprocessUndefs(B);
2651 preprocessCompositeConstants(B);
2654
2655 applyDemangledPtrArgTypes(B);
2656
2657 // Pass forward: use operand to deduce instructions result.
2658 for (auto &I : Worklist) {
2659 // Don't emit intrinsincs for convergence intrinsics.
2660 if (isConvergenceIntrinsic(I))
2661 continue;
2662
2663 bool Postpone = insertAssignPtrTypeIntrs(I, B, false);
2664 // if Postpone is true, we can't decide on pointee type yet
2665 insertAssignTypeIntrs(I, B);
2666 insertPtrCastOrAssignTypeInstr(I, B);
2668 // if instruction requires a pointee type set, let's check if we know it
2669 // already, and force it to be i8 if not
2670 if (Postpone && !GR->findAssignPtrTypeInstr(I))
2671 insertAssignPtrTypeIntrs(I, B, true);
2672
2673 if (auto *FPI = dyn_cast<ConstrainedFPIntrinsic>(I))
2674 useRoundingMode(FPI, B);
2675 }
2676
2677 // Pass backward: use instructions results to specify/update/cast operands
2678 // where needed.
2679 SmallPtrSet<Instruction *, 4> IncompleteRets;
2680 for (auto &I : llvm::reverse(instructions(Func)))
2681 deduceOperandElementType(&I, &IncompleteRets);
2682
2683 // Pass forward for PHIs only, their operands are not preceed the instruction
2684 // in meaning of `instructions(Func)`.
2685 for (BasicBlock &BB : Func)
2686 for (PHINode &Phi : BB.phis())
2687 if (isPointerTy(Phi.getType()))
2688 deduceOperandElementType(&Phi, nullptr);
2689
2690 for (auto *I : Worklist) {
2691 TrackConstants = true;
2692 if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
2694 // Visitors return either the original/newly created instruction for further
2695 // processing, nullptr otherwise.
2696 I = visit(*I);
2697 if (!I)
2698 continue;
2699
2700 // Don't emit intrinsics for convergence operations.
2701 if (isConvergenceIntrinsic(I))
2702 continue;
2703
2705 processInstrAfterVisit(I, B);
2706 }
2707
2708 return true;
2709}
2710
2711// Try to deduce a better type for pointers to untyped ptr.
2712bool SPIRVEmitIntrinsics::postprocessTypes(Module &M) {
2713 if (!GR || TodoTypeSz == 0)
2714 return false;
2715
2716 unsigned SzTodo = TodoTypeSz;
2718 for (auto [Op, Enabled] : TodoType) {
2719 // TODO: add isa<CallInst>(Op) to continue
2720 if (!Enabled || isa<GetElementPtrInst>(Op))
2721 continue;
2722 CallInst *AssignCI = GR->findAssignPtrTypeInstr(Op);
2723 Type *KnownTy = GR->findDeducedElementType(Op);
2724 if (!KnownTy || !AssignCI)
2725 continue;
2726 assert(Op == AssignCI->getArgOperand(0));
2727 // Try to improve the type deduced after all Functions are processed.
2728 if (auto *CI = dyn_cast<Instruction>(Op)) {
2729 CurrF = CI->getParent()->getParent();
2730 std::unordered_set<Value *> Visited;
2731 if (Type *ElemTy = deduceElementTypeHelper(Op, Visited, false, true)) {
2732 if (ElemTy != KnownTy) {
2734 propagateElemType(CI, ElemTy, VisitedSubst);
2735 eraseTodoType(Op);
2736 continue;
2737 }
2738 }
2739 }
2740
2741 if (Op->hasUseList()) {
2742 for (User *U : Op->users()) {
2743 Instruction *Inst = dyn_cast<Instruction>(U);
2744 if (Inst && !isa<IntrinsicInst>(Inst))
2745 ToProcess[Inst].insert(Op);
2746 }
2747 }
2748 }
2749 if (TodoTypeSz == 0)
2750 return true;
2751
2752 for (auto &F : M) {
2753 CurrF = &F;
2754 SmallPtrSet<Instruction *, 4> IncompleteRets;
2755 for (auto &I : llvm::reverse(instructions(F))) {
2756 auto It = ToProcess.find(&I);
2757 if (It == ToProcess.end())
2758 continue;
2759 It->second.remove_if([this](Value *V) { return !isTodoType(V); });
2760 if (It->second.size() == 0)
2761 continue;
2762 deduceOperandElementType(&I, &IncompleteRets, &It->second, true);
2763 if (TodoTypeSz == 0)
2764 return true;
2765 }
2766 }
2767
2768 return SzTodo > TodoTypeSz;
2769}
2770
2771// Parse and store argument types of function declarations where needed.
2772void SPIRVEmitIntrinsics::parseFunDeclarations(Module &M) {
2773 for (auto &F : M) {
2774 if (!F.isDeclaration() || F.isIntrinsic())
2775 continue;
2776 // get the demangled name
2777 std::string DemangledName = getOclOrSpirvBuiltinDemangledName(F.getName());
2778 if (DemangledName.empty())
2779 continue;
2780 // allow only OpGroupAsyncCopy use case at the moment
2781 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(F);
2782 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
2783 DemangledName, ST.getPreferredInstructionSet());
2784 if (Opcode != SPIRV::OpGroupAsyncCopy)
2785 continue;
2786 // find pointer arguments
2788 for (unsigned OpIdx = 0; OpIdx < F.arg_size(); ++OpIdx) {
2789 Argument *Arg = F.getArg(OpIdx);
2790 if (isPointerTy(Arg->getType()) && !hasPointeeTypeAttr(Arg))
2791 Idxs.push_back(OpIdx);
2792 }
2793 if (!Idxs.size())
2794 continue;
2795 // parse function arguments
2796 LLVMContext &Ctx = F.getContext();
2798 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
2799 if (!TypeStrs.size())
2800 continue;
2801 // find type info for pointer arguments
2802 for (unsigned Idx : Idxs) {
2803 if (Idx >= TypeStrs.size())
2804 continue;
2805 if (Type *ElemTy =
2806 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
2808 !ElemTy->isTargetExtTy())
2809 FDeclPtrTys[&F].push_back(std::make_pair(Idx, ElemTy));
2810 }
2811 }
2812}
2813
2814bool SPIRVEmitIntrinsics::runOnModule(Module &M) {
2815 bool Changed = false;
2816
2817 parseFunDeclarations(M);
2818
2819 TodoType.clear();
2820 for (auto &F : M)
2821 Changed |= runOnFunction(F);
2822
2823 // Specify function parameters after all functions were processed.
2824 for (auto &F : M) {
2825 // check if function parameter types are set
2826 CurrF = &F;
2827 if (!F.isDeclaration() && !F.isIntrinsic()) {
2828 IRBuilder<> B(F.getContext());
2829 processParamTypes(&F, B);
2830 }
2831 }
2832
2833 CanTodoType = false;
2834 Changed |= postprocessTypes(M);
2835
2836 if (HaveFunPtrs)
2837 Changed |= processFunctionPointers(M);
2838
2839 return Changed;
2840}
2841
2843 return new SPIRVEmitIntrinsics(TM);
2844}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
unsigned Intr
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.
return RetTy
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseSet and SmallDenseSet classes.
std::string Name
static bool runOnFunction(Function &F, bool PostInlining)
Hexagon Common GEP
iv Induction Variable Users
Definition: IVUsers.cpp:48
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
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 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 bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
#define SPIRV_BACKEND_SERVICE_FUN_NAME
Definition: SPIRVUtils.h:452
static bool Enabled
Definition: Statistic.cpp:46
DEMANGLE_NAMESPACE_BEGIN bool starts_with(std::string_view self, char C) noexcept
static SymbolRef::Type getType(const Symbol *Sym)
Definition: TapiFile.cpp:39
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
an instruction to allocate memory on the stack
Definition: Instructions.h:64
Represent the analysis usage information of a pass.
This class represents an incoming formal argument to a Function.
Definition: Argument.h:32
const Function * getParent() const
Definition: Argument.h:44
An instruction that atomically checks whether a specified value is in a memory location,...
Definition: Instructions.h:506
static unsigned getPointerOperandIndex()
Definition: Instructions.h:636
static unsigned getPointerOperandIndex()
Definition: Instructions.h:888
LLVM Basic Block Representation.
Definition: BasicBlock.h:62
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
Definition: BasicBlock.h:528
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.
Definition: BasicBlock.cpp:131
This class represents a no-op cast from one type to another.
static LLVM_ABI BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
Definition: Constants.cpp:1911
bool isInlineAsm() const
Check if this call is an inline asm statement.
Definition: InstrTypes.h:1415
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Definition: InstrTypes.h:1348
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Definition: InstrTypes.h:1340
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1292
FunctionType * getFunctionType() const
Definition: InstrTypes.h:1205
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
Definition: InstrTypes.h:1283
unsigned arg_size() const
Definition: InstrTypes.h:1290
This class represents a function call, abstracting a target machine's calling convention.
static ConstantAsMetadata * get(Constant *C)
Definition: Metadata.h:535
This is the shared class of boolean and integer constants.
Definition: Constants.h:87
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:163
This is an important base class in LLVM.
Definition: Constant.h:43
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Definition: Constants.cpp:373
This is the common base class for constrained floating point intrinsics.
LLVM_ABI std::optional< RoundingMode > getRoundingMode() const
This class represents an Operation in the Expression.
A debug info location.
Definition: DebugLoc.h:124
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:177
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition: DenseMap.h:245
iterator end()
Definition: DenseMap.h:87
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:230
Implements a dense probed hash-table based set.
Definition: DenseSet.h:263
This instruction extracts a single (scalar) element from a VectorType value.
This instruction extracts a struct member or array element value from an aggregate value.
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
Definition: Function.cpp:637
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:166
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
Definition: Function.h:244
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
Definition: Function.h:249
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:359
size_t arg_size() const
Definition: Function.h:899
Type * getReturnType() const
Returns the type of the ret val.
Definition: Function.h:214
Argument * getArg(unsigned i) const
Definition: Function.h:884
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
Definition: Instructions.h:949
static LLVM_ABI Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static unsigned getPointerOperandIndex()
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:296
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition: GlobalValue.h:61
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:2780
Indirect Branch Instruction.
LLVM_ABI void addDestination(BasicBlock *Dest)
Add a destination.
This instruction inserts a single (scalar) element into a VectorType value.
This instruction inserts a struct field of array element value into an aggregate value.
Base class for instruction visitors.
Definition: InstVisitor.h:78
RetTy visitExtractElementInst(ExtractElementInst &I)
Definition: InstVisitor.h:192
RetTy visitInsertValueInst(InsertValueInst &I)
Definition: InstVisitor.h:196
RetTy visitUnreachableInst(UnreachableInst &I)
Definition: InstVisitor.h:236
RetTy visitAtomicCmpXchgInst(AtomicCmpXchgInst &I)
Definition: InstVisitor.h:171
RetTy visitBitCastInst(BitCastInst &I)
Definition: InstVisitor.h:188
RetTy visitSwitchInst(SwitchInst &I)
Definition: InstVisitor.h:227
RetTy visitExtractValueInst(ExtractValueInst &I)
Definition: InstVisitor.h:195
RetTy visitStoreInst(StoreInst &I)
Definition: InstVisitor.h:170
RetTy visitInsertElementInst(InsertElementInst &I)
Definition: InstVisitor.h:193
RetTy visitAllocaInst(AllocaInst &I)
Definition: InstVisitor.h:168
RetTy visitCallInst(CallInst &I)
Definition: InstVisitor.h:215
RetTy visitGetElementPtrInst(GetElementPtrInst &I)
Definition: InstVisitor.h:174
void visitInstruction(Instruction &I)
Definition: InstVisitor.h:275
RetTy visitLoadInst(LoadInst &I)
Definition: InstVisitor.h:169
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...
Definition: Instruction.h:171
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
Definition: Instruction.cpp:82
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
A wrapper class for inspecting calls to intrinsic functions.
Definition: IntrinsicInst.h:49
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
An instruction for reading from memory.
Definition: Instructions.h:180
static unsigned getPointerOperandIndex()
Definition: Instructions.h:261
Metadata node.
Definition: Metadata.h:1077
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition: Metadata.h:1565
A single uniqued string.
Definition: Metadata.h:720
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Definition: Metadata.cpp:607
Flags
Flags values. These may be or'd together.
Metadata wrapper in the Value hierarchy.
Definition: Metadata.h:182
static LLVM_ABI MetadataAsValue * get(LLVMContext &Context, Metadata *MD)
Definition: Metadata.cpp:103
Metadata * getMetadata() const
Definition: Metadata.h:200
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:255
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:112
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:85
Type * findMutated(const Value *Val)
Type * findDeducedElementType(const Value *Val)
bool canUseExtension(SPIRV::Extension::Extension E) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:401
bool contains(ConstPtrType Ptr) const
Definition: SmallPtrSet.h:476
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:541
bool empty() const
Definition: SmallVector.h:82
size_t size() const
Definition: SmallVector.h:79
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
An instruction for storing to memory.
Definition: Instructions.h:296
static unsigned getPointerOperandIndex()
Definition: Instructions.h:388
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:133
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:269
Class to represent struct types.
Definition: DerivedTypes.h:218
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition: Type.cpp:620
Multiway switch.
Class to represent target extensions types, which are generally unintrospectable from target-independ...
Definition: DerivedTypes.h:781
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:908
Type * getTypeParameter(unsigned i) const
Definition: DerivedTypes.h:828
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
bool isVectorTy() const
True if this is an instance of VectorType.
Definition: Type.h:273
bool isArrayTy() const
True if this is an instance of ArrayType.
Definition: Type.h:264
bool isPointerTy() const
True if this is an instance of PointerType.
Definition: Type.h:267
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Type * getArrayElementType() const
Definition: Type.h:408
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
bool isStructTy() const
True if this is an instance of StructType.
Definition: Type.h:261
bool isTargetExtTy() const
Return true if this is a target extension type.
Definition: Type.h:203
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition: Type.h:304
bool isVoidTy() const
Return true if this is 'void'.
Definition: Type.h:139
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.
Definition: Constants.cpp:1866
This function has undefined behavior.
A Use represents the edge between a Value definition and its users.
Definition: Use.h:35
op_range operands()
Definition: User.h:292
Value * getOperand(unsigned i) const
Definition: User.h:232
LLVM Value Representation.
Definition: Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:256
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:390
iterator_range< user_iterator > users()
Definition: Value.h:426
bool use_empty() const
Definition: Value.h:346
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:322
bool user_empty() const
Definition: Value.h:389
const ParentTy * getParent() const
Definition: ilist_node.h:34
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ SPIR_KERNEL
Used for SPIR kernel functions.
Definition: CallingConv.h:144
bool match(Val *V, const Pattern &P)
Definition: PatternMatch.h:49
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
Definition: PatternMatch.h:612
std::string lookupBuiltinNameHelper(StringRef DemangledCall, FPDecorationId *DecorationId)
Parses the name part of the demangled builtin call.
Type * parseBuiltinCallArgumentType(StringRef TypeStr, LLVMContext &Ctx)
bool parseBuiltinTypeStr(SmallVector< StringRef, 10 > &BuiltinArgsTypeStrs, const StringRef DemangledCall, LLVMContext &Ctx)
std::tuple< int, unsigned, unsigned > mapBuiltinToOpcode(const StringRef DemangledCall, SPIRV::InstructionSet::InstructionSet Set)
Helper function for finding a builtin function attributes by a demangled function name.
Type * parseBuiltinCallArgumentBaseType(const StringRef DemangledCall, unsigned ArgIdx, LLVMContext &Ctx)
Parses the provided ArgIdx argument base type in the DemangledCall skeleton.
ElementType
The element type of an SRV or UAV resource.
Definition: DXILABI.h:59
NodeAddr< PhiNode * > Phi
Definition: RDFGraph.h:390
NodeAddr< FuncNode * > Func
Definition: RDFGraph.h:393
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:338
bool getVacantFunctionName(Module &M, std::string &Name)
Definition: SPIRVUtils.cpp:754
@ Offset
Definition: DWP.cpp:477
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
Definition: SPIRVUtils.h:330
ModulePass * createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM)
unsigned getPointerAddressSpace(const Type *T)
Definition: SPIRVUtils.h:294
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
Definition: SPIRVUtils.cpp:821
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition: STLExtras.h:2155
FPDecorationId
Definition: SPIRVUtils.h:476
bool isNestedPointer(const Type *Ty)
Definition: SPIRVUtils.cpp:832
MetadataAsValue * buildMD(Value *Arg)
Definition: SPIRVUtils.h:440
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
Definition: SPIRVUtils.cpp:434
LLVM_ABI bool isInstructionTriviallyDead(Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction is not used, and the instruction will return.
Definition: Local.cpp:402
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:428
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
Definition: SPIRVUtils.h:325
bool isVector1(Type *Ty)
Definition: SPIRVUtils.h:418
bool isPointerTy(const Type *T)
Definition: SPIRVUtils.h:288
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition: Error.cpp:167
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
Definition: SPIRVUtils.cpp:319
@ Ref
The access may reference the value stored in memory.
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
Definition: SPIRVUtils.h:307
bool hasPointeeTypeAttr(Argument *Arg)
Definition: SPIRVUtils.h:302
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
Definition: SPIRVUtils.h:380
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Definition: iterator.h:363
bool hasInitializer(const GlobalVariable *GV)
Definition: SPIRVUtils.h:273
Type * normalizeType(Type *Ty)
Definition: SPIRVUtils.h:426
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
Definition: SPIRVUtils.cpp:374
Type * getPointeeType(const Type *Ty)
Definition: SPIRVUtils.h:357
PoisonValue * getNormalizedPoisonValue(Type *Ty)
Definition: SPIRVUtils.h:436
bool isUntypedPointerTy(const Type *T)
Definition: SPIRVUtils.h:283
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
Definition: SPIRVUtils.cpp:301