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