27#include "llvm/IR/IntrinsicsSPIRV.h"
38#include <unordered_set>
61#define DEBUG_TYPE "spirv-emit-intrinsics"
65 cl::desc(
"Emit OpName for all instructions"),
69#define GET_BuiltinGroup_DECL
70#include "SPIRVGenTables.inc"
75class GlobalVariableUsers {
76 template <
typename T1,
typename T2>
77 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
79 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
81 void collectGlobalUsers(
82 const GlobalVariable *GV,
83 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
84 &GlobalIsUsedByGlobal) {
86 while (!
Stack.empty()) {
90 GlobalIsUsedByFun[GV].insert(
I->getFunction());
95 GlobalIsUsedByGlobal[GV].insert(UserGV);
100 Stack.append(
C->user_begin(),
C->user_end());
104 bool propagateGlobalToGlobalUsers(
105 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
106 &GlobalIsUsedByGlobal) {
109 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
110 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
111 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
112 auto It = GlobalIsUsedByGlobal.find(UserGV);
113 if (It == GlobalIsUsedByGlobal.end())
121 void propagateGlobalToFunctionReferences(
122 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
123 &GlobalIsUsedByGlobal) {
124 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
125 auto &UserFunctions = GlobalIsUsedByFun[GV];
126 for (
const GlobalVariable *UserGV : UserGlobals) {
127 auto It = GlobalIsUsedByFun.find(UserGV);
128 if (It == GlobalIsUsedByFun.end())
139 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
140 GlobalIsUsedByGlobal;
141 GlobalIsUsedByFun.clear();
142 for (GlobalVariable &GV :
M.globals())
143 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
146 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
149 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
152 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
153 const FunctionSetType &
154 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
155 auto It = GlobalIsUsedByFun.find(&GV);
156 if (It != GlobalIsUsedByFun.end())
159 static const FunctionSetType
Empty{};
164static bool isaGEP(
const Value *V) {
170static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
176 return AT->getNumElements();
182class SPIRVEmitIntrinsics
184 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
185 const SPIRVTargetMachine &TM;
186 SPIRVGlobalRegistry *GR =
nullptr;
188 bool TrackConstants =
true;
189 bool HaveFunPtrs =
false;
190 DenseMap<Instruction *, Constant *> AggrConsts;
191 DenseMap<Instruction *, Type *> AggrConstTypes;
192 DenseSet<Instruction *> AggrStores;
193 SmallPtrSet<Instruction *, 8> DeletedInstrs;
194 GlobalVariableUsers GVUsers;
195 std::unordered_set<Value *> Named;
198 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
201 bool CanTodoType =
true;
202 unsigned TodoTypeSz = 0;
203 DenseMap<Value *, bool> TodoType;
204 void insertTodoType(
Value *
Op) {
206 if (CanTodoType && !isaGEP(
Op)) {
207 auto It = TodoType.try_emplace(
Op,
true);
212 void eraseTodoType(
Value *
Op) {
213 auto It = TodoType.find(
Op);
214 if (It != TodoType.end() && It->second) {
222 auto It = TodoType.find(
Op);
223 return It != TodoType.end() && It->second;
227 std::unordered_set<Instruction *> TypeValidated;
230 enum WellKnownTypes { Event };
233 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
234 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
235 Type *deduceElementTypeHelper(
Value *
I, std::unordered_set<Value *> &Visited,
236 bool UnknownElemTypeI8,
237 bool IgnoreKnownType =
false);
238 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
239 bool UnknownElemTypeI8);
240 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
241 std::unordered_set<Value *> &Visited,
242 bool UnknownElemTypeI8);
244 std::unordered_set<Value *> &Visited,
245 bool UnknownElemTypeI8);
247 bool UnknownElemTypeI8);
250 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
251 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
252 std::unordered_set<Value *> &Visited,
253 bool UnknownElemTypeI8);
256 void deduceOperandElementType(Instruction *
I,
257 SmallPtrSet<Instruction *, 4> *IncompleteRets,
258 const SmallPtrSet<Value *, 4> *AskOps =
nullptr,
259 bool IsPostprocessing =
false);
264 void simplifyNullAddrSpaceCasts();
266 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
267 bool IsPostprocessing);
269 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
271 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
272 bool UnknownElemTypeI8);
274 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
276 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
277 Type *ExpectedElementType,
278 unsigned OperandToReplace,
280 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
281 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
283 void insertConstantsForFPFastMathDefault(
Module &M);
285 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
287 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
288 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
289 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx,
290 std::unordered_set<Function *> &FVisited);
292 bool deduceOperandElementTypeCalledFunction(
294 Type *&KnownElemTy,
bool &Incomplete);
295 void deduceOperandElementTypeFunctionPointer(
297 Type *&KnownElemTy,
bool IsPostprocessing);
298 bool deduceOperandElementTypeFunctionRet(
299 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
300 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
303 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
304 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
305 DenseMap<Function *, CallInst *> Ptrcasts);
307 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
310 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
311 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
312 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
313 std::unordered_set<Value *> &Visited,
314 DenseMap<Function *, CallInst *> Ptrcasts);
317 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
318 Instruction *Dest,
bool DeleteOld =
true);
322 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
325 bool postprocessTypes(
Module &M);
326 bool processFunctionPointers(
Module &M);
327 void parseFunDeclarations(
Module &M);
328 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
329 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
330 bool convertMaskedMemIntrinsics(
Module &M);
331 void preprocessBoolVectorBitcasts(Function &
F);
333 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
350 bool walkLogicalAccessChain(
351 GetElementPtrInst &
GEP,
352 const std::function<
void(
Type *PointedType, uint64_t Index)>
355 uint64_t Multiplier)> &OnDynamicIndexing);
357 bool walkLogicalAccessChainDynamic(
358 Type *CurType,
Value *Operand, uint64_t Multiplier,
359 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
360 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing);
362 bool walkLogicalAccessChainConstant(
364 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing);
370 Type *getGEPType(GetElementPtrInst *
GEP);
377 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
379 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
383 SPIRVEmitIntrinsics(
const SPIRVTargetMachine &TM) : ModulePass(ID), TM(TM) {}
386 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
389 Instruction *visitInsertElementInst(InsertElementInst &
I);
390 Instruction *visitExtractElementInst(ExtractElementInst &
I);
392 Instruction *visitExtractValueInst(ExtractValueInst &
I);
396 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
400 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
402 bool runOnModule(
Module &M)
override;
404 void getAnalysisUsage(AnalysisUsage &AU)
const override {
405 ModulePass::getAnalysisUsage(AU);
411 Intrinsic::experimental_convergence_loop,
412 Intrinsic::experimental_convergence_anchor>());
415bool expectIgnoredInIRTranslation(
const Instruction *
I) {
417 Intrinsic::spv_resource_handlefrombinding,
418 Intrinsic::spv_resource_getbasepointer,
419 Intrinsic::spv_resource_getpointer>());
426 return getPointerRoot(V);
432char SPIRVEmitIntrinsics::ID = 0;
435 "SPIRV emit intrinsics",
false,
false)
449 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
462 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
468 B.SetCurrentDebugLocation(
I->getDebugLoc());
469 if (
I->getType()->isVoidTy())
470 B.SetInsertPoint(
I->getNextNode());
472 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
482 if (
I->getType()->isTokenTy())
484 "does not support token type",
489 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
490 expectIgnoredInIRTranslation(
I))
501 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
512 std::vector<Value *> Args = {
515 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
518void SPIRVEmitIntrinsics::replaceAllUsesWith(
Value *Src,
Value *Dest,
522 if (isTodoType(Src)) {
525 insertTodoType(Dest);
529void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
534 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
535 Src->eraseFromParent();
538 if (Named.insert(Dest).second)
563Type *SPIRVEmitIntrinsics::reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
564 bool IsPostprocessing) {
568 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
582 if (UnknownElemTypeI8) {
583 if (!IsPostprocessing)
591CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *
F,
Value *
Op,
599 B.SetInsertPointPastAllocas(OpA->getParent());
602 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
604 Type *OpTy =
Op->getType();
608 CallInst *PtrCasted =
609 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
614void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
616 DenseMap<Function *, CallInst *> Ptrcasts) {
618 CallInst *PtrCastedI =
nullptr;
619 auto It = Ptrcasts.
find(
F);
620 if (It == Ptrcasts.
end()) {
621 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
622 Ptrcasts[
F] = PtrCastedI;
624 PtrCastedI = It->second;
626 I->replaceUsesOfWith(
Op, PtrCastedI);
629void SPIRVEmitIntrinsics::propagateElemType(
631 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
632 DenseMap<Function *, CallInst *> Ptrcasts;
634 for (
auto *U :
Users) {
637 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
642 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
643 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
647void SPIRVEmitIntrinsics::propagateElemTypeRec(
649 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
650 std::unordered_set<Value *> Visited;
651 DenseMap<Function *, CallInst *> Ptrcasts;
652 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
653 std::move(Ptrcasts));
656void SPIRVEmitIntrinsics::propagateElemTypeRec(
658 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
659 std::unordered_set<Value *> &Visited,
660 DenseMap<Function *, CallInst *> Ptrcasts) {
661 if (!Visited.insert(
Op).second)
664 for (
auto *U :
Users) {
667 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
672 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
673 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
681SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
682 bool UnknownElemTypeI8) {
683 std::unordered_set<Value *> Visited;
684 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
688Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
689 Type *ValueTy,
Value *Operand, std::unordered_set<Value *> &Visited,
690 bool UnknownElemTypeI8) {
695 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
706Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
707 Value *
Op, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8) {
719 for (User *OpU :
Op->users()) {
721 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
734 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
743Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I,
744 bool UnknownElemTypeI8) {
745 std::unordered_set<Value *> Visited;
746 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
749void SPIRVEmitIntrinsics::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
Type *RefTy,
750 bool UnknownElemTypeI8) {
752 if (!UnknownElemTypeI8)
761bool SPIRVEmitIntrinsics::walkLogicalAccessChainDynamic(
762 Type *CurType,
Value *Operand, uint64_t Multiplier,
763 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
764 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
770 if (
ST->getNumElements() > 0) {
771 CurType =
ST->getElementType(0);
772 OnLiteralIndexing(CurType, 0);
782 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
783 return AT ==
nullptr;
786bool SPIRVEmitIntrinsics::walkLogicalAccessChainConstant(
788 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
793 uint32_t EltTypeSize =
DL.getTypeSizeInBits(AT->getElementType()) / 8;
797 CurType = AT->getElementType();
798 OnLiteralIndexing(CurType, Index);
800 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
803 const auto &STL =
DL.getStructLayout(ST);
804 unsigned Element = STL->getElementContainingOffset(
Offset);
805 Offset -= STL->getElementOffset(Element);
806 CurType =
ST->getElementType(Element);
807 OnLiteralIndexing(CurType, Element);
809 Type *EltTy = VT->getElementType();
810 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
811 assert(EltSizeBits % 8 == 0 &&
812 "Element type size in bits must be a multiple of 8.");
813 uint32_t EltTypeSize = EltSizeBits / 8;
818 OnLiteralIndexing(CurType, Index);
828bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
829 GetElementPtrInst &
GEP,
830 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
831 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
834 std::optional<uint64_t> MultiplierOpt =
835 getByteAddressingMultiplier(
GEP.getSourceElementType());
836 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
837 uint64_t Multiplier = *MultiplierOpt;
840 Value *Src = getPointerRoot(
GEP.getPointerOperand());
841 Type *CurType = deduceElementType(Src,
true);
845 return walkLogicalAccessChainConstant(
846 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
848 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
849 OnLiteralIndexing, OnDynamicIndexing);
853SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP) {
856 B.SetInsertPoint(&
GEP);
858 std::vector<Value *> Indices;
859 Indices.push_back(ConstantInt::get(
860 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
861 walkLogicalAccessChain(
863 [&Indices, &
B](
Type *EltType, uint64_t Index) {
865 ConstantInt::get(
B.getInt64Ty(), Index,
false));
868 uint64_t Multiplier) {
870 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
872 if (Multiplier == EltTypeSize) {
874 }
else if (EltTypeSize % Multiplier == 0) {
877 EltTypeSize / Multiplier,
881 ConstantInt::get(
Offset->getType(), Multiplier,
884 Index =
B.CreateUDiv(Index,
885 ConstantInt::get(
Offset->getType(), EltTypeSize,
889 Indices.push_back(Index);
893 SmallVector<Value *, 4>
Args;
894 Args.push_back(
B.getInt1(
GEP.isInBounds()));
895 Args.push_back(
GEP.getOperand(0));
897 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
898 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
902Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *
GEP) {
904 Type *CurType =
GEP->getResultElementType();
906 bool Interrupted = walkLogicalAccessChain(
907 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
908 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
910 return Interrupted ?
GEP->getResultElementType() : CurType;
913Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *
Ref) {
914 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
916 return getGEPTypeLogical(
Ref);
923 Ty =
Ref->getSourceElementType();
927 Ty =
Ref->getResultElementType();
932Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
933 Value *
I, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8,
934 bool IgnoreKnownType) {
940 if (!IgnoreKnownType)
945 if (!Visited.insert(
I).second)
952 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
954 Ty = getGEPType(
Ref);
956 Ty = SGEP->getResultElementType();
961 KnownTy =
Op->getType();
963 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
966 Ty = SPIRV::getOriginalFunctionType(*Fn);
969 Ty = deduceElementTypeByValueDeep(
971 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
975 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
977 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
979 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
981 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
983 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
988 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
992 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
994 Type *BestTy =
nullptr;
996 DenseMap<Type *, unsigned> PhiTys;
997 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
998 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1005 if (It.first->second > MaxN) {
1006 MaxN = It.first->second;
1014 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1015 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1020 static StringMap<unsigned> ResTypeByArg = {
1024 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1025 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1026 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1027 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1028 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1029 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1033 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1034 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1036 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1037 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1038 for (User *U :
II->users()) {
1043 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1045 Ty = HandleType->getTypeParameter(0);
1046 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1060 }
else if (
II &&
II->getIntrinsicID() ==
1061 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1065 std::string DemangledName =
1067 if (DemangledName.length() > 0)
1068 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1069 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1070 if (AsArgIt != ResTypeByArg.
end())
1071 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1072 Visited, UnknownElemTypeI8);
1079 if (Ty && !IgnoreKnownType) {
1090Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1091 bool UnknownElemTypeI8) {
1092 std::unordered_set<Value *> Visited;
1093 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1096Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
1097 User *U,
Type *OrigTy, std::unordered_set<Value *> &Visited,
1098 bool UnknownElemTypeI8) {
1107 if (!Visited.insert(U).second)
1112 bool Change =
false;
1113 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1115 assert(
Op &&
"Operands should not be null.");
1116 Type *OpTy =
Op->getType();
1119 if (
Type *NestedTy =
1120 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1127 Change |= Ty != OpTy;
1135 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1136 Type *OpTy = ArrTy->getElementType();
1139 if (
Type *NestedTy =
1140 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1147 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1153 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1154 Type *OpTy = VecTy->getElementType();
1157 if (
Type *NestedTy =
1158 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1165 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1175Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I,
bool UnknownElemTypeI8) {
1176 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1178 if (!UnknownElemTypeI8)
1181 return IntegerType::getInt8Ty(
I->getContext());
1185 Value *PointerOperand) {
1191 return I->getType();
1199bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1201 Type *&KnownElemTy,
bool &Incomplete) {
1205 std::string DemangledName =
1207 if (DemangledName.length() > 0 &&
1209 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1210 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1211 DemangledName,
ST.getPreferredInstructionSet());
1212 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1213 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1219 KnownElemTy = ElemTy;
1220 Ops.push_back(std::make_pair(
Op, i));
1222 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1229 case SPIRV::OpAtomicFAddEXT:
1230 case SPIRV::OpAtomicFMinEXT:
1231 case SPIRV::OpAtomicFMaxEXT:
1232 case SPIRV::OpAtomicLoad:
1233 case SPIRV::OpAtomicCompareExchangeWeak:
1234 case SPIRV::OpAtomicCompareExchange:
1235 case SPIRV::OpAtomicExchange:
1236 case SPIRV::OpAtomicIAdd:
1237 case SPIRV::OpAtomicISub:
1238 case SPIRV::OpAtomicOr:
1239 case SPIRV::OpAtomicXor:
1240 case SPIRV::OpAtomicAnd:
1241 case SPIRV::OpAtomicUMin:
1242 case SPIRV::OpAtomicUMax:
1243 case SPIRV::OpAtomicSMin:
1244 case SPIRV::OpAtomicSMax: {
1249 Incomplete = isTodoType(
Op);
1250 Ops.push_back(std::make_pair(
Op, 0));
1252 case SPIRV::OpAtomicStore: {
1261 Incomplete = isTodoType(
Op);
1262 Ops.push_back(std::make_pair(
Op, 0));
1271void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1273 Type *&KnownElemTy,
bool IsPostprocessing) {
1277 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1278 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1279 bool IsNewFTy =
false, IsIncomplete =
false;
1282 Type *ArgTy = Arg->getType();
1287 if (isTodoType(Arg))
1288 IsIncomplete =
true;
1290 IsIncomplete =
true;
1293 ArgTy = FTy->getFunctionParamType(ParmIdx);
1297 Type *RetTy = FTy->getReturnType();
1304 IsIncomplete =
true;
1306 IsIncomplete =
true;
1309 if (!IsPostprocessing && IsIncomplete)
1312 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1315bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1316 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1317 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
1329 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1330 for (User *U :
F->users()) {
1338 propagateElemType(CI, PrevElemTy, VisitedSubst);
1348 for (Instruction *IncompleteRetI : *IncompleteRets)
1349 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1351 }
else if (IncompleteRets) {
1354 TypeValidated.insert(
I);
1362void SPIRVEmitIntrinsics::deduceOperandElementType(
1363 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1364 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing) {
1366 Type *KnownElemTy =
nullptr;
1367 bool Incomplete =
false;
1373 Incomplete = isTodoType(
I);
1374 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1377 Ops.push_back(std::make_pair(
Op, i));
1383 Incomplete = isTodoType(
I);
1384 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1391 Incomplete = isTodoType(
I);
1392 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1396 KnownElemTy =
Ref->getSourceElementType();
1397 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1402 KnownElemTy =
Ref->getBaseType();
1403 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1406 KnownElemTy =
I->getType();
1412 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1416 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1421 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1429 Incomplete = isTodoType(
Ref->getPointerOperand());
1430 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1438 Incomplete = isTodoType(
Ref->getPointerOperand());
1439 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1445 Incomplete = isTodoType(
I);
1446 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1449 Ops.push_back(std::make_pair(
Op, i));
1457 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1458 IsPostprocessing, KnownElemTy,
Op,
1461 Incomplete = isTodoType(CurrF);
1462 Ops.push_back(std::make_pair(
Op, 0));
1468 bool Incomplete0 = isTodoType(Op0);
1469 bool Incomplete1 = isTodoType(Op1);
1471 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1473 : GR->findDeducedElementType(Op0);
1475 KnownElemTy = ElemTy0;
1476 Incomplete = Incomplete0;
1477 Ops.push_back(std::make_pair(Op1, 1));
1478 }
else if (ElemTy1) {
1479 KnownElemTy = ElemTy1;
1480 Incomplete = Incomplete1;
1481 Ops.push_back(std::make_pair(Op0, 0));
1485 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1486 else if (HaveFunPtrs)
1487 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1492 if (!KnownElemTy ||
Ops.size() == 0)
1497 for (
auto &OpIt :
Ops) {
1501 Type *AskTy =
nullptr;
1502 CallInst *AskCI =
nullptr;
1503 if (IsPostprocessing && AskOps) {
1509 if (Ty == KnownElemTy)
1512 Type *OpTy =
Op->getType();
1513 if (
Op->hasUseList() &&
1520 else if (!IsPostprocessing)
1524 if (AssignCI ==
nullptr) {
1533 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1534 std::make_pair(
I,
Op)};
1535 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1539 CallInst *PtrCastI =
1540 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1541 if (OpIt.second == std::numeric_limits<unsigned>::max())
1544 I->setOperand(OpIt.second, PtrCastI);
1547 TypeValidated.insert(
I);
1550void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1555 if (isAssignTypeInstr(U)) {
1556 B.SetInsertPoint(U);
1557 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1558 CallInst *AssignCI =
1559 B.CreateIntrinsic(Intrinsic::spv_assign_type, {
New->getType()},
Args);
1561 U->eraseFromParent();
1564 U->replaceUsesOfWith(Old, New);
1572 Type *NewArgTy =
New->getType();
1574 if (NewArgTy != ExpectedArgTy) {
1577 M, Intrinsic::spv_abort, {NewArgTy});
1582 if (
Phi->getType() !=
New->getType()) {
1583 Phi->mutateType(
New->getType());
1584 Phi->replaceUsesOfWith(Old, New);
1587 for (User *PhiUser :
Phi->users())
1590 for (ExtractValueInst *EV : EVUsers) {
1591 B.SetInsertPoint(EV);
1593 for (
unsigned Idx : EV->indices())
1594 Args.push_back(
B.getInt32(Idx));
1596 B.CreateIntrinsic(Intrinsic::spv_extractv, {EV->getType()},
Args);
1597 EV->replaceAllUsesWith(NewEV);
1598 DeletedInstrs.
insert(EV);
1599 EV->eraseFromParent();
1602 Phi->replaceUsesOfWith(Old, New);
1608 New->copyMetadata(*Old);
1612void SPIRVEmitIntrinsics::preprocessUndefs(
IRBuilder<> &
B) {
1616 SmallVector<Instruction *, 16> Insts;
1620 for (Instruction *
I : Insts) {
1621 bool BPrepared =
false;
1622 for (
auto &
Op :
I->operands()) {
1624 if (!AggrUndef || !
Op->getType()->isAggregateType())
1629 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1630 "lowered as undef\n");
1636 auto *IntrUndef =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
1637 I->replaceUsesOfWith(
Op, IntrUndef);
1638 AggrConsts[IntrUndef] = AggrUndef;
1639 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1644void SPIRVEmitIntrinsics::preprocessPoisons(
IRBuilder<> &
B) {
1650 bool BPrepared =
false;
1653 for (
unsigned Idx = 0; Idx <
I.getNumOperands(); ++Idx) {
1656 if (!
Poison ||
Op->getType()->isMetadataTy())
1659 Type *OpTy =
Op->getType();
1660 Value *Replacement =
nullptr;
1667 B.CreateIntrinsic(Intrinsic::spv_poison, {
B.getInt32Ty()}, {});
1669 AggrConstTypes[
Call] = OpTy;
1673 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1674 else if (!BPrepared) {
1678 Replacement =
B.CreateIntrinsic(Intrinsic::spv_poison, {OpTy}, {});
1680 I.setOperand(Idx, Replacement);
1689void SPIRVEmitIntrinsics::simplifyNullAddrSpaceCasts() {
1693 ASC->replaceAllUsesWith(
1695 ASC->eraseFromParent();
1699void SPIRVEmitIntrinsics::preprocessCompositeConstants(
IRBuilder<> &
B) {
1703 std::queue<Instruction *> Worklist;
1707 while (!Worklist.empty()) {
1708 auto *
I = Worklist.front();
1711 bool KeepInst =
false;
1712 for (
const auto &
Op :
I->operands()) {
1714 Type *ResTy =
nullptr;
1717 ResTy = COp->getType();
1729 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1732 auto PrepareInsert = [&]() {
1735 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1736 :
B.SetInsertPoint(
I);
1741 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1742 Args.push_back(COp->getElementAsConstant(i));
1748 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1753 Type *PoisonTy =
Op->getType();
1755 auto *
Call =
B.CreateIntrinsic(Intrinsic::spv_poison,
1756 {
B.getInt32Ty()}, {});
1758 AggrConstTypes[
Call] = PoisonTy;
1761 Op =
B.CreateIntrinsic(Intrinsic::spv_poison, {PoisonTy}, {});
1768 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {
Args});
1772 AggrConsts[CI] = AggrConst;
1773 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1785 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1790 unsigned RoundingModeDeco,
1797 ConstantInt::get(
Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1806 MDNode *SaturatedConversionNode =
1808 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1828 MDString *ConstraintString =
1837 B.SetInsertPoint(&
Call);
1838 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1843void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1846 if (!
RM.has_value())
1848 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1849 switch (
RM.value()) {
1853 case RoundingMode::NearestTiesToEven:
1854 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1856 case RoundingMode::TowardNegative:
1857 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1859 case RoundingMode::TowardPositive:
1860 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1862 case RoundingMode::TowardZero:
1863 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1865 case RoundingMode::Dynamic:
1866 case RoundingMode::NearestTiesToAway:
1870 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1876Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &
I) {
1880 B.SetInsertPoint(&
I);
1881 SmallVector<Value *, 4>
Args;
1883 Args.push_back(
I.getCondition());
1886 for (
auto &Case :
I.cases()) {
1887 Args.push_back(Case.getCaseValue());
1888 BBCases.
push_back(Case.getCaseSuccessor());
1891 CallInst *NewI =
B.CreateIntrinsic(Intrinsic::spv_switch,
1892 {
I.getOperand(0)->getType()}, {
Args});
1896 I.eraseFromParent();
1899 B.SetInsertPoint(ParentBB);
1900 IndirectBrInst *BrI =
B.CreateIndirectBr(
1903 for (BasicBlock *BBCase : BBCases)
1912Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &
I) {
1918 B.SetInsertPoint(&
I);
1920 SmallVector<Value *, 4>
Args;
1921 Args.push_back(
B.getInt1(
true));
1922 Args.push_back(
I.getOperand(0));
1923 Args.push_back(
B.getInt32(0));
1924 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1925 Args.push_back(SGEP->getIndexOperand(J));
1927 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, Types, Args);
1928 replaceAllUsesWithAndErase(
B, &
I, NewI);
1932Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &
I) {
1934 B.SetInsertPoint(&
I);
1942 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
1943 return buildLogicalAccessChainFromGEP(
I);
1948 Value *PtrOp =
I.getPointerOperand();
1949 Type *SrcElemTy =
I.getSourceElementType();
1950 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
1953 if (ArrTy->getElementType() == SrcElemTy) {
1955 Type *FirstIdxType =
I.getOperand(1)->getType();
1956 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
1957 for (
Value *Idx :
I.indices())
1961 SmallVector<Value *, 4>
Args;
1962 Args.push_back(
B.getInt1(
I.isInBounds()));
1963 Args.push_back(
I.getPointerOperand());
1966 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
1967 replaceAllUsesWithAndErase(
B, &
I, NewI);
1974 SmallVector<Value *, 4>
Args;
1975 Args.push_back(
B.getInt1(
I.isInBounds()));
1977 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
1978 replaceAllUsesWithAndErase(
B, &
I, NewI);
1982Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &
I) {
1984 B.SetInsertPoint(&
I);
1993 I.eraseFromParent();
1999 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_bitcast, {
Types}, {
Args});
2000 replaceAllUsesWithAndErase(
B, &
I, NewI);
2004void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
2006 Type *VTy =
V->getType();
2011 if (ElemTy != AssignedType)
2024 if (CurrentType == AssignedType)
2031 " for value " +
V->getName(),
2039void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
2040 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2042 TypeValidated.insert(
I);
2045 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2046 if (PointerElemTy == ExpectedElementType ||
2052 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2054 bool FirstPtrCastOrAssignPtrType =
true;
2060 for (
auto User :
Pointer->users()) {
2063 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2064 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2065 II->getOperand(0) != Pointer)
2070 FirstPtrCastOrAssignPtrType =
false;
2071 if (
II->getOperand(1) != VMD ||
2078 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2083 if (
II->getParent() !=
I->getParent())
2086 I->setOperand(OperandToReplace,
II);
2092 if (FirstPtrCastOrAssignPtrType) {
2097 }
else if (isTodoType(Pointer)) {
2098 eraseTodoType(Pointer);
2106 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2107 std::make_pair(
I, Pointer)};
2109 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2121 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2127void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2132 replacePointerOperandWithPtrCast(
2133 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2139 Type *OpTy =
Op->getType();
2142 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2145 if (OpTy ==
Op->getType())
2146 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2147 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2152 Type *OpTy = LI->getType();
2157 Type *NewOpTy = OpTy;
2158 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2159 if (OpTy == NewOpTy)
2160 insertTodoType(Pointer);
2163 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2168 Type *OpTy =
nullptr;
2180 OpTy = GEPI->getSourceElementType();
2182 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2184 insertTodoType(Pointer);
2196 std::string DemangledName =
2200 bool HaveTypes =
false;
2218 for (User *U : CalledArg->
users()) {
2220 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2226 HaveTypes |= ElemTy !=
nullptr;
2231 if (DemangledName.empty() && !HaveTypes)
2249 Type *ExpectedType =
2251 if (!ExpectedType && !DemangledName.empty())
2252 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2253 DemangledName,
OpIdx,
I->getContext());
2254 if (!ExpectedType || ExpectedType->
isVoidTy())
2262 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2266Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &
I) {
2273 I.getOperand(1)->getType(),
2274 I.getOperand(2)->getType()};
2276 B.SetInsertPoint(&
I);
2278 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
2279 replaceAllUsesWithAndErase(
B, &
I, NewI);
2284SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &
I) {
2291 B.SetInsertPoint(&
I);
2293 I.getIndexOperand()->getType()};
2294 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2295 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
2296 replaceAllUsesWithAndErase(
B, &
I, NewI);
2300Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &
I) {
2302 B.SetInsertPoint(&
I);
2305 Value *AggregateOp =
I.getAggregateOperand();
2309 Args.push_back(AggregateOp);
2310 Args.push_back(
I.getInsertedValueOperand());
2311 for (
auto &
Op :
I.indices())
2312 Args.push_back(
B.getInt32(
Op));
2314 B.CreateIntrinsic(Intrinsic::spv_insertv, {
Types}, {
Args});
2315 replaceMemInstrUses(&
I, NewI,
B);
2319Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &
I) {
2320 if (
I.getAggregateOperand()->getType()->isAggregateType())
2323 B.SetInsertPoint(&
I);
2325 for (
auto &
Op :
I.indices())
2326 Args.push_back(
B.getInt32(
Op));
2328 B.CreateIntrinsic(Intrinsic::spv_extractv, {
I.getType()}, {
Args});
2329 replaceAllUsesWithAndErase(
B, &
I, NewI);
2333Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &
I) {
2334 if (!
I.getType()->isAggregateType())
2337 B.SetInsertPoint(&
I);
2338 TrackConstants =
false;
2343 unsigned IntrinsicId;
2344 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2345 if (!
I.isAtomic()) {
2346 IntrinsicId = Intrinsic::spv_load;
2347 Args.push_back(
B.getInt32(
I.getAlign().value()));
2349 IntrinsicId = Intrinsic::spv_atomic_load;
2350 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2353 B.CreateIntrinsic(IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2355 replaceMemInstrUses(&
I, NewI,
B);
2359Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &
I) {
2363 B.SetInsertPoint(&
I);
2364 TrackConstants =
false;
2368 auto *PtrOp =
I.getPointerOperand();
2370 if (
I.getValueOperand()->getType()->isAggregateType()) {
2378 "Unexpected argument of aggregate type, should be spv_extractv!");
2382 unsigned IntrinsicId;
2383 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2385 if (!
I.isAtomic()) {
2386 IntrinsicId = Intrinsic::spv_store;
2387 Args.push_back(
B.getInt32(
I.getAlign().value()));
2389 IntrinsicId = Intrinsic::spv_atomic_store;
2390 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2392 auto *NewI =
B.CreateIntrinsic(
2393 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2395 I.eraseFromParent();
2399Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &
I) {
2400 Value *ArraySize =
nullptr;
2401 if (
I.isArrayAllocation()) {
2404 SPIRV::Extension::SPV_INTEL_variable_length_array))
2406 "array allocation: this instruction requires the following "
2407 "SPIR-V extension: SPV_INTEL_variable_length_array",
2409 ArraySize =
I.getArraySize();
2412 B.SetInsertPoint(&
I);
2413 TrackConstants =
false;
2414 Type *PtrTy =
I.getType();
2417 ?
B.CreateIntrinsic(Intrinsic::spv_alloca_array,
2418 {PtrTy, ArraySize->
getType()},
2419 {ArraySize,
B.getInt32(
I.getAlign().value())})
2420 :
B.CreateIntrinsic(
Intrinsic::spv_alloca, {PtrTy},
2421 {
B.getInt32(
I.getAlign().value())});
2422 replaceAllUsesWithAndErase(
B, &
I, NewI);
2426Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2427 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2429 B.SetInsertPoint(&
I);
2431 Args.push_back(
B.getInt32(
2432 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2435 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2436 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2437 uint32_t ScSem =
static_cast<uint32_t
>(
2439 Args.push_back(
B.getInt32(
2441 Args.push_back(
B.getInt32(
2443 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
2444 {
I.getPointerOperand()->getType()}, {
Args});
2445 replaceMemInstrUses(&
I, NewI,
B);
2454 case Intrinsic::spv_abort:
2456 case Intrinsic::trap:
2457 case Intrinsic::ubsantrap:
2459 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2479 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2480 "abort-like call must be the last non-debug instruction before its "
2481 "block's terminator");
2485Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &
I) {
2486 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2490 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2499 static const StringSet<> ArtificialGlobals{
"llvm.global.annotations",
2500 "llvm.compiler.used",
"llvm.used"};
2505 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2506 if (UserFunctions.contains(
F))
2511 if (!UserFunctions.empty())
2516 const Module &M = *
F->getParent();
2517 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2518 return F == &FirstDefinition;
2521Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(
Type *AggrTy,
2523 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2524 auto *Leaf =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
2526 AggrConstTypes[Leaf] = ElemTy;
2529 SmallVector<Value *, 4> Elems;
2531 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2534 DenseMap<Type *, Instruction *> LeafByType;
2535 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2537 auto &
Entry = LeafByType[ElemTy];
2539 Entry = MakeLeaf(ElemTy);
2543 auto *Composite =
B.CreateIntrinsic(Intrinsic::spv_const_composite,
2544 {
B.getInt32Ty()}, Elems);
2546 AggrConstTypes[Composite] = AggrTy;
2550void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2561 deduceElementTypeHelper(&GV,
false);
2563 Value *InitOp = Init;
2571 B.CreateIntrinsic(Intrinsic::spv_poison, {
B.getInt32Ty()}, {});
2576 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2581 auto *InitInst =
B.CreateIntrinsic(Intrinsic::spv_init_global,
2583 InitInst->setArgOperand(1, InitOp);
2586 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2592bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *
I,
2594 bool UnknownElemTypeI8) {
2600 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2607void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *
I,
2610 static StringMap<unsigned> ResTypeWellKnown = {
2611 {
"async_work_group_copy", WellKnownTypes::Event},
2612 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2613 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2617 bool IsKnown =
false;
2622 std::string DemangledName =
2625 if (DemangledName.length() > 0)
2627 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2628 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2629 if (ResIt != ResTypeWellKnown.
end()) {
2632 switch (ResIt->second) {
2633 case WellKnownTypes::Event:
2640 switch (DecorationId) {
2643 case FPDecorationId::SAT:
2646 case FPDecorationId::RTE:
2648 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2650 case FPDecorationId::RTZ:
2652 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2654 case FPDecorationId::RTP:
2656 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2658 case FPDecorationId::RTN:
2660 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2666 Type *Ty =
I->getType();
2669 Type *TypeToAssign = Ty;
2672 auto It = AggrConstTypes.
find(
II);
2673 if (It == AggrConstTypes.
end())
2675 TypeToAssign = It->second;
2676 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2677 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2678 TypeToAssign = It->second;
2680 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2681 TypeToAssign = It->second;
2685 for (
const auto &
Op :
I->operands()) {
2692 Type *OpTy =
Op->getType();
2694 CallInst *AssignCI =
2699 Type *OpTy =
Op->getType();
2714 CallInst *AssignCI =
2724bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2725 Instruction *Inst) {
2727 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2737void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *
I,
2739 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2741 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2746 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2747 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2748 if (shouldTryToAddMemAliasingDecoration(
I)) {
2749 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2750 ? SPIRV::Decoration::AliasScopeINTEL
2751 : SPIRV::Decoration::NoAliasINTEL;
2753 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2756 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2757 {
I->getType()}, {
Args});
2761 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2762 processMemAliasingDecoration(LLVMContext::MD_noalias);
2765 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2767 bool AllowFPMaxError =
2769 if (!AllowFPMaxError)
2773 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2777 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
2781 auto &Ctx =
B.getContext();
2783 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
2786 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
2788 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
2789 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
2792 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
2794 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
2796 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2804 &FPFastMathDefaultInfoMap,
2806 auto it = FPFastMathDefaultInfoMap.
find(
F);
2807 if (it != FPFastMathDefaultInfoMap.
end())
2815 SPIRV::FPFastMathMode::None);
2817 SPIRV::FPFastMathMode::None);
2819 SPIRV::FPFastMathMode::None);
2820 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
2826 size_t BitWidth = Ty->getScalarSizeInBits();
2830 assert(Index >= 0 && Index < 3 &&
2831 "Expected FPFastMathDefaultInfo for half, float, or double");
2832 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2833 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2834 return FPFastMathDefaultInfoVec[Index];
2837void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(
Module &M) {
2839 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2848 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
2850 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
2858 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
2861 [[maybe_unused]] GlobalVariable *GV =
2862 new GlobalVariable(M,
2863 Type::getInt32Ty(
M.getContext()),
2877 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
2878 FPFastMathDefaultInfoMap;
2880 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
2889 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2891 "Expected 4 operands for FPFastMathDefault");
2897 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2899 SPIRV::FPFastMathDefaultInfo &
Info =
2902 Info.FPFastMathDefault =
true;
2903 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
2905 "Expected no operands for ContractionOff");
2909 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2911 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2912 Info.ContractionOff =
true;
2914 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
2916 "Expected 1 operand for SignedZeroInfNanPreserve");
2917 unsigned TargetWidth =
2922 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2926 assert(Index >= 0 && Index < 3 &&
2927 "Expected FPFastMathDefaultInfo for half, float, or double");
2928 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2929 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2930 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
2934 std::unordered_map<unsigned, GlobalVariable *> GlobalVars;
2935 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
2936 if (FPFastMathDefaultInfoVec.
empty())
2939 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2940 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
2943 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
2944 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
2948 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
2950 "and AllowContract");
2952 if (
Info.SignedZeroInfNanPreserve &&
2954 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2955 SPIRV::FPFastMathMode::NSZ))) {
2956 if (
Info.FPFastMathDefault)
2958 "SignedZeroInfNanPreserve but at least one of "
2959 "NotNaN/NotInf/NSZ is enabled.");
2962 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
2963 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
2964 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
2966 "AllowTransform requires AllowReassoc and "
2967 "AllowContract to be set.");
2970 auto it = GlobalVars.find(Flags);
2971 GlobalVariable *GV =
nullptr;
2972 if (it != GlobalVars.end()) {
2978 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
2981 GV =
new GlobalVariable(M,
2982 Type::getInt32Ty(
M.getContext()),
2987 GlobalVars[
Flags] = GV;
2993void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *
I,
2996 bool IsConstComposite =
2997 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
2998 if (IsConstComposite && TrackConstants) {
3000 auto t = AggrConsts.
find(
I);
3004 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3006 NewOp->setArgOperand(0,
I);
3009 for (
const auto &
Op :
I->operands()) {
3013 unsigned OpNo =
Op.getOperandNo();
3014 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3015 (!
II->isBundleOperand(OpNo) &&
3016 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3020 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3021 :
B.SetInsertPoint(
I);
3024 Type *OpTy =
Op->getType();
3032 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3034 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3035 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3037 SmallVector<Value *, 2>
Args = {
3040 CallInst *PtrCasted =
3041 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
3046 I->setOperand(OpNo, NewOp);
3048 if (Named.insert(
I).second)
3052Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *
F,
3054 std::unordered_set<Function *> FVisited;
3055 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3058Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
3059 Function *
F,
unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
3061 if (!FVisited.insert(
F).second)
3064 std::unordered_set<Value *> Visited;
3067 for (User *U :
F->users()) {
3079 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3082 for (User *OpU : OpArg->
users()) {
3084 if (!Inst || Inst == CI)
3087 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3094 if (FVisited.find(OuterF) != FVisited.end())
3096 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3097 if (OuterF->
getArg(i) == OpArg) {
3098 Lookup.push_back(std::make_pair(OuterF, i));
3105 for (
auto &Pair :
Lookup) {
3106 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3113void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *
F,
3115 B.SetInsertPointPastAllocas(
F);
3129 for (User *U :
F->users()) {
3145 for (User *U : Arg->
users()) {
3149 CI->
getParent()->getParent() == CurrF) {
3151 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3162void SPIRVEmitIntrinsics::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3163 B.SetInsertPointPastAllocas(
F);
3169 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3171 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3173 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3185 bool IsNewFTy =
false;
3201bool SPIRVEmitIntrinsics::processFunctionPointers(
Module &M) {
3204 if (
F.isIntrinsic())
3206 if (
F.isDeclaration()) {
3207 for (User *U :
F.users()) {
3220 for (User *U :
F.users()) {
3222 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3224 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3225 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3232 if (Worklist.
empty())
3235 LLVMContext &Ctx =
M.getContext();
3240 for (Function *
F : Worklist) {
3242 for (
const auto &Arg :
F->args())
3244 IRB.CreateCall(
F, Args);
3246 IRB.CreateRetVoid();
3252void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3253 DenseMap<Function *, CallInst *> Ptrcasts;
3254 for (
auto It : FDeclPtrTys) {
3256 for (
auto *U :
F->users()) {
3261 for (
auto [Idx, ElemTy] : It.second) {
3269 B.SetInsertPointPastAllocas(Arg->
getParent());
3273 }
else if (isaGEP(Param)) {
3274 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3283 .getFirstNonPHIOrDbgOrAlloca());
3304SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP) {
3311 Type *SrcTy =
GEP->getSourceElementType();
3312 SmallVector<Value *, 8> Indices(
GEP->indices());
3314 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3315 Indices.erase(Indices.begin());
3316 SrcTy = ArrTy->getElementType();
3318 GEP->getNoWrapFlags(),
"",
3319 GEP->getIterator());
3324void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &
F,
3331 if (
ST->canUseExtension(
3332 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3333 for (BasicBlock &BB :
F) {
3335 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3339 SmallVector<unsigned, 1>
Ops =
3341 unsigned LC =
Ops[0];
3342 if (LC == SPIRV::LoopControl::None)
3346 B.SetInsertPoint(Term);
3347 SmallVector<Value *, 4> IntrArgs;
3348 for (
unsigned Op :
Ops)
3350 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3357 DominatorTree DT(
F);
3362 for (Loop *L : LI.getLoopsInPreorder()) {
3371 SmallVector<unsigned, 1> LoopControlOps =
3373 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3377 B.SetInsertPoint(Header->getTerminator());
3380 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3381 for (
unsigned Imm : LoopControlOps)
3382 Args.emplace_back(
B.getInt32(Imm));
3383 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3387bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3388 if (
Func.isDeclaration())
3392 GR =
ST.getSPIRVGlobalRegistry();
3396 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3401 AggrConstTypes.
clear();
3403 DeletedInstrs.
clear();
3405 processParamTypesByFunHeader(CurrF,
B);
3409 SmallPtrSet<Instruction *, 4> DeadInsts;
3414 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3418 GR->addDeducedElementType(SGEP,
3423 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3425 GEP->replaceAllUsesWith(NewGEP);
3429 if (
Type *GepTy = getGEPType(
GEP))
3433 for (
auto *
I : DeadInsts) {
3434 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3435 I->eraseFromParent();
3445 Type *ElTy =
SI->getValueOperand()->getType();
3450 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3451 for (
auto &GV :
Func.getParent()->globals())
3452 processGlobalValue(GV,
B);
3454 preprocessUndefs(
B);
3455 preprocessPoisons(
B);
3456 simplifyNullAddrSpaceCasts();
3457 preprocessCompositeConstants(
B);
3459 for (BasicBlock &BB : Func)
3460 for (PHINode &Phi : BB.
phis())
3461 if (
Phi.getType()->isAggregateType()) {
3462 AggrConstTypes[&
Phi] =
Phi.getType();
3463 Phi.mutateType(
B.getInt32Ty());
3466 preprocessBoolVectorBitcasts(Func);
3470 applyDemangledPtrArgTypes(
B);
3473 for (
auto &
I : Worklist) {
3475 if (isConvergenceIntrinsic(
I))
3478 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3480 insertAssignTypeIntrs(
I,
B);
3481 insertPtrCastOrAssignTypeInstr(
I,
B);
3485 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3486 insertAssignPtrTypeIntrs(
I,
B,
true);
3489 useRoundingMode(FPI,
B);
3494 SmallPtrSet<Instruction *, 4> IncompleteRets;
3496 deduceOperandElementType(&
I, &IncompleteRets);
3500 for (BasicBlock &BB : Func)
3501 for (PHINode &Phi : BB.
phis())
3503 deduceOperandElementType(&Phi,
nullptr);
3505 for (
auto *
I : Worklist) {
3506 if (DeletedInstrs.
count(
I))
3508 TrackConstants =
true;
3518 if (isConvergenceIntrinsic(
I))
3522 processInstrAfterVisit(
I,
B);
3525 emitUnstructuredLoopControls(Func,
B);
3531bool SPIRVEmitIntrinsics::postprocessTypes(
Module &M) {
3532 if (!GR || TodoTypeSz == 0)
3535 unsigned SzTodo = TodoTypeSz;
3536 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3541 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3542 Type *KnownTy = GR->findDeducedElementType(
Op);
3543 if (!KnownTy || !AssignCI)
3549 std::unordered_set<Value *> Visited;
3550 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3551 if (ElemTy != KnownTy) {
3552 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3553 propagateElemType(CI, ElemTy, VisitedSubst);
3560 if (
Op->hasUseList()) {
3561 for (User *U :
Op->users()) {
3568 if (TodoTypeSz == 0)
3573 SmallPtrSet<Instruction *, 4> IncompleteRets;
3575 auto It = ToProcess.
find(&
I);
3576 if (It == ToProcess.
end())
3578 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3579 if (It->second.size() == 0)
3581 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3582 if (TodoTypeSz == 0)
3587 return SzTodo > TodoTypeSz;
3591void SPIRVEmitIntrinsics::parseFunDeclarations(
Module &M) {
3593 if (!
F.isDeclaration() ||
F.isIntrinsic())
3597 if (DemangledName.empty())
3601 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3602 DemangledName,
ST.getPreferredInstructionSet());
3603 if (Opcode != SPIRV::OpGroupAsyncCopy)
3606 SmallVector<unsigned> Idxs;
3615 LLVMContext &Ctx =
F.getContext();
3617 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3618 if (!TypeStrs.
size())
3621 for (
unsigned Idx : Idxs) {
3622 if (Idx >= TypeStrs.
size())
3625 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3628 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3633bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3634 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3636 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3637 if (!
ST.canUseExtension(
3638 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3639 I.getContext().emitError(
3640 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3644 I.eraseFromParent();
3650 Value *Ptrs =
I.getArgOperand(0);
3652 Value *Passthru =
I.getArgOperand(2);
3655 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3657 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3662 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3664 I.eraseFromParent();
3668 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3669 if (!
ST.canUseExtension(
3670 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3671 I.getContext().emitError(
3672 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3675 I.eraseFromParent();
3681 Value *Values =
I.getArgOperand(0);
3682 Value *Ptrs =
I.getArgOperand(1);
3687 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3689 SmallVector<Value *, 4>
Args = {Values, Ptrs,
B.getInt32(Alignment),
Mask};
3693 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3694 I.eraseFromParent();
3705void SPIRVEmitIntrinsics::preprocessBoolVectorBitcasts(Function &
F) {
3706 struct BoolVecBitcast {
3708 FixedVectorType *BoolVecTy;
3712 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3714 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3722 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3724 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3728 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3730 Value *Src = BC->getOperand(0);
3731 unsigned BoolVecN = BoolVecTy->getNumElements();
3733 Type *IntTy =
B.getIntNTy(BoolVecN);
3739 IntVal = ConstantInt::get(IntTy, 0);
3740 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3741 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3742 Value *Ext =
B.CreateZExt(Elem, IntTy);
3744 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3745 IntVal =
B.CreateOr(IntVal, Ext);
3751 if (!Src->getType()->isIntegerTy())
3752 IntVal =
B.CreateBitCast(Src, IntTy);
3757 if (!SrcIsBoolVec) {
3760 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3763 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
3764 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
3770 if (!BC->getDestTy()->isIntegerTy())
3771 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
3774 BC->replaceAllUsesWith(Result);
3775 BC->eraseFromParent();
3779bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(
Module &M) {
3783 if (!
F.isIntrinsic())
3786 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
3791 Changed |= processMaskedMemIntrinsic(*
II);
3795 F.eraseFromParent();
3801bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
3804 Changed |= convertMaskedMemIntrinsics(M);
3806 parseFunDeclarations(M);
3807 insertConstantsForFPFastMathDefault(M);
3818 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
3820 processParamTypes(&
F,
B);
3824 CanTodoType =
false;
3825 Changed |= postprocessTypes(M);
3828 Changed |= processFunctionPointers(M);
3835 SPIRVEmitIntrinsics Legacy(TM);
3836 if (Legacy.runOnModule(M))
3842 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
static Value * getOpcode(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
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 bool isAbortCall(const Instruction &I, const SPIRVSubtarget &ST)
static cl::opt< bool > SpirvEmitOpNames("spirv-emit-op-names", cl::desc("Emit OpName for all instructions"), cl::init(false))
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool isSpvAggrPlaceholder(const Value *V)
static bool precededByAbortIntrinsic(const UnreachableInst &I, const SPIRVSubtarget &ST)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
StringSet - A set-like wrapper for the StringMap.
static SymbolRef::Type getType(const Symbol *Sym)
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
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
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned arg_size() const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static 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)
Type * getParamType(unsigned i) const
Parameter type accessors.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
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 bool isDebugOrPseudoInst() const LLVM_READONLY
Return true if the instruction is a DbgInfoIntrinsic or PseudoProbeInst.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
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)
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.
This function has undefined behavior.
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.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
IntrinsicID_match m_Intrinsic()
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_Value()
Match an arbitrary value and ignore it.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
@ CE
Windows NT (Windows on ARM)
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)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
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)