LLVM 20.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 "SPIRVMetadata.h"
17#include "SPIRVSubtarget.h"
18#include "SPIRVTargetMachine.h"
19#include "SPIRVUtils.h"
20#include "llvm/ADT/DenseSet.h"
21#include "llvm/IR/IRBuilder.h"
23#include "llvm/IR/InstVisitor.h"
24#include "llvm/IR/IntrinsicsSPIRV.h"
26
27#include <queue>
28#include <unordered_set>
29
30// This pass performs the following transformation on LLVM IR level required
31// for the following translation to SPIR-V:
32// - replaces direct usages of aggregate constants with target-specific
33// intrinsics;
34// - replaces aggregates-related instructions (extract/insert, ld/st, etc)
35// with a target-specific intrinsics;
36// - emits intrinsics for the global variable initializers since IRTranslator
37// doesn't handle them and it's not very convenient to translate them
38// ourselves;
39// - emits intrinsics to keep track of the string names assigned to the values;
40// - emits intrinsics to keep track of constants (this is necessary to have an
41// LLVM IR constant after the IRTranslation is completed) for their further
42// deduplication;
43// - emits intrinsics to keep track of original LLVM types of the values
44// to be able to emit proper SPIR-V types eventually.
45//
46// TODO: consider removing spv.track.constant in favor of spv.assign.type.
47
48using namespace llvm;
49
50namespace llvm {
51namespace SPIRV {
52#define GET_BuiltinGroup_DECL
53#include "SPIRVGenTables.inc"
54} // namespace SPIRV
56} // namespace llvm
57
58namespace {
59
60inline MetadataAsValue *buildMD(Value *Arg) {
61 LLVMContext &Ctx = Arg->getContext();
64}
65
66class SPIRVEmitIntrinsics
67 : public ModulePass,
68 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
69 SPIRVTargetMachine *TM = nullptr;
70 SPIRVGlobalRegistry *GR = nullptr;
71 Function *CurrF = nullptr;
72 bool TrackConstants = true;
73 bool HaveFunPtrs = false;
76 DenseSet<Instruction *> AggrStores;
77
78 // map of function declarations to <pointer arg index => element type>
80
81 // a register of Instructions that don't have a complete type definition
82 bool CanTodoType = true;
83 unsigned TodoTypeSz = 0;
85 void insertTodoType(Value *Op) {
86 // TODO: add isa<CallInst>(Op) to no-insert
87 if (CanTodoType && !isa<GetElementPtrInst>(Op)) {
88 auto It = TodoType.try_emplace(Op, true);
89 if (It.second)
90 ++TodoTypeSz;
91 }
92 }
93 void eraseTodoType(Value *Op) {
94 auto It = TodoType.find(Op);
95 if (It != TodoType.end() && It->second) {
96 TodoType[Op] = false;
97 --TodoTypeSz;
98 }
99 }
100 bool isTodoType(Value *Op) {
101 if (isa<GetElementPtrInst>(Op))
102 return false;
103 auto It = TodoType.find(Op);
104 return It != TodoType.end() && It->second;
105 }
106 // a register of Instructions that were visited by deduceOperandElementType()
107 // to validate operand types with an instruction
108 std::unordered_set<Instruction *> TypeValidated;
109
110 // well known result types of builtins
111 enum WellKnownTypes { Event };
112
113 // deduce element type of untyped pointers
114 Type *deduceElementType(Value *I, bool UnknownElemTypeI8);
115 Type *deduceElementTypeHelper(Value *I, bool UnknownElemTypeI8);
116 Type *deduceElementTypeHelper(Value *I, std::unordered_set<Value *> &Visited,
117 bool UnknownElemTypeI8,
118 bool IgnoreKnownType = false);
119 Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
120 bool UnknownElemTypeI8);
121 Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
122 std::unordered_set<Value *> &Visited,
123 bool UnknownElemTypeI8);
124 Type *deduceElementTypeByUsersDeep(Value *Op,
125 std::unordered_set<Value *> &Visited,
126 bool UnknownElemTypeI8);
127 void maybeAssignPtrType(Type *&Ty, Value *I, Type *RefTy,
128 bool UnknownElemTypeI8);
129
130 // deduce nested types of composites
131 Type *deduceNestedTypeHelper(User *U, bool UnknownElemTypeI8);
132 Type *deduceNestedTypeHelper(User *U, Type *Ty,
133 std::unordered_set<Value *> &Visited,
134 bool UnknownElemTypeI8);
135
136 // deduce Types of operands of the Instruction if possible
137 void deduceOperandElementType(Instruction *I,
138 SmallPtrSet<Instruction *, 4> *UncompleteRets,
139 const SmallPtrSet<Value *, 4> *AskOps = nullptr,
140 bool IsPostprocessing = false);
141
142 void preprocessCompositeConstants(IRBuilder<> &B);
143 void preprocessUndefs(IRBuilder<> &B);
144
145 CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
146 Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,
147 IRBuilder<> &B) {
149 Args.push_back(Arg2);
150 Args.push_back(buildMD(Arg));
151 for (auto *Imm : Imms)
152 Args.push_back(Imm);
153 return B.CreateIntrinsic(IntrID, {Types}, Args);
154 }
155
156 Type *reconstructType(Value *Op, bool UnknownElemTypeI8,
157 bool IsPostprocessing);
158
159 void buildAssignType(IRBuilder<> &B, Type *ElemTy, Value *Arg);
160 void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);
161 void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType);
162
163 void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
164 void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);
165 bool insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B,
166 bool UnknownElemTypeI8);
167 void insertAssignTypeIntrs(Instruction *I, IRBuilder<> &B);
168 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType, Value *V,
169 IRBuilder<> &B);
170 void replacePointerOperandWithPtrCast(Instruction *I, Value *Pointer,
171 Type *ExpectedElementType,
172 unsigned OperandToReplace,
173 IRBuilder<> &B);
174 void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
176 void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
177 void processParamTypes(Function *F, IRBuilder<> &B);
178 void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
179 Type *deduceFunParamElementType(Function *F, unsigned OpIdx);
180 Type *deduceFunParamElementType(Function *F, unsigned OpIdx,
181 std::unordered_set<Function *> &FVisited);
182
183 bool deduceOperandElementTypeCalledFunction(
184 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
185 Type *&KnownElemTy);
186 void deduceOperandElementTypeFunctionPointer(
187 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
188 Type *&KnownElemTy, bool IsPostprocessing);
189 bool deduceOperandElementTypeFunctionRet(
191 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,
192 Type *&KnownElemTy, Value *Op, Function *F);
193
194 CallInst *buildSpvPtrcast(Function *F, Value *Op, Type *ElemTy);
195 void replaceUsesOfWithSpvPtrcast(Value *Op, Type *ElemTy, Instruction *I,
197 void propagateElemType(Value *Op, Type *ElemTy,
198 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
199 void
200 propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,
201 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
202 void propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,
203 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
204 std::unordered_set<Value *> &Visited,
206
207 void replaceAllUsesWith(Value *Src, Value *Dest, bool DeleteOld = true);
208 void replaceAllUsesWithAndErase(IRBuilder<> &B, Instruction *Src,
209 Instruction *Dest, bool DeleteOld = true);
210
211 void applyDemangledPtrArgTypes(IRBuilder<> &B);
212
213 bool runOnFunction(Function &F);
214 bool postprocessTypes(Module &M);
215 bool processFunctionPointers(Module &M);
216 void parseFunDeclarations(Module &M);
217
218 void useRoundingMode(ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
219
220public:
221 static char ID;
222 SPIRVEmitIntrinsics() : ModulePass(ID) {
224 }
225 SPIRVEmitIntrinsics(SPIRVTargetMachine *_TM) : ModulePass(ID), TM(_TM) {
227 }
242
243 StringRef getPassName() const override { return "SPIRV emit intrinsics"; }
244
245 bool runOnModule(Module &M) override;
246
247 void getAnalysisUsage(AnalysisUsage &AU) const override {
249 }
250};
251
252bool isConvergenceIntrinsic(const Instruction *I) {
253 const auto *II = dyn_cast<IntrinsicInst>(I);
254 if (!II)
255 return false;
256
257 return II->getIntrinsicID() == Intrinsic::experimental_convergence_entry ||
258 II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||
259 II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor;
260}
261
262bool expectIgnoredInIRTranslation(const Instruction *I) {
263 const auto *II = dyn_cast<IntrinsicInst>(I);
264 if (!II)
265 return false;
266 switch (II->getIntrinsicID()) {
267 case Intrinsic::invariant_start:
268 case Intrinsic::spv_resource_handlefrombinding:
269 case Intrinsic::spv_resource_getpointer:
270 return true;
271 default:
272 return false;
273 }
274}
275
276bool allowEmitFakeUse(const Value *Arg) {
277 if (isSpvIntrinsic(Arg))
278 return false;
279 if (dyn_cast<AtomicCmpXchgInst>(Arg) || dyn_cast<InsertValueInst>(Arg) ||
280 dyn_cast<UndefValue>(Arg))
281 return false;
282 if (const auto *LI = dyn_cast<LoadInst>(Arg))
283 if (LI->getType()->isAggregateType())
284 return false;
285 return true;
286}
287
288} // namespace
289
290char SPIRVEmitIntrinsics::ID = 0;
291
292INITIALIZE_PASS(SPIRVEmitIntrinsics, "emit-intrinsics", "SPIRV emit intrinsics",
293 false, false)
294
295static inline bool isAssignTypeInstr(const Instruction *I) {
296 return isa<IntrinsicInst>(I) &&
297 cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type;
298}
299
301 return isa<StoreInst>(I) || isa<LoadInst>(I) || isa<InsertValueInst>(I) ||
302 isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I);
303}
304
305static bool isAggrConstForceInt32(const Value *V) {
306 return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||
307 isa<ConstantDataArray>(V) ||
308 (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
309}
310
312 if (isa<PHINode>(I))
313 B.SetInsertPoint(I->getParent()->getFirstNonPHIOrDbgOrAlloca());
314 else
315 B.SetInsertPoint(I);
316}
317
319 B.SetCurrentDebugLocation(I->getDebugLoc());
320 if (I->getType()->isVoidTy())
321 B.SetInsertPoint(I->getNextNode());
322 else
323 B.SetInsertPoint(*I->getInsertionPointAfterDef());
324}
325
327 IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I);
328 if (Intr) {
329 switch (Intr->getIntrinsicID()) {
330 case Intrinsic::invariant_start:
331 case Intrinsic::invariant_end:
332 return false;
333 }
334 }
335 return true;
336}
337
338static inline void reportFatalOnTokenType(const Instruction *I) {
339 if (I->getType()->isTokenTy())
340 report_fatal_error("A token is encountered but SPIR-V without extensions "
341 "does not support token type",
342 false);
343}
344
346 if (!I->hasName() || I->getType()->isAggregateType() ||
347 expectIgnoredInIRTranslation(I))
348 return;
351 std::vector<Value *> Args = {I};
352 addStringImm(I->getName(), B, Args);
353 B.CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);
354}
355
356void SPIRVEmitIntrinsics::replaceAllUsesWith(Value *Src, Value *Dest,
357 bool DeleteOld) {
358 Src->replaceAllUsesWith(Dest);
359 // Update deduced type records
360 GR->updateIfExistDeducedElementType(Src, Dest, DeleteOld);
361 GR->updateIfExistAssignPtrTypeInstr(Src, Dest, DeleteOld);
362 // Update uncomplete type records if any
363 if (isTodoType(Src)) {
364 if (DeleteOld)
365 eraseTodoType(Src);
366 insertTodoType(Dest);
367 }
368}
369
370void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(IRBuilder<> &B,
371 Instruction *Src,
372 Instruction *Dest,
373 bool DeleteOld) {
374 replaceAllUsesWith(Src, Dest, DeleteOld);
375 std::string Name = Src->hasName() ? Src->getName().str() : "";
376 Src->eraseFromParent();
377 if (!Name.empty()) {
378 Dest->setName(Name);
379 emitAssignName(Dest, B);
380 }
381}
382
384 return SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&
385 isPointerTy(SI->getValueOperand()->getType()) &&
386 isa<Argument>(SI->getValueOperand());
387}
388
389// Maybe restore original function return type.
391 Type *Ty) {
392 CallInst *CI = dyn_cast<CallInst>(I);
393 if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||
395 return Ty;
396 if (Type *OriginalTy = GR->findMutated(CI->getCalledFunction()))
397 return OriginalTy;
398 return Ty;
399}
400
401// Reconstruct type with nested element types according to deduced type info.
402// Return nullptr if no detailed type info is available.
403Type *SPIRVEmitIntrinsics::reconstructType(Value *Op, bool UnknownElemTypeI8,
404 bool IsPostprocessing) {
405 Type *Ty = Op->getType();
406 if (auto *OpI = dyn_cast<Instruction>(Op))
407 Ty = restoreMutatedType(GR, OpI, Ty);
408 if (!isUntypedPointerTy(Ty))
409 return Ty;
410 // try to find the pointee type
411 if (Type *NestedTy = GR->findDeducedElementType(Op))
413 // not a pointer according to the type info (e.g., Event object)
415 if (CI) {
416 MetadataAsValue *MD = cast<MetadataAsValue>(CI->getArgOperand(1));
417 return cast<ConstantAsMetadata>(MD->getMetadata())->getType();
418 }
419 if (UnknownElemTypeI8) {
420 if (!IsPostprocessing)
421 insertTodoType(Op);
422 return getTypedPointerWrapper(IntegerType::getInt8Ty(Op->getContext()),
424 }
425 return nullptr;
426}
427
428void SPIRVEmitIntrinsics::buildAssignType(IRBuilder<> &B, Type *Ty,
429 Value *Arg) {
430 Value *OfType = PoisonValue::get(Ty);
431 CallInst *AssignCI = nullptr;
432 if (Arg->getType()->isAggregateType() && Ty->isAggregateType() &&
433 allowEmitFakeUse(Arg)) {
434 LLVMContext &Ctx = Arg->getContext();
437 MDString::get(Ctx, Arg->getName())};
438 B.CreateIntrinsic(Intrinsic::spv_value_md, {},
439 {MetadataAsValue::get(Ctx, MDTuple::get(Ctx, ArgMDs))});
440 AssignCI = B.CreateIntrinsic(Intrinsic::fake_use, {}, {Arg});
441 } else {
442 AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type, {Arg->getType()},
443 OfType, Arg, {}, B);
444 }
445 GR->addAssignPtrTypeInstr(Arg, AssignCI);
446}
447
448void SPIRVEmitIntrinsics::buildAssignPtr(IRBuilder<> &B, Type *ElemTy,
449 Value *Arg) {
450 Value *OfType = PoisonValue::get(ElemTy);
451 CallInst *AssignPtrTyCI = GR->findAssignPtrTypeInstr(Arg);
452 if (AssignPtrTyCI == nullptr ||
453 AssignPtrTyCI->getParent()->getParent() != CurrF) {
454 AssignPtrTyCI = buildIntrWithMD(
455 Intrinsic::spv_assign_ptr_type, {Arg->getType()}, OfType, Arg,
456 {B.getInt32(getPointerAddressSpace(Arg->getType()))}, B);
457 GR->addDeducedElementType(AssignPtrTyCI, ElemTy);
458 GR->addDeducedElementType(Arg, ElemTy);
459 GR->addAssignPtrTypeInstr(Arg, AssignPtrTyCI);
460 } else {
461 updateAssignType(AssignPtrTyCI, Arg, OfType);
462 }
463}
464
465void SPIRVEmitIntrinsics::updateAssignType(CallInst *AssignCI, Value *Arg,
466 Value *OfType) {
467 AssignCI->setArgOperand(1, buildMD(OfType));
468 if (cast<IntrinsicInst>(AssignCI)->getIntrinsicID() !=
469 Intrinsic::spv_assign_ptr_type)
470 return;
471
472 // update association with the pointee type
473 Type *ElemTy = OfType->getType();
474 GR->addDeducedElementType(AssignCI, ElemTy);
475 GR->addDeducedElementType(Arg, ElemTy);
476}
477
478CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,
479 Type *ElemTy) {
480 IRBuilder<> B(Op->getContext());
481 if (auto *OpI = dyn_cast<Instruction>(Op)) {
482 // spv_ptrcast's argument Op denotes an instruction that generates
483 // a value, and we may use getInsertionPointAfterDef()
485 } else if (auto *OpA = dyn_cast<Argument>(Op)) {
486 B.SetInsertPointPastAllocas(OpA->getParent());
487 B.SetCurrentDebugLocation(DebugLoc());
488 } else {
489 B.SetInsertPoint(F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
490 }
491 Type *OpTy = Op->getType();
492 SmallVector<Type *, 2> Types = {OpTy, OpTy};
493 SmallVector<Value *, 2> Args = {Op, buildMD(PoisonValue::get(ElemTy)),
494 B.getInt32(getPointerAddressSpace(OpTy))};
495 CallInst *PtrCasted =
496 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
497 buildAssignPtr(B, ElemTy, PtrCasted);
498 return PtrCasted;
499}
500
501void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
502 Value *Op, Type *ElemTy, Instruction *I,
504 Function *F = I->getParent()->getParent();
505 CallInst *PtrCastedI = nullptr;
506 auto It = Ptrcasts.find(F);
507 if (It == Ptrcasts.end()) {
508 PtrCastedI = buildSpvPtrcast(F, Op, ElemTy);
509 Ptrcasts[F] = PtrCastedI;
510 } else {
511 PtrCastedI = It->second;
512 }
513 I->replaceUsesOfWith(Op, PtrCastedI);
514}
515
516void SPIRVEmitIntrinsics::propagateElemType(
517 Value *Op, Type *ElemTy,
518 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
520 SmallVector<User *> Users(Op->users());
521 for (auto *U : Users) {
522 if (!isa<Instruction>(U) || isSpvIntrinsic(U))
523 continue;
524 if (!VisitedSubst.insert(std::make_pair(U, Op)).second)
525 continue;
526 Instruction *UI = dyn_cast<Instruction>(U);
527 // If the instruction was validated already, we need to keep it valid by
528 // keeping current Op type.
529 if (isa<GetElementPtrInst>(UI) ||
530 TypeValidated.find(UI) != TypeValidated.end())
531 replaceUsesOfWithSpvPtrcast(Op, ElemTy, UI, Ptrcasts);
532 }
533}
534
535void SPIRVEmitIntrinsics::propagateElemTypeRec(
536 Value *Op, Type *PtrElemTy, Type *CastElemTy,
537 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
538 std::unordered_set<Value *> Visited;
540 propagateElemTypeRec(Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
541 Ptrcasts);
542}
543
544void SPIRVEmitIntrinsics::propagateElemTypeRec(
545 Value *Op, Type *PtrElemTy, Type *CastElemTy,
546 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
547 std::unordered_set<Value *> &Visited,
549 if (!Visited.insert(Op).second)
550 return;
551 SmallVector<User *> Users(Op->users());
552 for (auto *U : Users) {
553 if (!isa<Instruction>(U) || isSpvIntrinsic(U))
554 continue;
555 if (!VisitedSubst.insert(std::make_pair(U, Op)).second)
556 continue;
557 Instruction *UI = dyn_cast<Instruction>(U);
558 // If the instruction was validated already, we need to keep it valid by
559 // keeping current Op type.
560 if (isa<GetElementPtrInst>(UI) ||
561 TypeValidated.find(UI) != TypeValidated.end())
562 replaceUsesOfWithSpvPtrcast(Op, CastElemTy, UI, Ptrcasts);
563 }
564}
565
566// Set element pointer type to the given value of ValueTy and tries to
567// specify this type further (recursively) by Operand value, if needed.
568
569Type *
570SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
571 bool UnknownElemTypeI8) {
572 std::unordered_set<Value *> Visited;
573 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
574 UnknownElemTypeI8);
575}
576
577Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
578 Type *ValueTy, Value *Operand, std::unordered_set<Value *> &Visited,
579 bool UnknownElemTypeI8) {
580 Type *Ty = ValueTy;
581 if (Operand) {
582 if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
583 if (Type *NestedTy =
584 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
585 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
586 } else {
587 Ty = deduceNestedTypeHelper(dyn_cast<User>(Operand), Ty, Visited,
588 UnknownElemTypeI8);
589 }
590 }
591 return Ty;
592}
593
594// Traverse User instructions to deduce an element pointer type of the operand.
595Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
596 Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {
597 if (!Op || !isPointerTy(Op->getType()) || isa<ConstantPointerNull>(Op) ||
598 isa<UndefValue>(Op))
599 return nullptr;
600
601 if (auto ElemTy = getPointeeType(Op->getType()))
602 return ElemTy;
603
604 // maybe we already know operand's element type
605 if (Type *KnownTy = GR->findDeducedElementType(Op))
606 return KnownTy;
607
608 for (User *OpU : Op->users()) {
609 if (Instruction *Inst = dyn_cast<Instruction>(OpU)) {
610 if (Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
611 return Ty;
612 }
613 }
614 return nullptr;
615}
616
617// Implements what we know in advance about intrinsics and builtin calls
618// TODO: consider feasibility of this particular case to be generalized by
619// encoding knowledge about intrinsics and builtin calls by corresponding
620// specification rules
622 Function *CalledF, unsigned OpIdx) {
623 if ((DemangledName.starts_with("__spirv_ocl_printf(") ||
624 DemangledName.starts_with("printf(")) &&
625 OpIdx == 0)
626 return IntegerType::getInt8Ty(CalledF->getContext());
627 return nullptr;
628}
629
630// Deduce and return a successfully deduced Type of the Instruction,
631// or nullptr otherwise.
632Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
633 bool UnknownElemTypeI8) {
634 std::unordered_set<Value *> Visited;
635 return deduceElementTypeHelper(I, Visited, UnknownElemTypeI8);
636}
637
638void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,
639 bool UnknownElemTypeI8) {
640 if (isUntypedPointerTy(RefTy)) {
641 if (!UnknownElemTypeI8)
642 return;
643 insertTodoType(Op);
644 }
645 Ty = RefTy;
646}
647
648Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
649 Value *I, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8,
650 bool IgnoreKnownType) {
651 // allow to pass nullptr as an argument
652 if (!I)
653 return nullptr;
654
655 // maybe already known
656 if (!IgnoreKnownType)
657 if (Type *KnownTy = GR->findDeducedElementType(I))
658 return KnownTy;
659
660 // maybe a cycle
661 if (!Visited.insert(I).second)
662 return nullptr;
663
664 // fallback value in case when we fail to deduce a type
665 Type *Ty = nullptr;
666 // look for known basic patterns of type inference
667 if (auto *Ref = dyn_cast<AllocaInst>(I)) {
668 maybeAssignPtrType(Ty, I, Ref->getAllocatedType(), UnknownElemTypeI8);
669 } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
670 // TODO: not sure if GetElementPtrInst::getTypeAtIndex() does anything
671 // useful here
672 if (isNestedPointer(Ref->getSourceElementType())) {
673 Ty = Ref->getSourceElementType();
674 for (Use &U : drop_begin(Ref->indices()))
675 Ty = GetElementPtrInst::getTypeAtIndex(Ty, U.get());
676 } else {
677 Ty = Ref->getResultElementType();
678 }
679 } else if (auto *Ref = dyn_cast<LoadInst>(I)) {
680 Value *Op = Ref->getPointerOperand();
681 Type *KnownTy = GR->findDeducedElementType(Op);
682 if (!KnownTy)
683 KnownTy = Op->getType();
684 if (Type *ElemTy = getPointeeType(KnownTy))
685 maybeAssignPtrType(Ty, I, ElemTy, UnknownElemTypeI8);
686 } else if (auto *Ref = dyn_cast<GlobalValue>(I)) {
687 Ty = deduceElementTypeByValueDeep(
688 Ref->getValueType(),
689 Ref->getNumOperands() > 0 ? Ref->getOperand(0) : nullptr, Visited,
690 UnknownElemTypeI8);
691 } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {
692 Type *RefTy = deduceElementTypeHelper(Ref->getPointerOperand(), Visited,
693 UnknownElemTypeI8);
694 maybeAssignPtrType(Ty, I, RefTy, UnknownElemTypeI8);
695 } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {
696 if (Type *Src = Ref->getSrcTy(), *Dest = Ref->getDestTy();
697 isPointerTy(Src) && isPointerTy(Dest))
698 Ty = deduceElementTypeHelper(Ref->getOperand(0), Visited,
699 UnknownElemTypeI8);
700 } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {
701 Value *Op = Ref->getNewValOperand();
702 if (isPointerTy(Op->getType()))
703 Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
704 } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {
705 Value *Op = Ref->getValOperand();
706 if (isPointerTy(Op->getType()))
707 Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
708 } else if (auto *Ref = dyn_cast<PHINode>(I)) {
709 Type *BestTy = nullptr;
710 unsigned MaxN = 1;
712 for (int i = Ref->getNumIncomingValues() - 1; i >= 0; --i) {
713 Ty = deduceElementTypeByUsersDeep(Ref->getIncomingValue(i), Visited,
714 UnknownElemTypeI8);
715 if (!Ty)
716 continue;
717 auto It = PhiTys.try_emplace(Ty, 1);
718 if (!It.second) {
719 ++It.first->second;
720 if (It.first->second > MaxN) {
721 MaxN = It.first->second;
722 BestTy = Ty;
723 }
724 }
725 }
726 if (BestTy)
727 Ty = BestTy;
728 } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
729 for (Value *Op : {Ref->getTrueValue(), Ref->getFalseValue()}) {
730 Ty = deduceElementTypeByUsersDeep(Op, Visited, UnknownElemTypeI8);
731 if (Ty)
732 break;
733 }
734 } else if (auto *CI = dyn_cast<CallInst>(I)) {
735 static StringMap<unsigned> ResTypeByArg = {
736 {"to_global", 0},
737 {"to_local", 0},
738 {"to_private", 0},
739 {"__spirv_GenericCastToPtr_ToGlobal", 0},
740 {"__spirv_GenericCastToPtr_ToLocal", 0},
741 {"__spirv_GenericCastToPtr_ToPrivate", 0},
742 {"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
743 {"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
744 {"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
745 // TODO: maybe improve performance by caching demangled names
746
747 auto *II = dyn_cast<IntrinsicInst>(I);
748 if (II && II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
749 auto *ImageType = cast<TargetExtType>(II->getOperand(0)->getType());
750 assert(ImageType->getTargetExtName() == "spirv.Image");
751 Ty = ImageType->getTypeParameter(0);
752 } else if (Function *CalledF = CI->getCalledFunction()) {
753 std::string DemangledName =
754 getOclOrSpirvBuiltinDemangledName(CalledF->getName());
755 if (DemangledName.length() > 0)
756 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
757 auto AsArgIt = ResTypeByArg.find(DemangledName);
758 if (AsArgIt != ResTypeByArg.end())
759 Ty = deduceElementTypeHelper(CI->getArgOperand(AsArgIt->second),
760 Visited, UnknownElemTypeI8);
761 else if (Type *KnownRetTy = GR->findDeducedElementType(CalledF))
762 Ty = KnownRetTy;
763 }
764 }
765
766 // remember the found relationship
767 if (Ty && !IgnoreKnownType) {
768 // specify nested types if needed, otherwise return unchanged
769 GR->addDeducedElementType(I, Ty);
770 }
771
772 return Ty;
773}
774
775// Re-create a type of the value if it has untyped pointer fields, also nested.
776// Return the original value type if no corrections of untyped pointer
777// information is found or needed.
778Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
779 bool UnknownElemTypeI8) {
780 std::unordered_set<Value *> Visited;
781 return deduceNestedTypeHelper(U, U->getType(), Visited, UnknownElemTypeI8);
782}
783
784Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
785 User *U, Type *OrigTy, std::unordered_set<Value *> &Visited,
786 bool UnknownElemTypeI8) {
787 if (!U)
788 return OrigTy;
789
790 // maybe already known
791 if (Type *KnownTy = GR->findDeducedCompositeType(U))
792 return KnownTy;
793
794 // maybe a cycle
795 if (!Visited.insert(U).second)
796 return OrigTy;
797
798 if (dyn_cast<StructType>(OrigTy)) {
800 bool Change = false;
801 for (unsigned i = 0; i < U->getNumOperands(); ++i) {
802 Value *Op = U->getOperand(i);
803 Type *OpTy = Op->getType();
804 Type *Ty = OpTy;
805 if (Op) {
806 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
807 if (Type *NestedTy =
808 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
809 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
810 } else {
811 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
812 UnknownElemTypeI8);
813 }
814 }
815 Tys.push_back(Ty);
816 Change |= Ty != OpTy;
817 }
818 if (Change) {
819 Type *NewTy = StructType::create(Tys);
820 GR->addDeducedCompositeType(U, NewTy);
821 return NewTy;
822 }
823 } else if (auto *ArrTy = dyn_cast<ArrayType>(OrigTy)) {
824 if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {
825 Type *OpTy = ArrTy->getElementType();
826 Type *Ty = OpTy;
827 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
828 if (Type *NestedTy =
829 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
830 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
831 } else {
832 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
833 UnknownElemTypeI8);
834 }
835 if (Ty != OpTy) {
836 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
837 GR->addDeducedCompositeType(U, NewTy);
838 return NewTy;
839 }
840 }
841 } else if (auto *VecTy = dyn_cast<VectorType>(OrigTy)) {
842 if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) {
843 Type *OpTy = VecTy->getElementType();
844 Type *Ty = OpTy;
845 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
846 if (Type *NestedTy =
847 deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8))
848 Ty = getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
849 } else {
850 Ty = deduceNestedTypeHelper(dyn_cast<User>(Op), OpTy, Visited,
851 UnknownElemTypeI8);
852 }
853 if (Ty != OpTy) {
854 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
855 GR->addDeducedCompositeType(U, NewTy);
856 return NewTy;
857 }
858 }
859 }
860
861 return OrigTy;
862}
863
864Type *SPIRVEmitIntrinsics::deduceElementType(Value *I, bool UnknownElemTypeI8) {
865 if (Type *Ty = deduceElementTypeHelper(I, UnknownElemTypeI8))
866 return Ty;
867 if (!UnknownElemTypeI8)
868 return nullptr;
869 insertTodoType(I);
870 return IntegerType::getInt8Ty(I->getContext());
871}
872
874 Value *PointerOperand) {
875 Type *PointeeTy = GR->findDeducedElementType(PointerOperand);
876 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
877 return nullptr;
878 auto *PtrTy = dyn_cast<PointerType>(I->getType());
879 if (!PtrTy)
880 return I->getType();
881 if (Type *NestedTy = GR->findDeducedElementType(I))
882 return getTypedPointerWrapper(NestedTy, PtrTy->getAddressSpace());
883 return nullptr;
884}
885
886// Try to deduce element type for a call base. Returns false if this is an
887// indirect function invocation, and true otherwise.
888bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
889 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
890 Type *&KnownElemTy) {
891 Function *CalledF = CI->getCalledFunction();
892 if (!CalledF)
893 return false;
894 std::string DemangledName =
896 if (DemangledName.length() > 0 &&
897 !StringRef(DemangledName).starts_with("llvm.")) {
898 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(*CalledF);
899 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
900 DemangledName, ST.getPreferredInstructionSet());
901 if (Opcode == SPIRV::OpGroupAsyncCopy) {
902 for (unsigned i = 0, PtrCnt = 0; i < CI->arg_size() && PtrCnt < 2; ++i) {
903 Value *Op = CI->getArgOperand(i);
904 if (!isPointerTy(Op->getType()))
905 continue;
906 ++PtrCnt;
907 if (Type *ElemTy = GR->findDeducedElementType(Op))
908 KnownElemTy = ElemTy; // src will rewrite dest if both are defined
909 Ops.push_back(std::make_pair(Op, i));
910 }
911 } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
912 if (CI->arg_size() < 2)
913 return true;
914 Value *Op = CI->getArgOperand(0);
915 if (!isPointerTy(Op->getType()))
916 return true;
917 switch (Opcode) {
918 case SPIRV::OpAtomicLoad:
919 case SPIRV::OpAtomicCompareExchangeWeak:
920 case SPIRV::OpAtomicCompareExchange:
921 case SPIRV::OpAtomicExchange:
922 case SPIRV::OpAtomicIAdd:
923 case SPIRV::OpAtomicISub:
924 case SPIRV::OpAtomicOr:
925 case SPIRV::OpAtomicXor:
926 case SPIRV::OpAtomicAnd:
927 case SPIRV::OpAtomicUMin:
928 case SPIRV::OpAtomicUMax:
929 case SPIRV::OpAtomicSMin:
930 case SPIRV::OpAtomicSMax: {
931 KnownElemTy = getAtomicElemTy(GR, CI, Op);
932 if (!KnownElemTy)
933 return true;
934 Ops.push_back(std::make_pair(Op, 0));
935 } break;
936 }
937 }
938 }
939 return true;
940}
941
942// Try to deduce element type for a function pointer.
943void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
944 CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
945 Type *&KnownElemTy, bool IsPostprocessing) {
946 Value *Op = CI->getCalledOperand();
947 if (!Op || !isPointerTy(Op->getType()))
948 return;
949 Ops.push_back(std::make_pair(Op, std::numeric_limits<unsigned>::max()));
950 FunctionType *FTy = CI->getFunctionType();
951 bool IsNewFTy = false, IsUncomplete = false;
953 for (Value *Arg : CI->args()) {
954 Type *ArgTy = Arg->getType();
955 if (ArgTy->isPointerTy()) {
956 if (Type *ElemTy = GR->findDeducedElementType(Arg)) {
957 IsNewFTy = true;
958 ArgTy = getTypedPointerWrapper(ElemTy, getPointerAddressSpace(ArgTy));
959 if (isTodoType(Arg))
960 IsUncomplete = true;
961 } else {
962 IsUncomplete = true;
963 }
964 }
965 ArgTys.push_back(ArgTy);
966 }
967 Type *RetTy = FTy->getReturnType();
968 if (CI->getType()->isPointerTy()) {
969 if (Type *ElemTy = GR->findDeducedElementType(CI)) {
970 IsNewFTy = true;
971 RetTy =
973 if (isTodoType(CI))
974 IsUncomplete = true;
975 } else {
976 IsUncomplete = true;
977 }
978 }
979 if (!IsPostprocessing && IsUncomplete)
980 insertTodoType(Op);
981 KnownElemTy =
982 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
983}
984
985bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
987 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,
988 Type *&KnownElemTy, Value *Op, Function *F) {
989 KnownElemTy = GR->findDeducedElementType(F);
990 if (KnownElemTy)
991 return false;
992 if (Type *OpElemTy = GR->findDeducedElementType(Op)) {
993 GR->addDeducedElementType(F, OpElemTy);
994 GR->addReturnType(
995 F, TypedPointerType::get(OpElemTy,
996 getPointerAddressSpace(F->getReturnType())));
997 // non-recursive update of types in function uses
998 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(I, Op)};
999 for (User *U : F->users()) {
1000 CallInst *CI = dyn_cast<CallInst>(U);
1001 if (!CI || CI->getCalledFunction() != F)
1002 continue;
1003 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(CI)) {
1004 if (Type *PrevElemTy = GR->findDeducedElementType(CI)) {
1005 updateAssignType(AssignCI, CI, PoisonValue::get(OpElemTy));
1006 propagateElemType(CI, PrevElemTy, VisitedSubst);
1007 }
1008 }
1009 }
1010 // Non-recursive update of types in the function uncomplete returns.
1011 // This may happen just once per a function, the latch is a pair of
1012 // findDeducedElementType(F) / addDeducedElementType(F, ...).
1013 // With or without the latch it is a non-recursive call due to
1014 // UncompleteRets set to nullptr in this call.
1015 if (UncompleteRets)
1016 for (Instruction *UncompleteRetI : *UncompleteRets)
1017 deduceOperandElementType(UncompleteRetI, nullptr, AskOps,
1018 IsPostprocessing);
1019 } else if (UncompleteRets) {
1020 UncompleteRets->insert(I);
1021 }
1022 TypeValidated.insert(I);
1023 return true;
1024}
1025
1026// If the Instruction has Pointer operands with unresolved types, this function
1027// tries to deduce them. If the Instruction has Pointer operands with known
1028// types which differ from expected, this function tries to insert a bitcast to
1029// resolve the issue.
1030void SPIRVEmitIntrinsics::deduceOperandElementType(
1032 const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing) {
1034 Type *KnownElemTy = nullptr;
1035 bool Uncomplete = false;
1036 // look for known basic patterns of type inference
1037 if (auto *Ref = dyn_cast<PHINode>(I)) {
1038 if (!isPointerTy(I->getType()) ||
1039 !(KnownElemTy = GR->findDeducedElementType(I)))
1040 return;
1041 Uncomplete = isTodoType(I);
1042 for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {
1043 Value *Op = Ref->getIncomingValue(i);
1044 if (isPointerTy(Op->getType()))
1045 Ops.push_back(std::make_pair(Op, i));
1046 }
1047 } else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I)) {
1048 KnownElemTy = GR->findDeducedElementType(I);
1049 if (!KnownElemTy)
1050 return;
1051 Uncomplete = isTodoType(I);
1052 Ops.push_back(std::make_pair(Ref->getPointerOperand(), 0));
1053 } else if (auto *Ref = dyn_cast<BitCastInst>(I)) {
1054 if (!isPointerTy(I->getType()))
1055 return;
1056 KnownElemTy = GR->findDeducedElementType(I);
1057 if (!KnownElemTy)
1058 return;
1059 Uncomplete = isTodoType(I);
1060 Ops.push_back(std::make_pair(Ref->getOperand(0), 0));
1061 } else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
1062 if (GR->findDeducedElementType(Ref->getPointerOperand()))
1063 return;
1064 KnownElemTy = Ref->getSourceElementType();
1065 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1067 } else if (auto *Ref = dyn_cast<LoadInst>(I)) {
1068 KnownElemTy = I->getType();
1069 if (isUntypedPointerTy(KnownElemTy))
1070 return;
1071 Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
1072 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
1073 return;
1074 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1076 } else if (auto *Ref = dyn_cast<StoreInst>(I)) {
1077 if (!(KnownElemTy =
1078 reconstructType(Ref->getValueOperand(), false, IsPostprocessing)))
1079 return;
1080 Type *PointeeTy = GR->findDeducedElementType(Ref->getPointerOperand());
1081 if (PointeeTy && !isUntypedPointerTy(PointeeTy))
1082 return;
1083 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1085 } else if (auto *Ref = dyn_cast<AtomicCmpXchgInst>(I)) {
1086 KnownElemTy = getAtomicElemTy(GR, I, Ref->getPointerOperand());
1087 if (!KnownElemTy)
1088 return;
1089 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1091 } else if (auto *Ref = dyn_cast<AtomicRMWInst>(I)) {
1092 KnownElemTy = getAtomicElemTy(GR, I, Ref->getPointerOperand());
1093 if (!KnownElemTy)
1094 return;
1095 Ops.push_back(std::make_pair(Ref->getPointerOperand(),
1097 } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
1098 if (!isPointerTy(I->getType()) ||
1099 !(KnownElemTy = GR->findDeducedElementType(I)))
1100 return;
1101 Uncomplete = isTodoType(I);
1102 for (unsigned i = 0; i < Ref->getNumOperands(); i++) {
1103 Value *Op = Ref->getOperand(i);
1104 if (isPointerTy(Op->getType()))
1105 Ops.push_back(std::make_pair(Op, i));
1106 }
1107 } else if (auto *Ref = dyn_cast<ReturnInst>(I)) {
1108 if (!isPointerTy(CurrF->getReturnType()))
1109 return;
1110 Value *Op = Ref->getReturnValue();
1111 if (!Op)
1112 return;
1113 if (deduceOperandElementTypeFunctionRet(I, UncompleteRets, AskOps,
1114 IsPostprocessing, KnownElemTy, Op,
1115 CurrF))
1116 return;
1117 Uncomplete = isTodoType(CurrF);
1118 Ops.push_back(std::make_pair(Op, 0));
1119 } else if (auto *Ref = dyn_cast<ICmpInst>(I)) {
1120 if (!isPointerTy(Ref->getOperand(0)->getType()))
1121 return;
1122 Value *Op0 = Ref->getOperand(0);
1123 Value *Op1 = Ref->getOperand(1);
1124 Type *ElemTy0 = GR->findDeducedElementType(Op0);
1125 Type *ElemTy1 = GR->findDeducedElementType(Op1);
1126 if (ElemTy0) {
1127 KnownElemTy = ElemTy0;
1128 Uncomplete = isTodoType(Op0);
1129 Ops.push_back(std::make_pair(Op1, 1));
1130 } else if (ElemTy1) {
1131 KnownElemTy = ElemTy1;
1132 Uncomplete = isTodoType(Op1);
1133 Ops.push_back(std::make_pair(Op0, 0));
1134 }
1135 } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
1136 if (!CI->isIndirectCall())
1137 deduceOperandElementTypeCalledFunction(CI, Ops, KnownElemTy);
1138 else if (HaveFunPtrs)
1139 deduceOperandElementTypeFunctionPointer(CI, Ops, KnownElemTy,
1140 IsPostprocessing);
1141 }
1142
1143 // There is no enough info to deduce types or all is valid.
1144 if (!KnownElemTy || Ops.size() == 0)
1145 return;
1146
1147 LLVMContext &Ctx = CurrF->getContext();
1148 IRBuilder<> B(Ctx);
1149 for (auto &OpIt : Ops) {
1150 Value *Op = OpIt.first;
1151 if (Op->use_empty())
1152 continue;
1153 if (AskOps && !AskOps->contains(Op))
1154 continue;
1155 Type *AskTy = nullptr;
1156 CallInst *AskCI = nullptr;
1157 if (IsPostprocessing && AskOps) {
1158 AskTy = GR->findDeducedElementType(Op);
1159 AskCI = GR->findAssignPtrTypeInstr(Op);
1160 assert(AskTy && AskCI);
1161 }
1162 Type *Ty = AskTy ? AskTy : GR->findDeducedElementType(Op);
1163 if (Ty == KnownElemTy)
1164 continue;
1165 Value *OpTyVal = PoisonValue::get(KnownElemTy);
1166 Type *OpTy = Op->getType();
1167 if (!Ty || AskTy || isUntypedPointerTy(Ty) || isTodoType(Op)) {
1168 Type *PrevElemTy = GR->findDeducedElementType(Op);
1169 GR->addDeducedElementType(Op, KnownElemTy);
1170 // check if KnownElemTy is complete
1171 if (!Uncomplete)
1172 eraseTodoType(Op);
1173 else if (!IsPostprocessing)
1174 insertTodoType(Op);
1175 // check if there is existing Intrinsic::spv_assign_ptr_type instruction
1176 CallInst *AssignCI = AskCI ? AskCI : GR->findAssignPtrTypeInstr(Op);
1177 if (AssignCI == nullptr) {
1178 Instruction *User = dyn_cast<Instruction>(Op->use_begin()->get());
1179 setInsertPointSkippingPhis(B, User ? User->getNextNode() : I);
1180 CallInst *CI =
1181 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,
1182 {B.getInt32(getPointerAddressSpace(OpTy))}, B);
1183 GR->addAssignPtrTypeInstr(Op, CI);
1184 } else {
1185 updateAssignType(AssignCI, Op, OpTyVal);
1187 std::make_pair(I, Op)};
1188 propagateElemTypeRec(Op, KnownElemTy, PrevElemTy, VisitedSubst);
1189 }
1190 } else {
1191 eraseTodoType(Op);
1192 CallInst *PtrCastI =
1193 buildSpvPtrcast(I->getParent()->getParent(), Op, KnownElemTy);
1194 if (OpIt.second == std::numeric_limits<unsigned>::max())
1195 dyn_cast<CallInst>(I)->setCalledOperand(PtrCastI);
1196 else
1197 I->setOperand(OpIt.second, PtrCastI);
1198 }
1199 }
1200 TypeValidated.insert(I);
1201}
1202
1203void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1204 Instruction *New,
1205 IRBuilder<> &B) {
1206 while (!Old->user_empty()) {
1207 auto *U = Old->user_back();
1208 if (isAssignTypeInstr(U)) {
1209 B.SetInsertPoint(U);
1210 SmallVector<Value *, 2> Args = {New, U->getOperand(1)};
1211 CallInst *AssignCI =
1212 B.CreateIntrinsic(Intrinsic::spv_assign_type, {New->getType()}, Args);
1213 GR->addAssignPtrTypeInstr(New, AssignCI);
1214 U->eraseFromParent();
1215 } else if (isMemInstrToReplace(U) || isa<ReturnInst>(U) ||
1216 isa<CallInst>(U)) {
1217 U->replaceUsesOfWith(Old, New);
1218 } else {
1219 llvm_unreachable("illegal aggregate intrinsic user");
1220 }
1221 }
1222 Old->eraseFromParent();
1223}
1224
1225void SPIRVEmitIntrinsics::preprocessUndefs(IRBuilder<> &B) {
1226 std::queue<Instruction *> Worklist;
1227 for (auto &I : instructions(CurrF))
1228 Worklist.push(&I);
1229
1230 while (!Worklist.empty()) {
1231 Instruction *I = Worklist.front();
1232 bool BPrepared = false;
1233 Worklist.pop();
1234
1235 for (auto &Op : I->operands()) {
1236 auto *AggrUndef = dyn_cast<UndefValue>(Op);
1237 if (!AggrUndef || !Op->getType()->isAggregateType())
1238 continue;
1239
1240 if (!BPrepared) {
1242 BPrepared = true;
1243 }
1244 auto *IntrUndef = B.CreateIntrinsic(Intrinsic::spv_undef, {}, {});
1245 Worklist.push(IntrUndef);
1246 I->replaceUsesOfWith(Op, IntrUndef);
1247 AggrConsts[IntrUndef] = AggrUndef;
1248 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1249 }
1250 }
1251}
1252
1253void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
1254 std::queue<Instruction *> Worklist;
1255 for (auto &I : instructions(CurrF))
1256 Worklist.push(&I);
1257
1258 while (!Worklist.empty()) {
1259 auto *I = Worklist.front();
1260 bool IsPhi = isa<PHINode>(I), BPrepared = false;
1261 assert(I);
1262 bool KeepInst = false;
1263 for (const auto &Op : I->operands()) {
1264 Constant *AggrConst = nullptr;
1265 Type *ResTy = nullptr;
1266 if (auto *COp = dyn_cast<ConstantVector>(Op)) {
1267 AggrConst = cast<Constant>(COp);
1268 ResTy = COp->getType();
1269 } else if (auto *COp = dyn_cast<ConstantArray>(Op)) {
1270 AggrConst = cast<Constant>(COp);
1271 ResTy = B.getInt32Ty();
1272 } else if (auto *COp = dyn_cast<ConstantStruct>(Op)) {
1273 AggrConst = cast<Constant>(COp);
1274 ResTy = B.getInt32Ty();
1275 } else if (auto *COp = dyn_cast<ConstantDataArray>(Op)) {
1276 AggrConst = cast<Constant>(COp);
1277 ResTy = B.getInt32Ty();
1278 } else if (auto *COp = dyn_cast<ConstantAggregateZero>(Op)) {
1279 AggrConst = cast<Constant>(COp);
1280 ResTy = Op->getType()->isVectorTy() ? COp->getType() : B.getInt32Ty();
1281 }
1282 if (AggrConst) {
1284 if (auto *COp = dyn_cast<ConstantDataSequential>(Op))
1285 for (unsigned i = 0; i < COp->getNumElements(); ++i)
1286 Args.push_back(COp->getElementAsConstant(i));
1287 else
1288 for (auto &COp : AggrConst->operands())
1289 Args.push_back(COp);
1290 if (!BPrepared) {
1291 IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
1292 : B.SetInsertPoint(I);
1293 BPrepared = true;
1294 }
1295 auto *CI =
1296 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {Args});
1297 Worklist.push(CI);
1298 I->replaceUsesOfWith(Op, CI);
1299 KeepInst = true;
1300 AggrConsts[CI] = AggrConst;
1301 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst, false);
1302 }
1303 }
1304 if (!KeepInst)
1305 Worklist.pop();
1306 }
1307}
1308
1310 IRBuilder<> &B) {
1311 LLVMContext &Ctx = I->getContext();
1313 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
1314 {I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, {Node}))});
1315}
1316
1318 unsigned RoundingModeDeco,
1319 IRBuilder<> &B) {
1320 LLVMContext &Ctx = I->getContext();
1321 Type *Int32Ty = Type::getInt32Ty(Ctx);
1322 MDNode *RoundingModeNode = MDNode::get(
1323 Ctx,
1325 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1326 ConstantAsMetadata::get(ConstantInt::get(Int32Ty, RoundingModeDeco))});
1327 createDecorationIntrinsic(I, RoundingModeNode, B);
1328}
1329
1331 IRBuilder<> &B) {
1332 LLVMContext &Ctx = I->getContext();
1333 Type *Int32Ty = Type::getInt32Ty(Ctx);
1334 MDNode *SaturatedConversionNode =
1335 MDNode::get(Ctx, {ConstantAsMetadata::get(ConstantInt::get(
1336 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1337 createDecorationIntrinsic(I, SaturatedConversionNode, B);
1338}
1339
1340Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
1341 if (!Call.isInlineAsm())
1342 return &Call;
1343
1344 const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
1345 LLVMContext &Ctx = CurrF->getContext();
1346
1347 Constant *TyC = UndefValue::get(IA->getFunctionType());
1348 MDString *ConstraintString = MDString::get(Ctx, IA->getConstraintString());
1350 buildMD(TyC),
1351 MetadataAsValue::get(Ctx, MDNode::get(Ctx, ConstraintString))};
1352 for (unsigned OpIdx = 0; OpIdx < Call.arg_size(); OpIdx++)
1353 Args.push_back(Call.getArgOperand(OpIdx));
1354
1355 IRBuilder<> B(Call.getParent());
1356 B.SetInsertPoint(&Call);
1357 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {}, {Args});
1358 return &Call;
1359}
1360
1361// Use a tip about rounding mode to create a decoration.
1362void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1363 IRBuilder<> &B) {
1364 std::optional<RoundingMode> RM = FPI->getRoundingMode();
1365 if (!RM.has_value())
1366 return;
1367 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1368 switch (RM.value()) {
1369 default:
1370 // ignore unknown rounding modes
1371 break;
1372 case RoundingMode::NearestTiesToEven:
1373 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1374 break;
1375 case RoundingMode::TowardNegative:
1376 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1377 break;
1378 case RoundingMode::TowardPositive:
1379 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1380 break;
1381 case RoundingMode::TowardZero:
1382 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1383 break;
1384 case RoundingMode::Dynamic:
1385 case RoundingMode::NearestTiesToAway:
1386 // TODO: check if supported
1387 break;
1388 }
1389 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1390 return;
1391 // Convert the tip about rounding mode into a decoration record.
1392 createRoundingModeDecoration(FPI, RoundingModeDeco, B);
1393}
1394
1395Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
1396 BasicBlock *ParentBB = I.getParent();
1397 IRBuilder<> B(ParentBB);
1398 B.SetInsertPoint(&I);
1401 for (auto &Op : I.operands()) {
1402 if (Op.get()->getType()->isSized()) {
1403 Args.push_back(Op);
1404 } else if (BasicBlock *BB = dyn_cast<BasicBlock>(Op.get())) {
1405 BBCases.push_back(BB);
1406 Args.push_back(BlockAddress::get(BB->getParent(), BB));
1407 } else {
1408 report_fatal_error("Unexpected switch operand");
1409 }
1410 }
1411 CallInst *NewI = B.CreateIntrinsic(Intrinsic::spv_switch,
1412 {I.getOperand(0)->getType()}, {Args});
1413 // remove switch to avoid its unneeded and undesirable unwrap into branches
1414 // and conditions
1415 replaceAllUsesWith(&I, NewI);
1416 I.eraseFromParent();
1417 // insert artificial and temporary instruction to preserve valid CFG,
1418 // it will be removed after IR translation pass
1419 B.SetInsertPoint(ParentBB);
1420 IndirectBrInst *BrI = B.CreateIndirectBr(
1421 Constant::getNullValue(PointerType::getUnqual(ParentBB->getContext())),
1422 BBCases.size());
1423 for (BasicBlock *BBCase : BBCases)
1424 BrI->addDestination(BBCase);
1425 return BrI;
1426}
1427
1428Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
1429 IRBuilder<> B(I.getParent());
1430 B.SetInsertPoint(&I);
1431 SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
1433 Args.push_back(B.getInt1(I.isInBounds()));
1434 for (auto &Op : I.operands())
1435 Args.push_back(Op);
1436 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
1437 replaceAllUsesWithAndErase(B, &I, NewI);
1438 return NewI;
1439}
1440
1441Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
1442 IRBuilder<> B(I.getParent());
1443 B.SetInsertPoint(&I);
1444 Value *Source = I.getOperand(0);
1445
1446 // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of
1447 // varying element types. In case of IR coming from older versions of LLVM
1448 // such bitcasts do not provide sufficient information, should be just skipped
1449 // here, and handled in insertPtrCastOrAssignTypeInstr.
1450 if (isPointerTy(I.getType())) {
1451 replaceAllUsesWith(&I, Source);
1452 I.eraseFromParent();
1453 return nullptr;
1454 }
1455
1456 SmallVector<Type *, 2> Types = {I.getType(), Source->getType()};
1457 SmallVector<Value *> Args(I.op_begin(), I.op_end());
1458 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_bitcast, {Types}, {Args});
1459 replaceAllUsesWithAndErase(B, &I, NewI);
1460 return NewI;
1461}
1462
1463void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
1464 TargetExtType *AssignedType, Value *V, IRBuilder<> &B) {
1465 Type *VTy = V->getType();
1466
1467 // A couple of sanity checks.
1468 assert((isPointerTy(VTy)) && "Expect a pointer type!");
1469 if (Type *ElemTy = getPointeeType(VTy))
1470 if (ElemTy != AssignedType)
1471 report_fatal_error("Unexpected pointer element type!");
1472
1473 CallInst *AssignCI = GR->findAssignPtrTypeInstr(V);
1474 if (!AssignCI) {
1475 buildAssignType(B, AssignedType, V);
1476 return;
1477 }
1478
1479 Type *CurrentType =
1480 dyn_cast<ConstantAsMetadata>(
1481 cast<MetadataAsValue>(AssignCI->getOperand(1))->getMetadata())
1482 ->getType();
1483 if (CurrentType == AssignedType)
1484 return;
1485
1486 // Builtin types cannot be redeclared or casted.
1487 if (CurrentType->isTargetExtTy())
1488 report_fatal_error("Type mismatch " + CurrentType->getTargetExtName() +
1489 "/" + AssignedType->getTargetExtName() +
1490 " for value " + V->getName(),
1491 false);
1492
1493 // Our previous guess about the type seems to be wrong, let's update
1494 // inferred type according to a new, more precise type information.
1495 updateAssignType(AssignCI, V, PoisonValue::get(AssignedType));
1496}
1497
1498void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
1499 Instruction *I, Value *Pointer, Type *ExpectedElementType,
1500 unsigned OperandToReplace, IRBuilder<> &B) {
1501 TypeValidated.insert(I);
1502
1503 // Do not emit spv_ptrcast if Pointer's element type is ExpectedElementType
1504 Type *PointerElemTy = deduceElementTypeHelper(Pointer, false);
1505 if (PointerElemTy == ExpectedElementType ||
1506 isEquivalentTypes(PointerElemTy, ExpectedElementType))
1507 return;
1508
1510 Value *ExpectedElementVal = PoisonValue::get(ExpectedElementType);
1511 MetadataAsValue *VMD = buildMD(ExpectedElementVal);
1512 unsigned AddressSpace = getPointerAddressSpace(Pointer->getType());
1513 bool FirstPtrCastOrAssignPtrType = true;
1514
1515 // Do not emit new spv_ptrcast if equivalent one already exists or when
1516 // spv_assign_ptr_type already targets this pointer with the same element
1517 // type.
1518 for (auto User : Pointer->users()) {
1519 auto *II = dyn_cast<IntrinsicInst>(User);
1520 if (!II ||
1521 (II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
1522 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
1523 II->getOperand(0) != Pointer)
1524 continue;
1525
1526 // There is some spv_ptrcast/spv_assign_ptr_type already targeting this
1527 // pointer.
1528 FirstPtrCastOrAssignPtrType = false;
1529 if (II->getOperand(1) != VMD ||
1530 dyn_cast<ConstantInt>(II->getOperand(2))->getSExtValue() !=
1532 continue;
1533
1534 // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the same
1535 // element type and address space.
1536 if (II->getIntrinsicID() != Intrinsic::spv_ptrcast)
1537 return;
1538
1539 // This must be a spv_ptrcast, do not emit new if this one has the same BB
1540 // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.
1541 if (II->getParent() != I->getParent())
1542 continue;
1543
1544 I->setOperand(OperandToReplace, II);
1545 return;
1546 }
1547
1548 if (isa<Instruction>(Pointer) || isa<Argument>(Pointer)) {
1549 if (FirstPtrCastOrAssignPtrType) {
1550 // If this would be the first spv_ptrcast, do not emit spv_ptrcast and
1551 // emit spv_assign_ptr_type instead.
1552 buildAssignPtr(B, ExpectedElementType, Pointer);
1553 return;
1554 } else if (isTodoType(Pointer)) {
1555 eraseTodoType(Pointer);
1556 if (!isa<CallInst>(Pointer) && !isa<GetElementPtrInst>(Pointer)) {
1557 // If this wouldn't be the first spv_ptrcast but existing type info is
1558 // uncomplete, update spv_assign_ptr_type arguments.
1559 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Pointer)) {
1560 Type *PrevElemTy = GR->findDeducedElementType(Pointer);
1561 assert(PrevElemTy);
1563 std::make_pair(I, Pointer)};
1564 updateAssignType(AssignCI, Pointer, ExpectedElementVal);
1565 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
1566 } else {
1567 buildAssignPtr(B, ExpectedElementType, Pointer);
1568 }
1569 return;
1570 }
1571 }
1572 }
1573
1574 // Emit spv_ptrcast
1575 SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};
1577 auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
1578 I->setOperand(OperandToReplace, PtrCastI);
1579 // We need to set up a pointee type for the newly created spv_ptrcast.
1580 buildAssignPtr(B, ExpectedElementType, PtrCastI);
1581}
1582
1583void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
1584 IRBuilder<> &B) {
1585 // Handle basic instructions:
1586 StoreInst *SI = dyn_cast<StoreInst>(I);
1587 if (IsKernelArgInt8(CurrF, SI)) {
1588 replacePointerOperandWithPtrCast(
1589 I, SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->getContext()),
1590 0, B);
1591 }
1592 if (SI) {
1593 Value *Op = SI->getValueOperand();
1594 Value *Pointer = SI->getPointerOperand();
1595 Type *OpTy = Op->getType();
1596 if (auto *OpI = dyn_cast<Instruction>(Op))
1597 OpTy = restoreMutatedType(GR, OpI, OpTy);
1598 if (OpTy == Op->getType())
1599 OpTy = deduceElementTypeByValueDeep(OpTy, Op, false);
1600 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 1, B);
1601 return;
1602 }
1603 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
1604 Value *Pointer = LI->getPointerOperand();
1605 Type *OpTy = LI->getType();
1606 if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
1607 if (Type *ElemTy = GR->findDeducedElementType(LI)) {
1608 OpTy = getTypedPointerWrapper(ElemTy, PtrTy->getAddressSpace());
1609 } else {
1610 Type *NewOpTy = OpTy;
1611 OpTy = deduceElementTypeByValueDeep(OpTy, LI, false);
1612 if (OpTy == NewOpTy)
1613 insertTodoType(Pointer);
1614 }
1615 }
1616 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 0, B);
1617 return;
1618 }
1619 if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
1620 Value *Pointer = GEPI->getPointerOperand();
1621 Type *OpTy = GEPI->getSourceElementType();
1622 replacePointerOperandWithPtrCast(I, Pointer, OpTy, 0, B);
1623 if (isNestedPointer(OpTy))
1624 insertTodoType(Pointer);
1625 return;
1626 }
1627
1628 // TODO: review and merge with existing logics:
1629 // Handle calls to builtins (non-intrinsics):
1630 CallInst *CI = dyn_cast<CallInst>(I);
1631 if (!CI || CI->isIndirectCall() || CI->isInlineAsm() ||
1633 return;
1634
1635 // collect information about formal parameter types
1636 std::string DemangledName =
1638 Function *CalledF = CI->getCalledFunction();
1639 SmallVector<Type *, 4> CalledArgTys;
1640 bool HaveTypes = false;
1641 for (unsigned OpIdx = 0; OpIdx < CalledF->arg_size(); ++OpIdx) {
1642 Argument *CalledArg = CalledF->getArg(OpIdx);
1643 Type *ArgType = CalledArg->getType();
1644 if (!isPointerTy(ArgType)) {
1645 CalledArgTys.push_back(nullptr);
1646 } else if (Type *ArgTypeElem = getPointeeType(ArgType)) {
1647 CalledArgTys.push_back(ArgTypeElem);
1648 HaveTypes = true;
1649 } else {
1650 Type *ElemTy = GR->findDeducedElementType(CalledArg);
1651 if (!ElemTy && hasPointeeTypeAttr(CalledArg))
1652 ElemTy = getPointeeTypeByAttr(CalledArg);
1653 if (!ElemTy) {
1654 ElemTy = getPointeeTypeByCallInst(DemangledName, CalledF, OpIdx);
1655 if (ElemTy) {
1656 GR->addDeducedElementType(CalledArg, ElemTy);
1657 } else {
1658 for (User *U : CalledArg->users()) {
1659 if (Instruction *Inst = dyn_cast<Instruction>(U)) {
1660 if ((ElemTy = deduceElementTypeHelper(Inst, false)) != nullptr)
1661 break;
1662 }
1663 }
1664 }
1665 }
1666 HaveTypes |= ElemTy != nullptr;
1667 CalledArgTys.push_back(ElemTy);
1668 }
1669 }
1670
1671 if (DemangledName.empty() && !HaveTypes)
1672 return;
1673
1674 for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) {
1675 Value *ArgOperand = CI->getArgOperand(OpIdx);
1676 if (!isPointerTy(ArgOperand->getType()))
1677 continue;
1678
1679 // Constants (nulls/undefs) are handled in insertAssignPtrTypeIntrs()
1680 if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand)) {
1681 // However, we may have assumptions about the formal argument's type and
1682 // may have a need to insert a ptr cast for the actual parameter of this
1683 // call.
1684 Argument *CalledArg = CalledF->getArg(OpIdx);
1685 if (!GR->findDeducedElementType(CalledArg))
1686 continue;
1687 }
1688
1689 Type *ExpectedType =
1690 OpIdx < CalledArgTys.size() ? CalledArgTys[OpIdx] : nullptr;
1691 if (!ExpectedType && !DemangledName.empty())
1693 DemangledName, OpIdx, I->getContext());
1694 if (!ExpectedType || ExpectedType->isVoidTy())
1695 continue;
1696
1697 if (ExpectedType->isTargetExtTy() &&
1698 !isTypedPointerWrapper(cast<TargetExtType>(ExpectedType)))
1699 insertAssignPtrTypeTargetExt(cast<TargetExtType>(ExpectedType),
1700 ArgOperand, B);
1701 else
1702 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx, B);
1703 }
1704}
1705
1706Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &I) {
1707 SmallVector<Type *, 4> Types = {I.getType(), I.getOperand(0)->getType(),
1708 I.getOperand(1)->getType(),
1709 I.getOperand(2)->getType()};
1710 IRBuilder<> B(I.getParent());
1711 B.SetInsertPoint(&I);
1712 SmallVector<Value *> Args(I.op_begin(), I.op_end());
1713 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
1714 replaceAllUsesWithAndErase(B, &I, NewI);
1715 return NewI;
1716}
1717
1719SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &I) {
1720 IRBuilder<> B(I.getParent());
1721 B.SetInsertPoint(&I);
1722 SmallVector<Type *, 3> Types = {I.getType(), I.getVectorOperandType(),
1723 I.getIndexOperand()->getType()};
1724 SmallVector<Value *, 2> Args = {I.getVectorOperand(), I.getIndexOperand()};
1725 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});
1726 replaceAllUsesWithAndErase(B, &I, NewI);
1727 return NewI;
1728}
1729
1730Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &I) {
1731 IRBuilder<> B(I.getParent());
1732 B.SetInsertPoint(&I);
1733 SmallVector<Type *, 1> Types = {I.getInsertedValueOperand()->getType()};
1735 for (auto &Op : I.operands())
1736 if (isa<UndefValue>(Op))
1737 Args.push_back(UndefValue::get(B.getInt32Ty()));
1738 else
1739 Args.push_back(Op);
1740 for (auto &Op : I.indices())
1741 Args.push_back(B.getInt32(Op));
1742 Instruction *NewI =
1743 B.CreateIntrinsic(Intrinsic::spv_insertv, {Types}, {Args});
1744 replaceMemInstrUses(&I, NewI, B);
1745 return NewI;
1746}
1747
1748Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
1749 if (I.getAggregateOperand()->getType()->isAggregateType())
1750 return &I;
1751 IRBuilder<> B(I.getParent());
1752 B.SetInsertPoint(&I);
1754 for (auto &Op : I.operands())
1755 Args.push_back(Op);
1756 for (auto &Op : I.indices())
1757 Args.push_back(B.getInt32(Op));
1758 auto *NewI =
1759 B.CreateIntrinsic(Intrinsic::spv_extractv, {I.getType()}, {Args});
1760 replaceAllUsesWithAndErase(B, &I, NewI);
1761 return NewI;
1762}
1763
1764Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &I) {
1765 if (!I.getType()->isAggregateType())
1766 return &I;
1767 IRBuilder<> B(I.getParent());
1768 B.SetInsertPoint(&I);
1769 TrackConstants = false;
1770 const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
1772 TLI->getLoadMemOperandFlags(I, CurrF->getDataLayout());
1773 auto *NewI =
1774 B.CreateIntrinsic(Intrinsic::spv_load, {I.getOperand(0)->getType()},
1775 {I.getPointerOperand(), B.getInt16(Flags),
1776 B.getInt8(I.getAlign().value())});
1777 replaceMemInstrUses(&I, NewI, B);
1778 return NewI;
1779}
1780
1781Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {
1782 if (!AggrStores.contains(&I))
1783 return &I;
1784 IRBuilder<> B(I.getParent());
1785 B.SetInsertPoint(&I);
1786 TrackConstants = false;
1787 const auto *TLI = TM->getSubtargetImpl()->getTargetLowering();
1789 TLI->getStoreMemOperandFlags(I, CurrF->getDataLayout());
1790 auto *PtrOp = I.getPointerOperand();
1791 auto *NewI = B.CreateIntrinsic(
1792 Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()},
1793 {I.getValueOperand(), PtrOp, B.getInt16(Flags),
1794 B.getInt8(I.getAlign().value())});
1795 I.eraseFromParent();
1796 return NewI;
1797}
1798
1799Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &I) {
1800 Value *ArraySize = nullptr;
1801 if (I.isArrayAllocation()) {
1802 const SPIRVSubtarget *STI = TM->getSubtargetImpl(*I.getFunction());
1803 if (!STI->canUseExtension(
1804 SPIRV::Extension::SPV_INTEL_variable_length_array))
1806 "array allocation: this instruction requires the following "
1807 "SPIR-V extension: SPV_INTEL_variable_length_array",
1808 false);
1809 ArraySize = I.getArraySize();
1810 }
1811 IRBuilder<> B(I.getParent());
1812 B.SetInsertPoint(&I);
1813 TrackConstants = false;
1814 Type *PtrTy = I.getType();
1815 auto *NewI =
1816 ArraySize
1817 ? B.CreateIntrinsic(Intrinsic::spv_alloca_array,
1818 {PtrTy, ArraySize->getType()},
1819 {ArraySize, B.getInt8(I.getAlign().value())})
1820 : B.CreateIntrinsic(Intrinsic::spv_alloca, {PtrTy},
1821 {B.getInt8(I.getAlign().value())});
1822 replaceAllUsesWithAndErase(B, &I, NewI);
1823 return NewI;
1824}
1825
1826Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
1827 assert(I.getType()->isAggregateType() && "Aggregate result is expected");
1828 IRBuilder<> B(I.getParent());
1829 B.SetInsertPoint(&I);
1831 for (auto &Op : I.operands())
1832 Args.push_back(Op);
1833 Args.push_back(B.getInt32(
1834 static_cast<uint32_t>(getMemScope(I.getContext(), I.getSyncScopeID()))));
1835 Args.push_back(B.getInt32(
1836 static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering()))));
1837 Args.push_back(B.getInt32(
1838 static_cast<uint32_t>(getMemSemantics(I.getFailureOrdering()))));
1839 auto *NewI = B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
1840 {I.getPointerOperand()->getType()}, {Args});
1841 replaceMemInstrUses(&I, NewI, B);
1842 return NewI;
1843}
1844
1845Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &I) {
1846 IRBuilder<> B(I.getParent());
1847 B.SetInsertPoint(&I);
1848 B.CreateIntrinsic(Intrinsic::spv_unreachable, {}, {});
1849 return &I;
1850}
1851
1852void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
1853 IRBuilder<> &B) {
1854 // Skip special artifical variable llvm.global.annotations.
1855 if (GV.getName() == "llvm.global.annotations")
1856 return;
1857 Constant *Init = nullptr;
1858 if (hasInitializer(&GV)) {
1859 // Deduce element type and store results in Global Registry.
1860 // Result is ignored, because TypedPointerType is not supported
1861 // by llvm IR general logic.
1862 deduceElementTypeHelper(&GV, false);
1863 Init = GV.getInitializer();
1864 Type *Ty = isAggrConstForceInt32(Init) ? B.getInt32Ty() : Init->getType();
1865 Constant *Const = isAggrConstForceInt32(Init) ? B.getInt32(1) : Init;
1866 auto *InitInst = B.CreateIntrinsic(Intrinsic::spv_init_global,
1867 {GV.getType(), Ty}, {&GV, Const});
1868 InitInst->setArgOperand(1, Init);
1869 }
1870 if (!Init && GV.getNumUses() == 0)
1871 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);
1872}
1873
1874// Return true, if we can't decide what is the pointee type now and will get
1875// back to the question later. Return false is spv_assign_ptr_type is not needed
1876// or can be inserted immediately.
1877bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
1878 IRBuilder<> &B,
1879 bool UnknownElemTypeI8) {
1881 if (!isPointerTy(I->getType()) || !requireAssignType(I))
1882 return false;
1883
1885 if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {
1886 buildAssignPtr(B, ElemTy, I);
1887 return false;
1888 }
1889 return true;
1890}
1891
1892void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
1893 IRBuilder<> &B) {
1894 // TODO: extend the list of functions with known result types
1895 static StringMap<unsigned> ResTypeWellKnown = {
1896 {"async_work_group_copy", WellKnownTypes::Event},
1897 {"async_work_group_strided_copy", WellKnownTypes::Event},
1898 {"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
1899
1901
1902 bool IsKnown = false;
1903 if (auto *CI = dyn_cast<CallInst>(I)) {
1904 if (!CI->isIndirectCall() && !CI->isInlineAsm() &&
1905 CI->getCalledFunction() && !CI->getCalledFunction()->isIntrinsic()) {
1906 Function *CalledF = CI->getCalledFunction();
1907 std::string DemangledName =
1909 FPDecorationId DecorationId = FPDecorationId::NONE;
1910 if (DemangledName.length() > 0)
1911 DemangledName =
1912 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
1913 auto ResIt = ResTypeWellKnown.find(DemangledName);
1914 if (ResIt != ResTypeWellKnown.end()) {
1915 IsKnown = true;
1917 switch (ResIt->second) {
1918 case WellKnownTypes::Event:
1919 buildAssignType(B, TargetExtType::get(I->getContext(), "spirv.Event"),
1920 I);
1921 break;
1922 }
1923 }
1924 // check if a floating rounding mode or saturation info is present
1925 switch (DecorationId) {
1926 default:
1927 break;
1928 case FPDecorationId::SAT:
1930 break;
1931 case FPDecorationId::RTE:
1933 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE, B);
1934 break;
1935 case FPDecorationId::RTZ:
1937 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ, B);
1938 break;
1939 case FPDecorationId::RTP:
1941 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP, B);
1942 break;
1943 case FPDecorationId::RTN:
1945 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN, B);
1946 break;
1947 }
1948 }
1949 }
1950
1951 Type *Ty = I->getType();
1952 if (!IsKnown && !Ty->isVoidTy() && !isPointerTy(Ty) && requireAssignType(I)) {
1954 Type *TypeToAssign = Ty;
1955 if (auto *II = dyn_cast<IntrinsicInst>(I)) {
1956 if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
1957 II->getIntrinsicID() == Intrinsic::spv_undef) {
1958 auto It = AggrConstTypes.find(II);
1959 if (It == AggrConstTypes.end())
1960 report_fatal_error("Unknown composite intrinsic type");
1961 TypeToAssign = It->second;
1962 }
1963 }
1964 TypeToAssign = restoreMutatedType(GR, I, TypeToAssign);
1965 buildAssignType(B, TypeToAssign, I);
1966 }
1967 for (const auto &Op : I->operands()) {
1968 if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
1969 // Check GetElementPtrConstantExpr case.
1970 (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) {
1972 Type *OpTy = Op->getType();
1973 if (isa<UndefValue>(Op) && OpTy->isAggregateType()) {
1974 CallInst *AssignCI =
1975 buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,
1976 UndefValue::get(B.getInt32Ty()), {}, B);
1977 GR->addAssignPtrTypeInstr(Op, AssignCI);
1978 } else if (!isa<Instruction>(Op)) {
1979 Type *OpTy = Op->getType();
1980 Type *OpTyElem = getPointeeType(OpTy);
1981 if (OpTyElem) {
1982 buildAssignPtr(B, OpTyElem, Op);
1983 } else if (isPointerTy(OpTy)) {
1984 Type *ElemTy = GR->findDeducedElementType(Op);
1985 buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true), Op);
1986 } else {
1987 CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,
1988 {OpTy}, Op, Op, {}, B);
1989 GR->addAssignPtrTypeInstr(Op, AssignCI);
1990 }
1991 }
1992 }
1993 }
1994}
1995
1996void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
1997 IRBuilder<> &B) {
1998 if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
2000 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
2001 {I, MetadataAsValue::get(I->getContext(), MD)});
2002 }
2003}
2004
2005void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
2006 IRBuilder<> &B) {
2007 auto *II = dyn_cast<IntrinsicInst>(I);
2008 bool IsConstComposite =
2009 II && II->getIntrinsicID() == Intrinsic::spv_const_composite;
2010 if (IsConstComposite && TrackConstants) {
2012 auto t = AggrConsts.find(I);
2013 assert(t != AggrConsts.end());
2014 auto *NewOp =
2015 buildIntrWithMD(Intrinsic::spv_track_constant,
2016 {II->getType(), II->getType()}, t->second, I, {}, B);
2017 replaceAllUsesWith(I, NewOp, false);
2018 NewOp->setArgOperand(0, I);
2019 }
2020 bool IsPhi = isa<PHINode>(I), BPrepared = false;
2021 for (const auto &Op : I->operands()) {
2022 if (isa<PHINode>(I) || isa<SwitchInst>(I))
2023 TrackConstants = false;
2024 if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) {
2025 unsigned OpNo = Op.getOperandNo();
2026 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
2027 (II->paramHasAttr(OpNo, Attribute::ImmArg))))
2028 continue;
2029 if (!BPrepared) {
2030 IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
2031 : B.SetInsertPoint(I);
2032 BPrepared = true;
2033 }
2034 Type *OpTy = Op->getType();
2035 Value *OpTyVal = Op;
2036 if (OpTy->isTargetExtTy())
2037 OpTyVal = PoisonValue::get(OpTy);
2038 CallInst *NewOp =
2039 buildIntrWithMD(Intrinsic::spv_track_constant,
2040 {OpTy, OpTyVal->getType()}, Op, OpTyVal, {}, B);
2041 Type *OpElemTy = nullptr;
2042 if (!IsConstComposite && isPointerTy(OpTy) &&
2043 (OpElemTy = GR->findDeducedElementType(Op)) != nullptr &&
2044 OpElemTy != IntegerType::getInt8Ty(I->getContext())) {
2045 buildAssignPtr(B, IntegerType::getInt8Ty(I->getContext()), NewOp);
2046 SmallVector<Type *, 2> Types = {OpTy, OpTy};
2048 NewOp, buildMD(PoisonValue::get(OpElemTy)),
2049 B.getInt32(getPointerAddressSpace(OpTy))};
2050 CallInst *PtrCasted =
2051 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
2052 buildAssignPtr(B, OpElemTy, PtrCasted);
2053 NewOp = PtrCasted;
2054 }
2055 I->setOperand(OpNo, NewOp);
2056 }
2057 }
2058 emitAssignName(I, B);
2059}
2060
2061Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F,
2062 unsigned OpIdx) {
2063 std::unordered_set<Function *> FVisited;
2064 return deduceFunParamElementType(F, OpIdx, FVisited);
2065}
2066
2067Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
2068 Function *F, unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
2069 // maybe a cycle
2070 if (!FVisited.insert(F).second)
2071 return nullptr;
2072
2073 std::unordered_set<Value *> Visited;
2075 // search in function's call sites
2076 for (User *U : F->users()) {
2077 CallInst *CI = dyn_cast<CallInst>(U);
2078 if (!CI || OpIdx >= CI->arg_size())
2079 continue;
2080 Value *OpArg = CI->getArgOperand(OpIdx);
2081 if (!isPointerTy(OpArg->getType()))
2082 continue;
2083 // maybe we already know operand's element type
2084 if (Type *KnownTy = GR->findDeducedElementType(OpArg))
2085 return KnownTy;
2086 // try to deduce from the operand itself
2087 Visited.clear();
2088 if (Type *Ty = deduceElementTypeHelper(OpArg, Visited, false))
2089 return Ty;
2090 // search in actual parameter's users
2091 for (User *OpU : OpArg->users()) {
2092 Instruction *Inst = dyn_cast<Instruction>(OpU);
2093 if (!Inst || Inst == CI)
2094 continue;
2095 Visited.clear();
2096 if (Type *Ty = deduceElementTypeHelper(Inst, Visited, false))
2097 return Ty;
2098 }
2099 // check if it's a formal parameter of the outer function
2100 if (!CI->getParent() || !CI->getParent()->getParent())
2101 continue;
2102 Function *OuterF = CI->getParent()->getParent();
2103 if (FVisited.find(OuterF) != FVisited.end())
2104 continue;
2105 for (unsigned i = 0; i < OuterF->arg_size(); ++i) {
2106 if (OuterF->getArg(i) == OpArg) {
2107 Lookup.push_back(std::make_pair(OuterF, i));
2108 break;
2109 }
2110 }
2111 }
2112
2113 // search in function parameters
2114 for (auto &Pair : Lookup) {
2115 if (Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
2116 return Ty;
2117 }
2118
2119 return nullptr;
2120}
2121
2122void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
2123 IRBuilder<> &B) {
2124 B.SetInsertPointPastAllocas(F);
2125 for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
2126 Argument *Arg = F->getArg(OpIdx);
2127 if (!isUntypedPointerTy(Arg->getType()))
2128 continue;
2129 Type *ElemTy = GR->findDeducedElementType(Arg);
2130 if (ElemTy)
2131 continue;
2132 if (hasPointeeTypeAttr(Arg) &&
2133 (ElemTy = getPointeeTypeByAttr(Arg)) != nullptr) {
2134 buildAssignPtr(B, ElemTy, Arg);
2135 continue;
2136 }
2137 // search in function's call sites
2138 for (User *U : F->users()) {
2139 CallInst *CI = dyn_cast<CallInst>(U);
2140 if (!CI || OpIdx >= CI->arg_size())
2141 continue;
2142 Value *OpArg = CI->getArgOperand(OpIdx);
2143 if (!isPointerTy(OpArg->getType()))
2144 continue;
2145 // maybe we already know operand's element type
2146 if ((ElemTy = GR->findDeducedElementType(OpArg)) != nullptr)
2147 break;
2148 }
2149 if (ElemTy) {
2150 buildAssignPtr(B, ElemTy, Arg);
2151 continue;
2152 }
2153 if (HaveFunPtrs) {
2154 for (User *U : Arg->users()) {
2155 CallInst *CI = dyn_cast<CallInst>(U);
2156 if (CI && !isa<IntrinsicInst>(CI) && CI->isIndirectCall() &&
2157 CI->getCalledOperand() == Arg &&
2158 CI->getParent()->getParent() == CurrF) {
2160 deduceOperandElementTypeFunctionPointer(CI, Ops, ElemTy, false);
2161 if (ElemTy) {
2162 buildAssignPtr(B, ElemTy, Arg);
2163 break;
2164 }
2165 }
2166 }
2167 }
2168 }
2169}
2170
2171void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
2172 B.SetInsertPointPastAllocas(F);
2173 for (unsigned OpIdx = 0; OpIdx < F->arg_size(); ++OpIdx) {
2174 Argument *Arg = F->getArg(OpIdx);
2175 if (!isUntypedPointerTy(Arg->getType()))
2176 continue;
2177 Type *ElemTy = GR->findDeducedElementType(Arg);
2178 if (!ElemTy && (ElemTy = deduceFunParamElementType(F, OpIdx)) != nullptr) {
2179 if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Arg)) {
2181 updateAssignType(AssignCI, Arg, PoisonValue::get(ElemTy));
2182 propagateElemType(Arg, IntegerType::getInt8Ty(F->getContext()),
2183 VisitedSubst);
2184 } else {
2185 buildAssignPtr(B, ElemTy, Arg);
2186 }
2187 }
2188 }
2189}
2190
2192 SPIRVGlobalRegistry *GR) {
2193 FunctionType *FTy = F->getFunctionType();
2194 bool IsNewFTy = false;
2196 for (Argument &Arg : F->args()) {
2197 Type *ArgTy = Arg.getType();
2198 if (ArgTy->isPointerTy())
2199 if (Type *ElemTy = GR->findDeducedElementType(&Arg)) {
2200 IsNewFTy = true;
2201 ArgTy = getTypedPointerWrapper(ElemTy, getPointerAddressSpace(ArgTy));
2202 }
2203 ArgTys.push_back(ArgTy);
2204 }
2205 return IsNewFTy
2206 ? FunctionType::get(FTy->getReturnType(), ArgTys, FTy->isVarArg())
2207 : FTy;
2208}
2209
2210bool SPIRVEmitIntrinsics::processFunctionPointers(Module &M) {
2211 SmallVector<Function *> Worklist;
2212 for (auto &F : M) {
2213 if (F.isIntrinsic())
2214 continue;
2215 if (F.isDeclaration()) {
2216 for (User *U : F.users()) {
2217 CallInst *CI = dyn_cast<CallInst>(U);
2218 if (!CI || CI->getCalledFunction() != &F) {
2219 Worklist.push_back(&F);
2220 break;
2221 }
2222 }
2223 } else {
2224 if (F.user_empty())
2225 continue;
2226 Type *FPElemTy = GR->findDeducedElementType(&F);
2227 if (!FPElemTy)
2228 FPElemTy = getFunctionPointerElemType(&F, GR);
2229 for (User *U : F.users()) {
2230 IntrinsicInst *II = dyn_cast<IntrinsicInst>(U);
2231 if (!II || II->arg_size() != 3 || II->getOperand(0) != &F)
2232 continue;
2233 if (II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
2234 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
2235 updateAssignType(II, &F, PoisonValue::get(FPElemTy));
2236 break;
2237 }
2238 }
2239 }
2240 }
2241 if (Worklist.empty())
2242 return false;
2243
2244 std::string ServiceFunName = SPIRV_BACKEND_SERVICE_FUN_NAME;
2245 if (!getVacantFunctionName(M, ServiceFunName))
2247 "cannot allocate a name for the internal service function");
2248 LLVMContext &Ctx = M.getContext();
2249 Function *SF =
2250 Function::Create(FunctionType::get(Type::getVoidTy(Ctx), {}, false),
2251 GlobalValue::PrivateLinkage, ServiceFunName, M);
2253 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", SF);
2254 IRBuilder<> IRB(BB);
2255
2256 for (Function *F : Worklist) {
2258 for (const auto &Arg : F->args())
2259 Args.push_back(PoisonValue::get(Arg.getType()));
2260 IRB.CreateCall(F, Args);
2261 }
2262 IRB.CreateRetVoid();
2263
2264 return true;
2265}
2266
2267// Apply types parsed from demangled function declarations.
2268void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) {
2269 for (auto It : FDeclPtrTys) {
2270 Function *F = It.first;
2271 for (auto *U : F->users()) {
2272 CallInst *CI = dyn_cast<CallInst>(U);
2273 if (!CI || CI->getCalledFunction() != F)
2274 continue;
2275 unsigned Sz = CI->arg_size();
2276 for (auto [Idx, ElemTy] : It.second) {
2277 if (Idx >= Sz)
2278 continue;
2279 Value *Param = CI->getArgOperand(Idx);
2280 if (GR->findDeducedElementType(Param) || isa<GlobalValue>(Param))
2281 continue;
2282 if (Argument *Arg = dyn_cast<Argument>(Param)) {
2283 if (!hasPointeeTypeAttr(Arg)) {
2284 B.SetInsertPointPastAllocas(Arg->getParent());
2285 B.SetCurrentDebugLocation(DebugLoc());
2286 buildAssignPtr(B, ElemTy, Arg);
2287 }
2288 } else if (isa<Instruction>(Param)) {
2289 GR->addDeducedElementType(Param, ElemTy);
2290 // insertAssignTypeIntrs() will complete buildAssignPtr()
2291 } else {
2292 B.SetInsertPoint(CI->getParent()
2293 ->getParent()
2294 ->getEntryBlock()
2295 .getFirstNonPHIOrDbgOrAlloca());
2296 buildAssignPtr(B, ElemTy, Param);
2297 }
2298 CallInst *Ref = dyn_cast<CallInst>(Param);
2299 if (!Ref)
2300 continue;
2301 Function *RefF = Ref->getCalledFunction();
2302 if (!RefF || !isPointerTy(RefF->getReturnType()) ||
2303 GR->findDeducedElementType(RefF))
2304 continue;
2305 GR->addDeducedElementType(RefF, ElemTy);
2306 GR->addReturnType(
2308 ElemTy, getPointerAddressSpace(RefF->getReturnType())));
2309 }
2310 }
2311 }
2312}
2313
2314bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
2315 if (Func.isDeclaration())
2316 return false;
2317
2318 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(Func);
2319 GR = ST.getSPIRVGlobalRegistry();
2320
2321 if (!CurrF)
2322 HaveFunPtrs =
2323 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
2324
2325 CurrF = &Func;
2326 IRBuilder<> B(Func.getContext());
2327 AggrConsts.clear();
2328 AggrConstTypes.clear();
2329 AggrStores.clear();
2330
2331 processParamTypesByFunHeader(CurrF, B);
2332
2333 // StoreInst's operand type can be changed during the next transformations,
2334 // so we need to store it in the set. Also store already transformed types.
2335 for (auto &I : instructions(Func)) {
2336 StoreInst *SI = dyn_cast<StoreInst>(&I);
2337 if (!SI)
2338 continue;
2339 Type *ElTy = SI->getValueOperand()->getType();
2340 if (ElTy->isAggregateType() || ElTy->isVectorTy())
2341 AggrStores.insert(&I);
2342 }
2343
2344 B.SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin());
2345 for (auto &GV : Func.getParent()->globals())
2346 processGlobalValue(GV, B);
2347
2348 preprocessUndefs(B);
2349 preprocessCompositeConstants(B);
2351 for (auto &I : instructions(Func))
2352 Worklist.push_back(&I);
2353
2354 applyDemangledPtrArgTypes(B);
2355
2356 // Pass forward: use operand to deduce instructions result.
2357 for (auto &I : Worklist) {
2358 // Don't emit intrinsincs for convergence intrinsics.
2359 if (isConvergenceIntrinsic(I))
2360 continue;
2361
2362 bool Postpone = insertAssignPtrTypeIntrs(I, B, false);
2363 // if Postpone is true, we can't decide on pointee type yet
2364 insertAssignTypeIntrs(I, B);
2365 insertPtrCastOrAssignTypeInstr(I, B);
2367 // if instruction requires a pointee type set, let's check if we know it
2368 // already, and force it to be i8 if not
2369 if (Postpone && !GR->findAssignPtrTypeInstr(I))
2370 insertAssignPtrTypeIntrs(I, B, true);
2371
2372 if (auto *FPI = dyn_cast<ConstrainedFPIntrinsic>(I))
2373 useRoundingMode(FPI, B);
2374 }
2375
2376 // Pass backward: use instructions results to specify/update/cast operands
2377 // where needed.
2378 SmallPtrSet<Instruction *, 4> UncompleteRets;
2379 for (auto &I : llvm::reverse(instructions(Func)))
2380 deduceOperandElementType(&I, &UncompleteRets);
2381
2382 // Pass forward for PHIs only, their operands are not preceed the instruction
2383 // in meaning of `instructions(Func)`.
2384 for (BasicBlock &BB : Func)
2385 for (PHINode &Phi : BB.phis())
2386 if (isPointerTy(Phi.getType()))
2387 deduceOperandElementType(&Phi, nullptr);
2388
2389 for (auto *I : Worklist) {
2390 TrackConstants = true;
2391 if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
2393 // Visitors return either the original/newly created instruction for further
2394 // processing, nullptr otherwise.
2395 I = visit(*I);
2396 if (!I)
2397 continue;
2398
2399 // Don't emit intrinsics for convergence operations.
2400 if (isConvergenceIntrinsic(I))
2401 continue;
2402
2403 processInstrAfterVisit(I, B);
2404 }
2405
2406 return true;
2407}
2408
2409// Try to deduce a better type for pointers to untyped ptr.
2410bool SPIRVEmitIntrinsics::postprocessTypes(Module &M) {
2411 if (!GR || TodoTypeSz == 0)
2412 return false;
2413
2414 unsigned SzTodo = TodoTypeSz;
2416 for (auto [Op, Enabled] : TodoType) {
2417 // TODO: add isa<CallInst>(Op) to continue
2418 if (!Enabled || isa<GetElementPtrInst>(Op))
2419 continue;
2420 CallInst *AssignCI = GR->findAssignPtrTypeInstr(Op);
2421 Type *KnownTy = GR->findDeducedElementType(Op);
2422 if (!KnownTy || !AssignCI)
2423 continue;
2424 assert(Op == AssignCI->getArgOperand(0));
2425 // Try to improve the type deduced after all Functions are processed.
2426 if (auto *CI = dyn_cast<Instruction>(Op)) {
2427 CurrF = CI->getParent()->getParent();
2428 std::unordered_set<Value *> Visited;
2429 if (Type *ElemTy = deduceElementTypeHelper(Op, Visited, false, true)) {
2430 if (ElemTy != KnownTy) {
2432 propagateElemType(CI, ElemTy, VisitedSubst);
2433 eraseTodoType(Op);
2434 continue;
2435 }
2436 }
2437 }
2438 for (User *U : Op->users()) {
2439 Instruction *Inst = dyn_cast<Instruction>(U);
2440 if (Inst && !isa<IntrinsicInst>(Inst))
2441 ToProcess[Inst].insert(Op);
2442 }
2443 }
2444 if (TodoTypeSz == 0)
2445 return true;
2446
2447 for (auto &F : M) {
2448 CurrF = &F;
2449 SmallPtrSet<Instruction *, 4> UncompleteRets;
2450 for (auto &I : llvm::reverse(instructions(F))) {
2451 auto It = ToProcess.find(&I);
2452 if (It == ToProcess.end())
2453 continue;
2454 It->second.remove_if([this](Value *V) { return !isTodoType(V); });
2455 if (It->second.size() == 0)
2456 continue;
2457 deduceOperandElementType(&I, &UncompleteRets, &It->second, true);
2458 if (TodoTypeSz == 0)
2459 return true;
2460 }
2461 }
2462
2463 return SzTodo > TodoTypeSz;
2464}
2465
2466// Parse and store argument types of function declarations where needed.
2467void SPIRVEmitIntrinsics::parseFunDeclarations(Module &M) {
2468 for (auto &F : M) {
2469 if (!F.isDeclaration() || F.isIntrinsic())
2470 continue;
2471 // get the demangled name
2472 std::string DemangledName = getOclOrSpirvBuiltinDemangledName(F.getName());
2473 if (DemangledName.empty())
2474 continue;
2475 // allow only OpGroupAsyncCopy use case at the moment
2476 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(F);
2477 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
2478 DemangledName, ST.getPreferredInstructionSet());
2479 if (Opcode != SPIRV::OpGroupAsyncCopy)
2480 continue;
2481 // find pointer arguments
2483 for (unsigned OpIdx = 0; OpIdx < F.arg_size(); ++OpIdx) {
2484 Argument *Arg = F.getArg(OpIdx);
2485 if (isPointerTy(Arg->getType()) && !hasPointeeTypeAttr(Arg))
2486 Idxs.push_back(OpIdx);
2487 }
2488 if (!Idxs.size())
2489 continue;
2490 // parse function arguments
2491 LLVMContext &Ctx = F.getContext();
2493 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
2494 if (!TypeStrs.size())
2495 continue;
2496 // find type info for pointer arguments
2497 for (unsigned Idx : Idxs) {
2498 if (Idx >= TypeStrs.size())
2499 continue;
2500 if (Type *ElemTy =
2501 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
2503 !ElemTy->isTargetExtTy())
2504 FDeclPtrTys[&F].push_back(std::make_pair(Idx, ElemTy));
2505 }
2506 }
2507}
2508
2509bool SPIRVEmitIntrinsics::runOnModule(Module &M) {
2510 bool Changed = false;
2511
2512 parseFunDeclarations(M);
2513
2514 TodoType.clear();
2515 for (auto &F : M)
2516 Changed |= runOnFunction(F);
2517
2518 // Specify function parameters after all functions were processed.
2519 for (auto &F : M) {
2520 // check if function parameter types are set
2521 CurrF = &F;
2522 if (!F.isDeclaration() && !F.isIntrinsic()) {
2523 IRBuilder<> B(F.getContext());
2524 processParamTypes(&F, B);
2525 }
2526 }
2527
2528 CanTodoType = false;
2529 Changed |= postprocessTypes(M);
2530
2531 if (HaveFunPtrs)
2532 Changed |= processFunctionPointers(M);
2533
2534 return Changed;
2535}
2536
2538 return new SPIRVEmitIntrinsics(TM);
2539}
static unsigned getIntrinsicID(const SDNode *N)
aarch64 promote const
unsigned Intr
always inline
Expand Atomic instructions
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void replaceAllUsesWith(Value *Old, Value *New, SmallSet< BasicBlock *, 32 > &FreshBBs, bool IsHuge)
Replace all old uses with new ones, and push the updated BBs into FreshBBs.
return RetTy
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseSet and SmallDenseSet classes.
std::string Name
static bool runOnFunction(Function &F, bool PostInlining)
iv Induction Variable Users
Definition: IVUsers.cpp:48
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrConstForceInt32(const Value *V)
static Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static void emitAssignName(Instruction *I, IRBuilder<> &B)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void createRoundingModeDecoration(Instruction *I, unsigned RoundingModeDeco, IRBuilder<> &B)
static void createDecorationIntrinsic(Instruction *I, MDNode *Node, IRBuilder<> &B)
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB)
spirv structurize SPIRV
#define SPIRV_BACKEND_SERVICE_FUN_NAME
Definition: SPIRVUtils.h:388
static bool Enabled
Definition: Statistic.cpp:46
DEMANGLE_NAMESPACE_BEGIN bool starts_with(std::string_view self, char C) noexcept
static SymbolRef::Type getType(const Symbol *Sym)
Definition: TapiFile.cpp:39
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
an instruction to allocate memory on the stack
Definition: Instructions.h:63
Represent the analysis usage information of a pass.
This class represents an incoming formal argument to a Function.
Definition: Argument.h:31
const Function * getParent() const
Definition: Argument.h:43
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
An instruction that atomically checks whether a specified value is in a memory location,...
Definition: Instructions.h:501
static unsigned getPointerOperandIndex()
Definition: Instructions.h:631
static unsigned getPointerOperandIndex()
Definition: Instructions.h:872
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
Definition: BasicBlock.h:517
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:212
LLVMContext & getContext() const
Get the context in which this basic block lives.
Definition: BasicBlock.cpp:168
This class represents a no-op cast from one type to another.
static BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
Definition: Constants.cpp:1897
bool isInlineAsm() const
Check if this call is an inline asm statement.
Definition: InstrTypes.h:1408
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Definition: InstrTypes.h:1341
bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Definition: InstrTypes.h:1334
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1286
void setArgOperand(unsigned i, Value *v)
Definition: InstrTypes.h:1291
FunctionType * getFunctionType() const
Definition: InstrTypes.h:1199
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
Definition: InstrTypes.h:1277
unsigned arg_size() const
Definition: InstrTypes.h:1284
This class represents a function call, abstracting a target machine's calling convention.
static ConstantAsMetadata * get(Constant *C)
Definition: Metadata.h:532
This is an important base class in LLVM.
Definition: Constant.h:42
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Definition: Constants.cpp:373
This is the common base class for constrained floating point intrinsics.
std::optional< RoundingMode > getRoundingMode() const
This class represents an Operation in the Expression.
A debug info location.
Definition: DebugLoc.h:33
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:156
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition: DenseMap.h:226
iterator end()
Definition: DenseMap.h:84
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:211
Implements a dense probed hash-table based set.
Definition: DenseSet.h:278
This instruction extracts a single (scalar) element from a VectorType value.
This instruction extracts a struct member or array element value from an aggregate value.
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
Definition: Function.cpp:641
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:173
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
Definition: Function.cpp:373
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
Definition: Function.h:256
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:369
size_t arg_size() const
Definition: Function.h:901
Type * getReturnType() const
Returns the type of the ret val.
Definition: Function.h:221
Argument * getArg(unsigned i) const
Definition: Function.h:886
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
Definition: Instructions.h:933
static Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static unsigned getPointerOperandIndex()
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:295
@ PrivateLinkage
Like Internal, but omit from symbol table.
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:2705
Indirect Branch Instruction.
void addDestination(BasicBlock *Dest)
Add a destination.
This instruction inserts a single (scalar) element into a VectorType value.
This instruction inserts a struct field of array element value into an aggregate value.
Base class for instruction visitors.
Definition: InstVisitor.h:78
RetTy visitExtractElementInst(ExtractElementInst &I)
Definition: InstVisitor.h:191
RetTy visitInsertValueInst(InsertValueInst &I)
Definition: InstVisitor.h:195
RetTy visitUnreachableInst(UnreachableInst &I)
Definition: InstVisitor.h:244
RetTy visitAtomicCmpXchgInst(AtomicCmpXchgInst &I)
Definition: InstVisitor.h:171
RetTy visitBitCastInst(BitCastInst &I)
Definition: InstVisitor.h:187
RetTy visitSwitchInst(SwitchInst &I)
Definition: InstVisitor.h:235
RetTy visitExtractValueInst(ExtractValueInst &I)
Definition: InstVisitor.h:194
RetTy visitStoreInst(StoreInst &I)
Definition: InstVisitor.h:170
RetTy visitInsertElementInst(InsertElementInst &I)
Definition: InstVisitor.h:192
RetTy visitAllocaInst(AllocaInst &I)
Definition: InstVisitor.h:168
RetTy visitCallInst(CallInst &I)
Definition: InstVisitor.h:223
RetTy visitGetElementPtrInst(GetElementPtrInst &I)
Definition: InstVisitor.h:174
void visitInstruction(Instruction &I)
Definition: InstVisitor.h:283
RetTy visitLoadInst(LoadInst &I)
Definition: InstVisitor.h:169
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:94
Instruction * user_back()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
Definition: Instruction.h:169
A wrapper class for inspecting calls to intrinsic functions.
Definition: IntrinsicInst.h:48
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
An instruction for reading from memory.
Definition: Instructions.h:176
static unsigned getPointerOperandIndex()
Definition: Instructions.h:257
Metadata node.
Definition: Metadata.h:1073
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition: Metadata.h:1549
A single uniqued string.
Definition: Metadata.h:724
static MDString * get(LLVMContext &Context, StringRef Str)
Definition: Metadata.cpp:606
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition: Metadata.h:1506
Flags
Flags values. These may be or'd together.
Metadata wrapper in the Value hierarchy.
Definition: Metadata.h:180
static MetadataAsValue * get(LLVMContext &Context, Metadata *MD)
Definition: Metadata.cpp:103
Metadata * getMetadata() const
Definition: Metadata.h:197
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:251
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
Definition: PassRegistry.h:37
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:98
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
static PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Definition: Constants.cpp:1878
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
Type * findDeducedCompositeType(const Value *Val)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
void updateIfExistDeducedElementType(Value *OldVal, Value *NewVal, bool DeleteOld)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
void updateIfExistAssignPtrTypeInstr(Value *OldVal, Value *NewVal, bool DeleteOld)
Type * findDeducedElementType(const Value *Val)
CallInst * findAssignPtrTypeInstr(const Value *Val)
bool canUseExtension(SPIRV::Extension::Extension E) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:384
bool contains(ConstPtrType Ptr) const
Definition: SmallPtrSet.h:458
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:519
bool empty() const
Definition: SmallVector.h:81
size_t size() const
Definition: SmallVector.h:78
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
An instruction for storing to memory.
Definition: Instructions.h:292
static unsigned getPointerOperandIndex()
Definition: Instructions.h:383
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:128
iterator end()
Definition: StringMap.h:220
iterator find(StringRef Key)
Definition: StringMap.h:233
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:265
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition: Type.cpp:612
Multiway switch.
Class to represent target extensions types, which are generally unintrospectable from target-independ...
Definition: DerivedTypes.h:744
static 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:895
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
bool isVectorTy() const
True if this is an instance of VectorType.
Definition: Type.h:270
bool isPointerTy() const
True if this is an instance of PointerType.
Definition: Type.h:264
StringRef getTargetExtName() const
static Type * getVoidTy(LLVMContext &C)
bool isTargetExtTy() const
Return true if this is a target extension type.
Definition: Type.h:203
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition: Type.h:303
static IntegerType * getInt32Ty(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
Definition: Type.h:139
static bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
static TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Definition: Constants.cpp:1859
This function has undefined behavior.
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
op_range operands()
Definition: User.h:288
Value * getOperand(unsigned i) const
Definition: User.h:228
static ConstantAsMetadata * getConstant(Value *C)
Definition: Metadata.h:476
LLVM Value Representation.
Definition: Value.h:74
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:377
iterator_range< user_iterator > users()
Definition: Value.h:421
LLVMContext & getContext() const
All values hold a context through their type.
Definition: Value.cpp:1075
unsigned getNumUses() const
This method computes the number of uses of this Value.
Definition: Value.cpp:255
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:309
bool user_empty() const
Definition: Value.h:385
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:213
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition: DenseSet.h:193
const ParentTy * getParent() const
Definition: ilist_node.h:32
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ SPIR_KERNEL
Used for SPIR kernel functions.
Definition: CallingConv.h:144
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
ID ArrayRef< Type * > Tys
Definition: Intrinsics.h:102
std::string lookupBuiltinNameHelper(StringRef DemangledCall, FPDecorationId *DecorationId)
Parses the name part of the demangled builtin call.
Type * parseBuiltinCallArgumentType(StringRef TypeStr, LLVMContext &Ctx)
bool parseBuiltinTypeStr(SmallVector< StringRef, 10 > &BuiltinArgsTypeStrs, const StringRef DemangledCall, LLVMContext &Ctx)
std::tuple< int, unsigned, unsigned > mapBuiltinToOpcode(const StringRef DemangledCall, SPIRV::InstructionSet::InstructionSet Set)
Helper function for finding a builtin function attributes by a demangled function name.
Type * parseBuiltinCallArgumentBaseType(const StringRef DemangledCall, unsigned ArgIdx, LLVMContext &Ctx)
Parses the provided ArgIdx argument base type in the DemangledCall skeleton.
NodeAddr< PhiNode * > Phi
Definition: RDFGraph.h:390
NodeAddr< FuncNode * > Func
Definition: RDFGraph.h:393
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:329
bool getVacantFunctionName(Module &M, std::string &Name)
Definition: SPIRVUtils.cpp:711
void initializeSPIRVEmitIntrinsicsPass(PassRegistry &)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
Definition: SPIRVUtils.h:298
ModulePass * createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM)
unsigned getPointerAddressSpace(const Type *T)
Definition: SPIRVUtils.h:262
FPDecorationId
Definition: SPIRVUtils.h:409
bool isNestedPointer(const Type *Ty)
Definition: SPIRVUtils.cpp:774
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
Definition: SPIRVUtils.cpp:392
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
Definition: SPIRVUtils.h:293
bool isPointerTy(const Type *T)
Definition: SPIRVUtils.h:256
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
Definition: SPIRVUtils.cpp:281
@ Ref
The access may reference the value stored in memory.
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
Definition: SPIRVUtils.h:275
bool hasPointeeTypeAttr(Argument *Arg)
Definition: SPIRVUtils.h:270
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
Definition: SPIRVUtils.h:348
bool hasInitializer(const GlobalVariable *GV)
Definition: SPIRVUtils.h:241
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
Definition: SPIRVUtils.cpp:332
Type * getPointeeType(const Type *Ty)
Definition: SPIRVUtils.h:325
void addStringImm(const StringRef &Str, MCInst &Inst)
Definition: SPIRVUtils.cpp:54
bool isUntypedPointerTy(const Type *T)
Definition: SPIRVUtils.h:251
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
Definition: SPIRVUtils.cpp:263