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