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