27#include "llvm/IR/IntrinsicsSPIRV.h"
37#include <unordered_set>
62 cl::desc(
"Emit OpName for all instructions"),
66#define GET_BuiltinGroup_DECL
67#include "SPIRVGenTables.inc"
72class GlobalVariableUsers {
73 template <
typename T1,
typename T2>
74 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
76 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
78 void collectGlobalUsers(
79 const GlobalVariable *GV,
80 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
81 &GlobalIsUsedByGlobal) {
83 while (!
Stack.empty()) {
87 GlobalIsUsedByFun[GV].insert(
I->getFunction());
92 GlobalIsUsedByGlobal[GV].insert(UserGV);
97 Stack.append(
C->user_begin(),
C->user_end());
101 bool propagateGlobalToGlobalUsers(
102 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
103 &GlobalIsUsedByGlobal) {
106 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
107 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
108 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
109 auto It = GlobalIsUsedByGlobal.find(UserGV);
110 if (It == GlobalIsUsedByGlobal.end())
118 void propagateGlobalToFunctionReferences(
119 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
120 &GlobalIsUsedByGlobal) {
121 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
122 auto &UserFunctions = GlobalIsUsedByFun[GV];
123 for (
const GlobalVariable *UserGV : UserGlobals) {
124 auto It = GlobalIsUsedByFun.find(UserGV);
125 if (It == GlobalIsUsedByFun.end())
136 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
137 GlobalIsUsedByGlobal;
138 GlobalIsUsedByFun.clear();
139 for (GlobalVariable &GV :
M.globals())
140 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
143 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
146 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
149 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
150 const FunctionSetType &
151 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
152 auto It = GlobalIsUsedByFun.find(&GV);
153 if (It != GlobalIsUsedByFun.end())
156 static const FunctionSetType
Empty{};
161static bool isaGEP(
const Value *V) {
167static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
173 return AT->getNumElements();
179class SPIRVEmitIntrinsics
181 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
182 const SPIRVTargetMachine &TM;
183 SPIRVGlobalRegistry *GR =
nullptr;
185 bool TrackConstants =
true;
186 bool HaveFunPtrs =
false;
187 DenseMap<Instruction *, Constant *> AggrConsts;
188 DenseMap<Instruction *, Type *> AggrConstTypes;
189 DenseSet<Instruction *> AggrStores;
190 SmallPtrSet<Instruction *, 8> DeletedInstrs;
191 GlobalVariableUsers GVUsers;
192 std::unordered_set<Value *> Named;
195 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
198 bool CanTodoType =
true;
199 unsigned TodoTypeSz = 0;
200 DenseMap<Value *, bool> TodoType;
201 void insertTodoType(
Value *
Op) {
203 if (CanTodoType && !isaGEP(
Op)) {
204 auto It = TodoType.try_emplace(
Op,
true);
209 void eraseTodoType(
Value *
Op) {
210 auto It = TodoType.find(
Op);
211 if (It != TodoType.end() && It->second) {
219 auto It = TodoType.find(
Op);
220 return It != TodoType.end() && It->second;
224 std::unordered_set<Instruction *> TypeValidated;
227 enum WellKnownTypes { Event };
230 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
231 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
232 Type *deduceElementTypeHelper(
Value *
I, std::unordered_set<Value *> &Visited,
233 bool UnknownElemTypeI8,
234 bool IgnoreKnownType =
false);
235 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
236 bool UnknownElemTypeI8);
237 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
238 std::unordered_set<Value *> &Visited,
239 bool UnknownElemTypeI8);
241 std::unordered_set<Value *> &Visited,
242 bool UnknownElemTypeI8);
244 bool UnknownElemTypeI8);
247 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
248 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
249 std::unordered_set<Value *> &Visited,
250 bool UnknownElemTypeI8);
253 void deduceOperandElementType(Instruction *
I,
254 SmallPtrSet<Instruction *, 4> *IncompleteRets,
255 const SmallPtrSet<Value *, 4> *AskOps =
nullptr,
256 bool IsPostprocessing =
false);
260 void simplifyNullAddrSpaceCasts();
262 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
263 bool IsPostprocessing);
265 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
267 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
268 bool UnknownElemTypeI8);
270 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
272 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
273 Type *ExpectedElementType,
274 unsigned OperandToReplace,
276 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
277 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
279 void insertConstantsForFPFastMathDefault(
Module &M);
281 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
283 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
284 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
285 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx,
286 std::unordered_set<Function *> &FVisited);
288 bool deduceOperandElementTypeCalledFunction(
290 Type *&KnownElemTy,
bool &Incomplete);
291 void deduceOperandElementTypeFunctionPointer(
293 Type *&KnownElemTy,
bool IsPostprocessing);
294 bool deduceOperandElementTypeFunctionRet(
295 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
296 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
299 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
300 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
301 DenseMap<Function *, CallInst *> Ptrcasts);
303 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
306 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
307 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
308 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
309 std::unordered_set<Value *> &Visited,
310 DenseMap<Function *, CallInst *> Ptrcasts);
313 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
314 Instruction *Dest,
bool DeleteOld =
true);
318 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
321 bool postprocessTypes(
Module &M);
322 bool processFunctionPointers(
Module &M);
323 void parseFunDeclarations(
Module &M);
324 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
325 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
326 bool convertMaskedMemIntrinsics(
Module &M);
327 void preprocessBoolVectorBitcasts(Function &
F);
329 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
346 bool walkLogicalAccessChain(
347 GetElementPtrInst &
GEP,
348 const std::function<
void(
Type *PointedType, uint64_t Index)>
351 uint64_t Multiplier)> &OnDynamicIndexing);
353 bool walkLogicalAccessChainDynamic(
354 Type *CurType,
Value *Operand, uint64_t Multiplier,
355 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
356 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing);
358 bool walkLogicalAccessChainConstant(
360 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing);
366 Type *getGEPType(GetElementPtrInst *
GEP);
373 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
375 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
379 SPIRVEmitIntrinsics(
const SPIRVTargetMachine &TM) : ModulePass(ID), TM(TM) {}
382 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
385 Instruction *visitInsertElementInst(InsertElementInst &
I);
386 Instruction *visitExtractElementInst(ExtractElementInst &
I);
388 Instruction *visitExtractValueInst(ExtractValueInst &
I);
392 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
396 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
398 bool runOnModule(
Module &M)
override;
400 void getAnalysisUsage(AnalysisUsage &AU)
const override {
401 ModulePass::getAnalysisUsage(AU);
407 Intrinsic::experimental_convergence_loop,
408 Intrinsic::experimental_convergence_anchor>());
411bool expectIgnoredInIRTranslation(
const Instruction *
I) {
413 Intrinsic::spv_resource_handlefrombinding,
414 Intrinsic::spv_resource_getpointer>());
421 return getPointerRoot(V);
427char SPIRVEmitIntrinsics::ID = 0;
430 "SPIRV emit intrinsics",
false,
false)
444 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
451 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
457 B.SetCurrentDebugLocation(
I->getDebugLoc());
458 if (
I->getType()->isVoidTy())
459 B.SetInsertPoint(
I->getNextNode());
461 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
471 if (
I->getType()->isTokenTy())
473 "does not support token type",
478 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
479 expectIgnoredInIRTranslation(
I))
490 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
501 std::vector<Value *> Args = {
504 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
507void SPIRVEmitIntrinsics::replaceAllUsesWith(
Value *Src,
Value *Dest,
511 if (isTodoType(Src)) {
514 insertTodoType(Dest);
518void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
523 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
524 Src->eraseFromParent();
527 if (Named.insert(Dest).second)
552Type *SPIRVEmitIntrinsics::reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
553 bool IsPostprocessing) {
568 if (UnknownElemTypeI8) {
569 if (!IsPostprocessing)
577CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *
F,
Value *
Op,
585 B.SetInsertPointPastAllocas(OpA->getParent());
588 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
590 Type *OpTy =
Op->getType();
594 CallInst *PtrCasted =
595 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
600void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
602 DenseMap<Function *, CallInst *> Ptrcasts) {
604 CallInst *PtrCastedI =
nullptr;
605 auto It = Ptrcasts.
find(
F);
606 if (It == Ptrcasts.
end()) {
607 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
608 Ptrcasts[
F] = PtrCastedI;
610 PtrCastedI = It->second;
612 I->replaceUsesOfWith(
Op, PtrCastedI);
615void SPIRVEmitIntrinsics::propagateElemType(
617 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
618 DenseMap<Function *, CallInst *> Ptrcasts;
620 for (
auto *U :
Users) {
623 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
628 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
629 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
633void SPIRVEmitIntrinsics::propagateElemTypeRec(
635 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
636 std::unordered_set<Value *> Visited;
637 DenseMap<Function *, CallInst *> Ptrcasts;
638 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
639 std::move(Ptrcasts));
642void SPIRVEmitIntrinsics::propagateElemTypeRec(
644 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
645 std::unordered_set<Value *> &Visited,
646 DenseMap<Function *, CallInst *> Ptrcasts) {
647 if (!Visited.insert(
Op).second)
650 for (
auto *U :
Users) {
653 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
658 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
659 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
667SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
668 bool UnknownElemTypeI8) {
669 std::unordered_set<Value *> Visited;
670 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
674Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
675 Type *ValueTy,
Value *Operand, std::unordered_set<Value *> &Visited,
676 bool UnknownElemTypeI8) {
681 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
692Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
693 Value *
Op, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8) {
705 for (User *OpU :
Op->users()) {
707 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
720 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
729Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I,
730 bool UnknownElemTypeI8) {
731 std::unordered_set<Value *> Visited;
732 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
735void SPIRVEmitIntrinsics::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
Type *RefTy,
736 bool UnknownElemTypeI8) {
738 if (!UnknownElemTypeI8)
745bool SPIRVEmitIntrinsics::walkLogicalAccessChainDynamic(
746 Type *CurType,
Value *Operand, uint64_t Multiplier,
747 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
748 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
754 if (
ST->getNumElements() > 0) {
755 CurType =
ST->getElementType(0);
756 OnLiteralIndexing(CurType, 0);
766 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
767 return AT ==
nullptr;
770bool SPIRVEmitIntrinsics::walkLogicalAccessChainConstant(
772 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
777 uint32_t EltTypeSize =
DL.getTypeSizeInBits(AT->getElementType()) / 8;
781 CurType = AT->getElementType();
782 OnLiteralIndexing(CurType, Index);
784 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
787 const auto &STL =
DL.getStructLayout(ST);
788 unsigned Element = STL->getElementContainingOffset(
Offset);
789 Offset -= STL->getElementOffset(Element);
790 CurType =
ST->getElementType(Element);
791 OnLiteralIndexing(CurType, Element);
793 Type *EltTy = VT->getElementType();
794 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
795 assert(EltSizeBits % 8 == 0 &&
796 "Element type size in bits must be a multiple of 8.");
797 uint32_t EltTypeSize = EltSizeBits / 8;
802 OnLiteralIndexing(CurType, Index);
812bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
813 GetElementPtrInst &
GEP,
814 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
815 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
818 std::optional<uint64_t> MultiplierOpt =
819 getByteAddressingMultiplier(
GEP.getSourceElementType());
820 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
821 uint64_t Multiplier = *MultiplierOpt;
824 Value *Src = getPointerRoot(
GEP.getPointerOperand());
825 Type *CurType = deduceElementType(Src,
true);
829 return walkLogicalAccessChainConstant(
830 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
832 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
833 OnLiteralIndexing, OnDynamicIndexing);
837SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP) {
840 B.SetInsertPoint(&
GEP);
842 std::vector<Value *> Indices;
843 Indices.push_back(ConstantInt::get(
844 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
845 walkLogicalAccessChain(
847 [&Indices, &
B](
Type *EltType, uint64_t Index) {
849 ConstantInt::get(
B.getInt64Ty(), Index,
false));
852 uint64_t Multiplier) {
854 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
856 if (Multiplier == EltTypeSize) {
858 }
else if (EltTypeSize % Multiplier == 0) {
861 EltTypeSize / Multiplier,
865 ConstantInt::get(
Offset->getType(), Multiplier,
868 Index =
B.CreateUDiv(Index,
869 ConstantInt::get(
Offset->getType(), EltTypeSize,
873 Indices.push_back(Index);
877 SmallVector<Value *, 4>
Args;
878 Args.push_back(
B.getInt1(
GEP.isInBounds()));
879 Args.push_back(
GEP.getOperand(0));
881 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
882 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
886Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *
GEP) {
888 Type *CurType =
GEP->getResultElementType();
890 bool Interrupted = walkLogicalAccessChain(
891 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
892 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
894 return Interrupted ?
GEP->getResultElementType() : CurType;
897Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *
Ref) {
898 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
900 return getGEPTypeLogical(
Ref);
907 Ty =
Ref->getSourceElementType();
911 Ty =
Ref->getResultElementType();
916Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
917 Value *
I, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8,
918 bool IgnoreKnownType) {
924 if (!IgnoreKnownType)
929 if (!Visited.insert(
I).second)
936 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
938 Ty = getGEPType(
Ref);
940 Ty = SGEP->getResultElementType();
945 KnownTy =
Op->getType();
947 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
950 Ty = SPIRV::getOriginalFunctionType(*Fn);
953 Ty = deduceElementTypeByValueDeep(
955 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
959 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
961 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
963 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
965 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
967 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
972 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
976 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
978 Type *BestTy =
nullptr;
980 DenseMap<Type *, unsigned> PhiTys;
981 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
982 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
989 if (It.first->second > MaxN) {
990 MaxN = It.first->second;
998 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
999 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1004 static StringMap<unsigned> ResTypeByArg = {
1008 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1009 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1010 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1011 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1012 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1013 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1017 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1019 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1020 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1021 for (User *U :
II->users()) {
1026 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1028 Ty = HandleType->getTypeParameter(0);
1040 }
else if (
II &&
II->getIntrinsicID() ==
1041 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1045 std::string DemangledName =
1047 if (DemangledName.length() > 0)
1048 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1049 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1050 if (AsArgIt != ResTypeByArg.
end())
1051 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1052 Visited, UnknownElemTypeI8);
1059 if (Ty && !IgnoreKnownType) {
1070Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1071 bool UnknownElemTypeI8) {
1072 std::unordered_set<Value *> Visited;
1073 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1076Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
1077 User *U,
Type *OrigTy, std::unordered_set<Value *> &Visited,
1078 bool UnknownElemTypeI8) {
1087 if (!Visited.insert(U).second)
1092 bool Change =
false;
1093 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1095 assert(
Op &&
"Operands should not be null.");
1096 Type *OpTy =
Op->getType();
1099 if (
Type *NestedTy =
1100 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1107 Change |= Ty != OpTy;
1115 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1116 Type *OpTy = ArrTy->getElementType();
1119 if (
Type *NestedTy =
1120 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1127 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1133 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1134 Type *OpTy = VecTy->getElementType();
1137 if (
Type *NestedTy =
1138 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1145 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1155Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I,
bool UnknownElemTypeI8) {
1156 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1158 if (!UnknownElemTypeI8)
1161 return IntegerType::getInt8Ty(
I->getContext());
1165 Value *PointerOperand) {
1171 return I->getType();
1179bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1181 Type *&KnownElemTy,
bool &Incomplete) {
1185 std::string DemangledName =
1187 if (DemangledName.length() > 0 &&
1189 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1190 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1191 DemangledName,
ST.getPreferredInstructionSet());
1192 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1193 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1199 KnownElemTy = ElemTy;
1200 Ops.push_back(std::make_pair(
Op, i));
1202 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1209 case SPIRV::OpAtomicFAddEXT:
1210 case SPIRV::OpAtomicFMinEXT:
1211 case SPIRV::OpAtomicFMaxEXT:
1212 case SPIRV::OpAtomicLoad:
1213 case SPIRV::OpAtomicCompareExchangeWeak:
1214 case SPIRV::OpAtomicCompareExchange:
1215 case SPIRV::OpAtomicExchange:
1216 case SPIRV::OpAtomicIAdd:
1217 case SPIRV::OpAtomicISub:
1218 case SPIRV::OpAtomicOr:
1219 case SPIRV::OpAtomicXor:
1220 case SPIRV::OpAtomicAnd:
1221 case SPIRV::OpAtomicUMin:
1222 case SPIRV::OpAtomicUMax:
1223 case SPIRV::OpAtomicSMin:
1224 case SPIRV::OpAtomicSMax: {
1229 Incomplete = isTodoType(
Op);
1230 Ops.push_back(std::make_pair(
Op, 0));
1232 case SPIRV::OpAtomicStore: {
1241 Incomplete = isTodoType(
Op);
1242 Ops.push_back(std::make_pair(
Op, 0));
1251void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1253 Type *&KnownElemTy,
bool IsPostprocessing) {
1257 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1258 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1259 bool IsNewFTy =
false, IsIncomplete =
false;
1262 Type *ArgTy = Arg->getType();
1267 if (isTodoType(Arg))
1268 IsIncomplete =
true;
1270 IsIncomplete =
true;
1273 ArgTy = FTy->getFunctionParamType(ParmIdx);
1277 Type *RetTy = FTy->getReturnType();
1284 IsIncomplete =
true;
1286 IsIncomplete =
true;
1289 if (!IsPostprocessing && IsIncomplete)
1292 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1295bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1296 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1297 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
1309 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1310 for (User *U :
F->users()) {
1318 propagateElemType(CI, PrevElemTy, VisitedSubst);
1328 for (Instruction *IncompleteRetI : *IncompleteRets)
1329 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1331 }
else if (IncompleteRets) {
1334 TypeValidated.insert(
I);
1342void SPIRVEmitIntrinsics::deduceOperandElementType(
1343 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1344 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing) {
1346 Type *KnownElemTy =
nullptr;
1347 bool Incomplete =
false;
1353 Incomplete = isTodoType(
I);
1354 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1357 Ops.push_back(std::make_pair(
Op, i));
1363 Incomplete = isTodoType(
I);
1364 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1371 Incomplete = isTodoType(
I);
1372 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1376 KnownElemTy =
Ref->getSourceElementType();
1377 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1382 KnownElemTy =
Ref->getBaseType();
1383 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1386 KnownElemTy =
I->getType();
1392 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1396 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1401 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1409 Incomplete = isTodoType(
Ref->getPointerOperand());
1410 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1418 Incomplete = isTodoType(
Ref->getPointerOperand());
1419 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1425 Incomplete = isTodoType(
I);
1426 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1429 Ops.push_back(std::make_pair(
Op, i));
1437 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1438 IsPostprocessing, KnownElemTy,
Op,
1441 Incomplete = isTodoType(CurrF);
1442 Ops.push_back(std::make_pair(
Op, 0));
1448 bool Incomplete0 = isTodoType(Op0);
1449 bool Incomplete1 = isTodoType(Op1);
1451 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1453 : GR->findDeducedElementType(Op0);
1455 KnownElemTy = ElemTy0;
1456 Incomplete = Incomplete0;
1457 Ops.push_back(std::make_pair(Op1, 1));
1458 }
else if (ElemTy1) {
1459 KnownElemTy = ElemTy1;
1460 Incomplete = Incomplete1;
1461 Ops.push_back(std::make_pair(Op0, 0));
1465 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1466 else if (HaveFunPtrs)
1467 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1472 if (!KnownElemTy ||
Ops.size() == 0)
1477 for (
auto &OpIt :
Ops) {
1481 Type *AskTy =
nullptr;
1482 CallInst *AskCI =
nullptr;
1483 if (IsPostprocessing && AskOps) {
1489 if (Ty == KnownElemTy)
1492 Type *OpTy =
Op->getType();
1493 if (
Op->hasUseList() &&
1500 else if (!IsPostprocessing)
1504 if (AssignCI ==
nullptr) {
1513 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1514 std::make_pair(
I,
Op)};
1515 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1519 CallInst *PtrCastI =
1520 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1521 if (OpIt.second == std::numeric_limits<unsigned>::max())
1524 I->setOperand(OpIt.second, PtrCastI);
1527 TypeValidated.insert(
I);
1530void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1535 if (isAssignTypeInstr(U)) {
1536 B.SetInsertPoint(U);
1537 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1538 CallInst *AssignCI =
1539 B.CreateIntrinsic(Intrinsic::spv_assign_type, {
New->getType()},
Args);
1541 U->eraseFromParent();
1544 U->replaceUsesOfWith(Old, New);
1546 if (
Phi->getType() !=
New->getType()) {
1547 Phi->mutateType(
New->getType());
1548 Phi->replaceUsesOfWith(Old, New);
1551 for (User *PhiUser :
Phi->users())
1554 for (ExtractValueInst *EV : EVUsers) {
1555 B.SetInsertPoint(EV);
1557 for (
unsigned Idx : EV->indices())
1558 Args.push_back(
B.getInt32(Idx));
1560 B.CreateIntrinsic(Intrinsic::spv_extractv, {EV->getType()},
Args);
1561 EV->replaceAllUsesWith(NewEV);
1562 DeletedInstrs.
insert(EV);
1563 EV->eraseFromParent();
1566 Phi->replaceUsesOfWith(Old, New);
1572 New->copyMetadata(*Old);
1576void SPIRVEmitIntrinsics::preprocessUndefs(
IRBuilder<> &
B) {
1577 std::queue<Instruction *> Worklist;
1581 while (!Worklist.empty()) {
1583 bool BPrepared =
false;
1586 for (
auto &
Op :
I->operands()) {
1588 if (!AggrUndef || !
Op->getType()->isAggregateType())
1595 auto *IntrUndef =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
1596 Worklist.push(IntrUndef);
1597 I->replaceUsesOfWith(
Op, IntrUndef);
1598 AggrConsts[IntrUndef] = AggrUndef;
1599 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1608void SPIRVEmitIntrinsics::simplifyNullAddrSpaceCasts() {
1612 ASC->replaceAllUsesWith(
1614 ASC->eraseFromParent();
1618void SPIRVEmitIntrinsics::preprocessCompositeConstants(
IRBuilder<> &
B) {
1619 std::queue<Instruction *> Worklist;
1623 while (!Worklist.empty()) {
1624 auto *
I = Worklist.front();
1627 bool KeepInst =
false;
1628 for (
const auto &
Op :
I->operands()) {
1630 Type *ResTy =
nullptr;
1633 ResTy = COp->getType();
1645 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1650 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1651 Args.push_back(COp->getElementAsConstant(i));
1657 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1663 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1664 :
B.SetInsertPoint(
I);
1668 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {
Args});
1672 AggrConsts[CI] = AggrConst;
1673 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1685 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1690 unsigned RoundingModeDeco,
1697 ConstantInt::get(
Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1706 MDNode *SaturatedConversionNode =
1708 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1728 MDString *ConstraintString =
1737 B.SetInsertPoint(&
Call);
1738 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1743void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1746 if (!
RM.has_value())
1748 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1749 switch (
RM.value()) {
1753 case RoundingMode::NearestTiesToEven:
1754 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1756 case RoundingMode::TowardNegative:
1757 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1759 case RoundingMode::TowardPositive:
1760 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1762 case RoundingMode::TowardZero:
1763 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1765 case RoundingMode::Dynamic:
1766 case RoundingMode::NearestTiesToAway:
1770 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1776Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &
I) {
1780 B.SetInsertPoint(&
I);
1781 SmallVector<Value *, 4>
Args;
1783 Args.push_back(
I.getCondition());
1786 for (
auto &Case :
I.cases()) {
1787 Args.push_back(Case.getCaseValue());
1788 BBCases.
push_back(Case.getCaseSuccessor());
1791 CallInst *NewI =
B.CreateIntrinsic(Intrinsic::spv_switch,
1792 {
I.getOperand(0)->getType()}, {
Args});
1796 I.eraseFromParent();
1799 B.SetInsertPoint(ParentBB);
1800 IndirectBrInst *BrI =
B.CreateIndirectBr(
1803 for (BasicBlock *BBCase : BBCases)
1812Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &
I) {
1818 B.SetInsertPoint(&
I);
1820 SmallVector<Value *, 4>
Args;
1821 Args.push_back(
B.getInt1(
true));
1822 Args.push_back(
I.getOperand(0));
1823 Args.push_back(
B.getInt32(0));
1824 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1825 Args.push_back(SGEP->getIndexOperand(J));
1827 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, Types, Args);
1828 replaceAllUsesWithAndErase(
B, &
I, NewI);
1832Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &
I) {
1834 B.SetInsertPoint(&
I);
1842 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
1843 return buildLogicalAccessChainFromGEP(
I);
1848 Value *PtrOp =
I.getPointerOperand();
1849 Type *SrcElemTy =
I.getSourceElementType();
1850 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
1853 if (ArrTy->getElementType() == SrcElemTy) {
1855 Type *FirstIdxType =
I.getOperand(1)->getType();
1856 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
1857 for (
Value *Idx :
I.indices())
1861 SmallVector<Value *, 4>
Args;
1862 Args.push_back(
B.getInt1(
I.isInBounds()));
1863 Args.push_back(
I.getPointerOperand());
1866 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
1867 replaceAllUsesWithAndErase(
B, &
I, NewI);
1874 SmallVector<Value *, 4>
Args;
1875 Args.push_back(
B.getInt1(
I.isInBounds()));
1877 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
1878 replaceAllUsesWithAndErase(
B, &
I, NewI);
1882Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &
I) {
1884 B.SetInsertPoint(&
I);
1893 I.eraseFromParent();
1899 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_bitcast, {
Types}, {
Args});
1900 replaceAllUsesWithAndErase(
B, &
I, NewI);
1904void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
1906 Type *VTy =
V->getType();
1911 if (ElemTy != AssignedType)
1924 if (CurrentType == AssignedType)
1931 " for value " +
V->getName(),
1939void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
1940 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
1942 TypeValidated.insert(
I);
1945 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
1946 if (PointerElemTy == ExpectedElementType ||
1952 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
1954 bool FirstPtrCastOrAssignPtrType =
true;
1960 for (
auto User :
Pointer->users()) {
1963 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
1964 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
1965 II->getOperand(0) != Pointer)
1970 FirstPtrCastOrAssignPtrType =
false;
1971 if (
II->getOperand(1) != VMD ||
1978 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
1983 if (
II->getParent() !=
I->getParent())
1986 I->setOperand(OperandToReplace,
II);
1992 if (FirstPtrCastOrAssignPtrType) {
1997 }
else if (isTodoType(Pointer)) {
1998 eraseTodoType(Pointer);
2006 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2007 std::make_pair(
I, Pointer)};
2009 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2021 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2027void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2032 replacePointerOperandWithPtrCast(
2033 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2039 Type *OpTy =
Op->getType();
2042 if (OpTy ==
Op->getType())
2043 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2044 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2049 Type *OpTy = LI->getType();
2054 Type *NewOpTy = OpTy;
2055 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2056 if (OpTy == NewOpTy)
2057 insertTodoType(Pointer);
2060 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2065 Type *OpTy =
nullptr;
2077 OpTy = GEPI->getSourceElementType();
2079 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2081 insertTodoType(Pointer);
2093 std::string DemangledName =
2097 bool HaveTypes =
false;
2115 for (User *U : CalledArg->
users()) {
2117 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2123 HaveTypes |= ElemTy !=
nullptr;
2128 if (DemangledName.empty() && !HaveTypes)
2146 Type *ExpectedType =
2148 if (!ExpectedType && !DemangledName.empty())
2149 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2150 DemangledName,
OpIdx,
I->getContext());
2151 if (!ExpectedType || ExpectedType->
isVoidTy())
2159 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2163Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &
I) {
2170 I.getOperand(1)->getType(),
2171 I.getOperand(2)->getType()};
2173 B.SetInsertPoint(&
I);
2175 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
2176 replaceAllUsesWithAndErase(
B, &
I, NewI);
2181SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &
I) {
2188 B.SetInsertPoint(&
I);
2190 I.getIndexOperand()->getType()};
2191 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2192 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
2193 replaceAllUsesWithAndErase(
B, &
I, NewI);
2197Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &
I) {
2199 B.SetInsertPoint(&
I);
2202 Value *AggregateOp =
I.getAggregateOperand();
2206 Args.push_back(AggregateOp);
2207 Args.push_back(
I.getInsertedValueOperand());
2208 for (
auto &
Op :
I.indices())
2209 Args.push_back(
B.getInt32(
Op));
2211 B.CreateIntrinsic(Intrinsic::spv_insertv, {
Types}, {
Args});
2212 replaceMemInstrUses(&
I, NewI,
B);
2216Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &
I) {
2217 if (
I.getAggregateOperand()->getType()->isAggregateType())
2220 B.SetInsertPoint(&
I);
2222 for (
auto &
Op :
I.indices())
2223 Args.push_back(
B.getInt32(
Op));
2225 B.CreateIntrinsic(Intrinsic::spv_extractv, {
I.getType()}, {
Args});
2226 replaceAllUsesWithAndErase(
B, &
I, NewI);
2230Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &
I) {
2231 if (!
I.getType()->isAggregateType())
2234 B.SetInsertPoint(&
I);
2235 TrackConstants =
false;
2240 unsigned IntrinsicId;
2241 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2242 if (!
I.isAtomic()) {
2243 IntrinsicId = Intrinsic::spv_load;
2244 Args.push_back(
B.getInt32(
I.getAlign().value()));
2246 IntrinsicId = Intrinsic::spv_atomic_load;
2247 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2250 B.CreateIntrinsic(IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2252 replaceMemInstrUses(&
I, NewI,
B);
2256Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &
I) {
2260 B.SetInsertPoint(&
I);
2261 TrackConstants =
false;
2265 auto *PtrOp =
I.getPointerOperand();
2267 if (
I.getValueOperand()->getType()->isAggregateType()) {
2275 "Unexpected argument of aggregate type, should be spv_extractv!");
2279 unsigned IntrinsicId;
2280 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2282 if (!
I.isAtomic()) {
2283 IntrinsicId = Intrinsic::spv_store;
2284 Args.push_back(
B.getInt32(
I.getAlign().value()));
2286 IntrinsicId = Intrinsic::spv_atomic_store;
2287 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2289 auto *NewI =
B.CreateIntrinsic(
2290 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2292 I.eraseFromParent();
2296Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &
I) {
2297 Value *ArraySize =
nullptr;
2298 if (
I.isArrayAllocation()) {
2301 SPIRV::Extension::SPV_INTEL_variable_length_array))
2303 "array allocation: this instruction requires the following "
2304 "SPIR-V extension: SPV_INTEL_variable_length_array",
2306 ArraySize =
I.getArraySize();
2309 B.SetInsertPoint(&
I);
2310 TrackConstants =
false;
2311 Type *PtrTy =
I.getType();
2314 ?
B.CreateIntrinsic(Intrinsic::spv_alloca_array,
2315 {PtrTy, ArraySize->
getType()},
2316 {ArraySize,
B.getInt32(
I.getAlign().value())})
2317 :
B.CreateIntrinsic(
Intrinsic::spv_alloca, {PtrTy},
2318 {
B.getInt32(
I.getAlign().value())});
2319 replaceAllUsesWithAndErase(
B, &
I, NewI);
2323Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2324 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2326 B.SetInsertPoint(&
I);
2328 Args.push_back(
B.getInt32(
2329 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2332 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2333 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2334 uint32_t ScSem =
static_cast<uint32_t
>(
2336 Args.push_back(
B.getInt32(
2338 Args.push_back(
B.getInt32(
2340 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
2341 {
I.getPointerOperand()->getType()}, {
Args});
2342 replaceMemInstrUses(&
I, NewI,
B);
2346Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &
I) {
2348 B.SetInsertPoint(&
I);
2349 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2358 static const StringSet<> ArtificialGlobals{
"llvm.global.annotations",
2359 "llvm.compiler.used",
"llvm.used"};
2364 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2365 if (UserFunctions.contains(
F))
2370 if (!UserFunctions.empty())
2375 const Module &M = *
F->getParent();
2376 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2377 return F == &FirstDefinition;
2380Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(
Type *AggrTy,
2382 SmallVector<Value *, 4> Elems;
2384 Type *ElemTy = ArrTy->getElementType();
2385 auto *UI =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
2387 AggrConstTypes[UI] = ElemTy;
2388 Elems.
assign(ArrTy->getNumElements(), UI);
2391 DenseMap<Type *, Instruction *> UndefByType;
2392 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2394 auto &
Entry = UndefByType[ElemTy];
2396 Entry =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
2398 AggrConstTypes[
Entry] = ElemTy;
2403 auto *Composite =
B.CreateIntrinsic(Intrinsic::spv_const_composite,
2404 {
B.getInt32Ty()}, Elems);
2406 AggrConstTypes[Composite] = AggrTy;
2410void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2421 deduceElementTypeHelper(&GV,
false);
2423 Value *InitOp = Init;
2425 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2428 auto *InitInst =
B.CreateIntrinsic(Intrinsic::spv_init_global,
2430 InitInst->setArgOperand(1, InitOp);
2433 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2439bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *
I,
2441 bool UnknownElemTypeI8) {
2447 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2454void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *
I,
2457 static StringMap<unsigned> ResTypeWellKnown = {
2458 {
"async_work_group_copy", WellKnownTypes::Event},
2459 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2460 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2464 bool IsKnown =
false;
2469 std::string DemangledName =
2472 if (DemangledName.length() > 0)
2474 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2475 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2476 if (ResIt != ResTypeWellKnown.
end()) {
2479 switch (ResIt->second) {
2480 case WellKnownTypes::Event:
2487 switch (DecorationId) {
2490 case FPDecorationId::SAT:
2493 case FPDecorationId::RTE:
2495 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2497 case FPDecorationId::RTZ:
2499 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2501 case FPDecorationId::RTP:
2503 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2505 case FPDecorationId::RTN:
2507 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2513 Type *Ty =
I->getType();
2516 Type *TypeToAssign = Ty;
2518 if (
II->getIntrinsicID() == Intrinsic::spv_const_composite ||
2519 II->getIntrinsicID() == Intrinsic::spv_undef) {
2520 auto It = AggrConstTypes.
find(
II);
2521 if (It == AggrConstTypes.
end())
2523 TypeToAssign = It->second;
2525 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2526 TypeToAssign = It->second;
2530 for (
const auto &
Op :
I->operands()) {
2537 Type *OpTy =
Op->getType();
2539 CallInst *AssignCI =
2544 Type *OpTy =
Op->getType();
2559 CallInst *AssignCI =
2569bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2570 Instruction *Inst) {
2572 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2582void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *
I,
2584 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2586 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2591 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2592 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2593 if (shouldTryToAddMemAliasingDecoration(
I)) {
2594 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2595 ? SPIRV::Decoration::AliasScopeINTEL
2596 : SPIRV::Decoration::NoAliasINTEL;
2598 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2601 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2602 {
I->getType()}, {
Args});
2606 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2607 processMemAliasingDecoration(LLVMContext::MD_noalias);
2610 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2612 bool AllowFPMaxError =
2614 if (!AllowFPMaxError)
2618 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2622 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
2626 auto &Ctx =
B.getContext();
2628 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
2631 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
2633 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
2634 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
2637 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
2639 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
2641 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2649 &FPFastMathDefaultInfoMap,
2651 auto it = FPFastMathDefaultInfoMap.
find(
F);
2652 if (it != FPFastMathDefaultInfoMap.
end())
2660 SPIRV::FPFastMathMode::None);
2662 SPIRV::FPFastMathMode::None);
2664 SPIRV::FPFastMathMode::None);
2665 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
2671 size_t BitWidth = Ty->getScalarSizeInBits();
2675 assert(Index >= 0 && Index < 3 &&
2676 "Expected FPFastMathDefaultInfo for half, float, or double");
2677 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2678 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2679 return FPFastMathDefaultInfoVec[Index];
2682void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(
Module &M) {
2684 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2693 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
2695 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
2703 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
2706 [[maybe_unused]] GlobalVariable *GV =
2707 new GlobalVariable(M,
2708 Type::getInt32Ty(
M.getContext()),
2722 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
2723 FPFastMathDefaultInfoMap;
2725 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
2734 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2736 "Expected 4 operands for FPFastMathDefault");
2742 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2744 SPIRV::FPFastMathDefaultInfo &
Info =
2747 Info.FPFastMathDefault =
true;
2748 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
2750 "Expected no operands for ContractionOff");
2754 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2756 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2757 Info.ContractionOff =
true;
2759 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
2761 "Expected 1 operand for SignedZeroInfNanPreserve");
2762 unsigned TargetWidth =
2767 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2771 assert(Index >= 0 && Index < 3 &&
2772 "Expected FPFastMathDefaultInfo for half, float, or double");
2773 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2774 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2775 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
2779 std::unordered_map<unsigned, GlobalVariable *> GlobalVars;
2780 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
2781 if (FPFastMathDefaultInfoVec.
empty())
2784 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2785 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
2788 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
2789 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
2793 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
2795 "and AllowContract");
2797 if (
Info.SignedZeroInfNanPreserve &&
2799 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2800 SPIRV::FPFastMathMode::NSZ))) {
2801 if (
Info.FPFastMathDefault)
2803 "SignedZeroInfNanPreserve but at least one of "
2804 "NotNaN/NotInf/NSZ is enabled.");
2807 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
2808 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
2809 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
2811 "AllowTransform requires AllowReassoc and "
2812 "AllowContract to be set.");
2815 auto it = GlobalVars.find(Flags);
2816 GlobalVariable *GV =
nullptr;
2817 if (it != GlobalVars.end()) {
2823 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
2826 GV =
new GlobalVariable(M,
2827 Type::getInt32Ty(
M.getContext()),
2832 GlobalVars[
Flags] = GV;
2838void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *
I,
2841 bool IsConstComposite =
2842 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
2843 if (IsConstComposite && TrackConstants) {
2845 auto t = AggrConsts.
find(
I);
2849 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
2851 NewOp->setArgOperand(0,
I);
2854 for (
const auto &
Op :
I->operands()) {
2858 unsigned OpNo =
Op.getOperandNo();
2859 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
2860 (!
II->isBundleOperand(OpNo) &&
2861 II->paramHasAttr(OpNo, Attribute::ImmArg))))
2865 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
2866 :
B.SetInsertPoint(
I);
2869 Type *OpTy =
Op->getType();
2877 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
2879 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
2880 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
2882 SmallVector<Value *, 2>
Args = {
2885 CallInst *PtrCasted =
2886 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2891 I->setOperand(OpNo, NewOp);
2893 if (Named.insert(
I).second)
2897Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *
F,
2899 std::unordered_set<Function *> FVisited;
2900 return deduceFunParamElementType(
F,
OpIdx, FVisited);
2903Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
2904 Function *
F,
unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
2906 if (!FVisited.insert(
F).second)
2909 std::unordered_set<Value *> Visited;
2912 for (User *U :
F->users()) {
2924 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
2927 for (User *OpU : OpArg->
users()) {
2929 if (!Inst || Inst == CI)
2932 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
2939 if (FVisited.find(OuterF) != FVisited.end())
2941 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
2942 if (OuterF->
getArg(i) == OpArg) {
2943 Lookup.push_back(std::make_pair(OuterF, i));
2950 for (
auto &Pair :
Lookup) {
2951 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
2958void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *
F,
2960 B.SetInsertPointPastAllocas(
F);
2974 for (User *U :
F->users()) {
2990 for (User *U : Arg->
users()) {
2994 CI->
getParent()->getParent() == CurrF) {
2996 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3007void SPIRVEmitIntrinsics::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3008 B.SetInsertPointPastAllocas(
F);
3014 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3016 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3018 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3030 bool IsNewFTy =
false;
3046bool SPIRVEmitIntrinsics::processFunctionPointers(
Module &M) {
3049 if (
F.isIntrinsic())
3051 if (
F.isDeclaration()) {
3052 for (User *U :
F.users()) {
3065 for (User *U :
F.users()) {
3067 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3069 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3070 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3077 if (Worklist.
empty())
3080 LLVMContext &Ctx =
M.getContext();
3085 for (Function *
F : Worklist) {
3087 for (
const auto &Arg :
F->args())
3089 IRB.CreateCall(
F, Args);
3091 IRB.CreateRetVoid();
3097void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3098 DenseMap<Function *, CallInst *> Ptrcasts;
3099 for (
auto It : FDeclPtrTys) {
3101 for (
auto *U :
F->users()) {
3106 for (
auto [Idx, ElemTy] : It.second) {
3114 B.SetInsertPointPastAllocas(Arg->
getParent());
3118 }
else if (isaGEP(Param)) {
3119 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3128 .getFirstNonPHIOrDbgOrAlloca());
3149SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP) {
3156 Type *SrcTy =
GEP->getSourceElementType();
3157 SmallVector<Value *, 8> Indices(
GEP->indices());
3159 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3160 Indices.erase(Indices.begin());
3161 SrcTy = ArrTy->getElementType();
3163 GEP->getNoWrapFlags(),
"",
3164 GEP->getIterator());
3169void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &
F,
3176 if (
ST->canUseExtension(
3177 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3178 for (BasicBlock &BB :
F) {
3180 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3186 unsigned LC =
Ops[0];
3187 if (LC == SPIRV::LoopControl::None)
3191 B.SetInsertPoint(Term);
3192 SmallVector<Value *, 4> IntrArgs;
3193 for (
unsigned Op :
Ops)
3195 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3202 DominatorTree DT(
F);
3207 for (Loop *L : LI.getLoopsInPreorder()) {
3218 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3222 B.SetInsertPoint(Header->getTerminator());
3225 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3226 for (
unsigned Imm : LoopControlOps)
3227 Args.emplace_back(
B.getInt32(Imm));
3228 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3232bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3233 if (
Func.isDeclaration())
3237 GR =
ST.getSPIRVGlobalRegistry();
3241 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3246 AggrConstTypes.
clear();
3248 DeletedInstrs.
clear();
3250 processParamTypesByFunHeader(CurrF,
B);
3254 SmallPtrSet<Instruction *, 4> DeadInsts;
3259 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3263 GR->addDeducedElementType(SGEP,
3268 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3270 GEP->replaceAllUsesWith(NewGEP);
3274 if (
Type *GepTy = getGEPType(
GEP))
3278 for (
auto *
I : DeadInsts) {
3279 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3280 I->eraseFromParent();
3290 Type *ElTy =
SI->getValueOperand()->getType();
3295 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3296 for (
auto &GV :
Func.getParent()->globals())
3297 processGlobalValue(GV,
B);
3299 preprocessUndefs(
B);
3300 simplifyNullAddrSpaceCasts();
3301 preprocessCompositeConstants(
B);
3303 for (BasicBlock &BB : Func)
3304 for (PHINode &Phi : BB.
phis())
3305 if (
Phi.getType()->isAggregateType()) {
3306 AggrConstTypes[&
Phi] =
Phi.getType();
3307 Phi.mutateType(
B.getInt32Ty());
3310 preprocessBoolVectorBitcasts(Func);
3314 applyDemangledPtrArgTypes(
B);
3317 for (
auto &
I : Worklist) {
3319 if (isConvergenceIntrinsic(
I))
3322 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3324 insertAssignTypeIntrs(
I,
B);
3325 insertPtrCastOrAssignTypeInstr(
I,
B);
3329 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3330 insertAssignPtrTypeIntrs(
I,
B,
true);
3333 useRoundingMode(FPI,
B);
3338 SmallPtrSet<Instruction *, 4> IncompleteRets;
3340 deduceOperandElementType(&
I, &IncompleteRets);
3344 for (BasicBlock &BB : Func)
3345 for (PHINode &Phi : BB.
phis())
3347 deduceOperandElementType(&Phi,
nullptr);
3349 for (
auto *
I : Worklist) {
3350 if (DeletedInstrs.
count(
I))
3352 TrackConstants =
true;
3362 if (isConvergenceIntrinsic(
I))
3366 processInstrAfterVisit(
I,
B);
3369 emitUnstructuredLoopControls(Func,
B);
3375bool SPIRVEmitIntrinsics::postprocessTypes(
Module &M) {
3376 if (!GR || TodoTypeSz == 0)
3379 unsigned SzTodo = TodoTypeSz;
3380 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3385 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3386 Type *KnownTy = GR->findDeducedElementType(
Op);
3387 if (!KnownTy || !AssignCI)
3393 std::unordered_set<Value *> Visited;
3394 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3395 if (ElemTy != KnownTy) {
3396 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3397 propagateElemType(CI, ElemTy, VisitedSubst);
3404 if (
Op->hasUseList()) {
3405 for (User *U :
Op->users()) {
3412 if (TodoTypeSz == 0)
3417 SmallPtrSet<Instruction *, 4> IncompleteRets;
3419 auto It = ToProcess.
find(&
I);
3420 if (It == ToProcess.
end())
3422 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3423 if (It->second.size() == 0)
3425 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3426 if (TodoTypeSz == 0)
3431 return SzTodo > TodoTypeSz;
3435void SPIRVEmitIntrinsics::parseFunDeclarations(
Module &M) {
3437 if (!
F.isDeclaration() ||
F.isIntrinsic())
3441 if (DemangledName.empty())
3445 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3446 DemangledName,
ST.getPreferredInstructionSet());
3447 if (Opcode != SPIRV::OpGroupAsyncCopy)
3450 SmallVector<unsigned> Idxs;
3459 LLVMContext &Ctx =
F.getContext();
3461 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3462 if (!TypeStrs.
size())
3465 for (
unsigned Idx : Idxs) {
3466 if (Idx >= TypeStrs.
size())
3469 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3472 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3477bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3478 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3480 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3481 if (!
ST.canUseExtension(
3482 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3483 I.getContext().emitError(
3484 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3488 I.eraseFromParent();
3494 Value *Ptrs =
I.getArgOperand(0);
3496 Value *Passthru =
I.getArgOperand(2);
3499 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3501 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3506 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3508 I.eraseFromParent();
3512 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3513 if (!
ST.canUseExtension(
3514 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3515 I.getContext().emitError(
3516 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3519 I.eraseFromParent();
3525 Value *Values =
I.getArgOperand(0);
3526 Value *Ptrs =
I.getArgOperand(1);
3531 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3533 SmallVector<Value *, 4>
Args = {Values, Ptrs,
B.getInt32(Alignment),
Mask};
3537 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3538 I.eraseFromParent();
3549void SPIRVEmitIntrinsics::preprocessBoolVectorBitcasts(Function &
F) {
3550 struct BoolVecBitcast {
3552 FixedVectorType *BoolVecTy;
3556 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3558 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3566 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3568 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3572 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3574 Value *Src = BC->getOperand(0);
3575 unsigned BoolVecN = BoolVecTy->getNumElements();
3577 Type *IntTy =
B.getIntNTy(BoolVecN);
3583 IntVal = ConstantInt::get(IntTy, 0);
3584 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3585 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3586 Value *Ext =
B.CreateZExt(Elem, IntTy);
3588 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3589 IntVal =
B.CreateOr(IntVal, Ext);
3595 if (!Src->getType()->isIntegerTy())
3596 IntVal =
B.CreateBitCast(Src, IntTy);
3601 if (!SrcIsBoolVec) {
3604 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3607 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
3608 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
3614 if (!BC->getDestTy()->isIntegerTy())
3615 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
3618 BC->replaceAllUsesWith(Result);
3619 BC->eraseFromParent();
3623bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(
Module &M) {
3627 if (!
F.isIntrinsic())
3630 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
3635 Changed |= processMaskedMemIntrinsic(*
II);
3639 F.eraseFromParent();
3645bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
3648 Changed |= convertMaskedMemIntrinsics(M);
3650 parseFunDeclarations(M);
3651 insertConstantsForFPFastMathDefault(M);
3662 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
3664 processParamTypes(&
F,
B);
3668 CanTodoType =
false;
3669 Changed |= postprocessTypes(M);
3672 Changed |= processFunctionPointers(M);
3679 SPIRVEmitIntrinsics Legacy(TM);
3680 if (Legacy.runOnModule(M))
3686 return new SPIRVEmitIntrinsics(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void replaceAllUsesWith(Value *Old, Value *New, SmallPtrSet< BasicBlock *, 32 > &FreshBBs, bool IsHuge)
Replace all old uses with new ones, and push the updated BBs into FreshBBs.
static Type * getPointeeType(Value *Ptr, const DataLayout &DL)
This file defines the DenseSet and SmallDenseSet classes.
static bool runOnFunction(Function &F, bool PostInlining)
iv Induction Variable Users
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Machine Check Debug Module
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static unsigned getNumElements(Type *Ty)
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrConstForceInt32(const Value *V)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, DenseMap< Function *, SPIRV::FPFastMathDefaultInfoVector > &FPFastMathDefaultInfoMap, Function *F)
static Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static void emitAssignName(Instruction *I, IRBuilder<> &B)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void createRoundingModeDecoration(Instruction *I, unsigned RoundingModeDeco, IRBuilder<> &B)
static void createDecorationIntrinsic(Instruction *I, MDNode *Node, IRBuilder<> &B)
static SPIRV::FPFastMathDefaultInfo & getFPFastMathDefaultInfo(SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty)
static cl::opt< bool > SpirvEmitOpNames("spirv-emit-op-names", cl::desc("Emit OpName for all instructions"), cl::init(false))
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
StringSet - A set-like wrapper for the StringMap.
static SymbolRef::Type getType(const Symbol *Sym)
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
This class represents an incoming formal argument to a Function.
const Function * getParent() const
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
static LLVM_ABI BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned arg_size() const
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI std::optional< RoundingMode > getRoundingMode() const
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Type * getReturnType() const
Returns the type of the ret val.
Argument * getArg(unsigned i) const
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static LLVM_ABI Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static unsigned getPointerOperandIndex()
PointerType * getType() const
Global values are always pointers.
@ InternalLinkage
Rename collisions when linking (static functions).
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...
LLVM_ABI void addDestination(BasicBlock *Dest)
Add a destination.
Base class for instruction visitors.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
static unsigned getPointerOperandIndex()
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Flags
Flags values. These may be or'd together.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg)
Type * findDeducedCompositeType(const Value *Val)
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld=true)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator find(StringRef Key)
StringRef - Represent a constant reference to a string, i.e.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
StringSet - A wrapper for StringMap that provides set-like functionality.
bool contains(StringRef key) const
Check if the set contains the given key.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getArrayElementType() const
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
bool isStructTy() const
True if this is an instance of StructType.
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
void setOperand(unsigned i, Value *Val)
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
const ParentTy * getParent() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ SPIR_KERNEL
Used for SPIR kernel functions.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
bool match(Val *V, const Pattern &P)
IntrinsicID_match m_Intrinsic()
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_Value()
Match an arbitrary value and ignore it.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
ModulePass * createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
bool isNestedPointer(const Type *Ty)
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
auto reverse(ContainerTy &&C)
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
bool isPointerTy(const Type *T)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
@ Ref
The access may reference the value stored in memory.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
bool hasInitializer(const GlobalVariable *GV)
Type * normalizeType(Type *Ty)
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
PoisonValue * getNormalizedPoisonValue(Type *Ty)
bool isUntypedPointerTy(const Type *T)
Type * reconstitutePeeledArrayType(Type *Ty)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)