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