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