29#include "llvm/IR/IntrinsicsSPIRV.h"
62#define DEBUG_TYPE "spirv-emit-intrinsics"
66 cl::desc(
"Emit OpName for all instructions"),
70#define GET_BuiltinGroup_DECL
71#include "SPIRVGenTables.inc"
76class GlobalVariableUsers {
77 template <
typename T1,
typename T2>
78 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
80 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
82 void collectGlobalUsers(
83 const GlobalVariable *GV,
84 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
85 &GlobalIsUsedByGlobal) {
87 while (!
Stack.empty()) {
91 GlobalIsUsedByFun[GV].insert(
I->getFunction());
96 GlobalIsUsedByGlobal[GV].insert(UserGV);
101 Stack.append(
C->user_begin(),
C->user_end());
105 bool propagateGlobalToGlobalUsers(
106 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
107 &GlobalIsUsedByGlobal) {
110 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
111 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
112 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
113 auto It = GlobalIsUsedByGlobal.find(UserGV);
114 if (It == GlobalIsUsedByGlobal.end())
122 void propagateGlobalToFunctionReferences(
123 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
124 &GlobalIsUsedByGlobal) {
125 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
126 auto &UserFunctions = GlobalIsUsedByFun[GV];
127 for (
const GlobalVariable *UserGV : UserGlobals) {
128 auto It = GlobalIsUsedByFun.find(UserGV);
129 if (It == GlobalIsUsedByFun.end())
140 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
141 GlobalIsUsedByGlobal;
142 GlobalIsUsedByFun.clear();
143 for (GlobalVariable &GV :
M.globals())
144 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
147 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
150 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
153 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
154 const FunctionSetType &
155 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
156 auto It = GlobalIsUsedByFun.find(&GV);
157 if (It != GlobalIsUsedByFun.end())
160 static const FunctionSetType
Empty{};
165static bool isaGEP(
const Value *V) {
171static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
177 return AT->getNumElements();
183class SPIRVEmitIntrinsics
185 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
186 const SPIRVTargetMachine &TM;
187 SPIRVGlobalRegistry *GR =
nullptr;
189 bool TrackConstants =
true;
190 bool HaveFunPtrs =
false;
191 DenseMap<Instruction *, Constant *> AggrConsts;
192 DenseMap<Instruction *, Type *> AggrConstTypes;
193 SmallPtrSet<Instruction *, 0> AggrStores;
194 GlobalVariableUsers GVUsers;
195 SmallPtrSet<Value *, 0> Named;
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 SmallPtrSet<Instruction *, 0> TypeValidated;
230 enum WellKnownTypes { Event };
233 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
234 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
235 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
236 bool UnknownElemTypeI8,
237 bool IgnoreKnownType =
false);
238 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
239 bool UnknownElemTypeI8);
240 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
241 SmallPtrSetImpl<Value *> &Visited,
242 bool UnknownElemTypeI8);
244 SmallPtrSetImpl<Value *> &Visited,
245 bool UnknownElemTypeI8);
247 bool UnknownElemTypeI8);
250 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
251 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
252 SmallPtrSetImpl<Value *> &Visited,
253 bool UnknownElemTypeI8);
257 deduceOperandElementType(Instruction *
I,
258 SmallPtrSetImpl<Instruction *> *IncompleteRets,
259 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
260 bool IsPostprocessing =
false);
265 void simplifyNullAddrSpaceCasts();
267 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
268 bool IsPostprocessing);
270 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
272 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
273 bool UnknownElemTypeI8);
275 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
277 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
278 Type *ExpectedElementType,
279 unsigned OperandToReplace,
281 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
282 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
284 void insertConstantsForFPFastMathDefault(
Module &M);
286 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
288 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
289 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
290 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx,
291 SmallPtrSetImpl<Function *> &FVisited);
293 bool deduceOperandElementTypeCalledFunction(
295 Type *&KnownElemTy,
bool &Incomplete);
296 void deduceOperandElementTypeFunctionPointer(
298 Type *&KnownElemTy,
bool IsPostprocessing);
299 bool deduceOperandElementTypeFunctionRet(
300 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
301 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
304 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
305 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
306 DenseMap<Function *, CallInst *> Ptrcasts);
308 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
311 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
312 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
313 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
314 SmallPtrSetImpl<Value *> &Visited,
315 DenseMap<Function *, CallInst *> Ptrcasts);
318 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
319 Instruction *Dest,
bool DeleteOld =
true);
323 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
326 bool postprocessTypes(
Module &M);
327 bool processFunctionPointers(
Module &M);
328 void parseFunDeclarations(
Module &M);
329 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
330 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
331 bool convertMaskedMemIntrinsics(
Module &M);
332 void preprocessBoolVectorBitcasts(Function &
F);
334 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
351 bool walkLogicalAccessChain(
352 GetElementPtrInst &
GEP,
353 const std::function<
void(
Type *PointedType, uint64_t Index)>
356 uint64_t Multiplier)> &OnDynamicIndexing);
358 bool walkLogicalAccessChainDynamic(
359 Type *CurType,
Value *Operand, uint64_t Multiplier,
360 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
361 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing);
363 bool walkLogicalAccessChainConstant(
365 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing);
371 Type *getGEPType(GetElementPtrInst *
GEP);
378 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
380 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
384 SPIRVEmitIntrinsics(
const SPIRVTargetMachine &TM) : ModulePass(ID), TM(TM) {}
387 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
390 Instruction *visitInsertElementInst(InsertElementInst &
I);
391 Instruction *visitExtractElementInst(ExtractElementInst &
I);
393 Instruction *visitExtractValueInst(ExtractValueInst &
I);
397 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
401 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
403 bool runOnModule(
Module &M)
override;
405 void getAnalysisUsage(AnalysisUsage &AU)
const override {
406 ModulePass::getAnalysisUsage(AU);
412 Intrinsic::experimental_convergence_loop,
413 Intrinsic::experimental_convergence_anchor>());
416bool expectIgnoredInIRTranslation(
const Instruction *
I) {
418 Intrinsic::spv_resource_handlefrombinding,
419 Intrinsic::spv_resource_getbasepointer,
420 Intrinsic::spv_resource_getpointer>());
427 return getPointerRoot(V);
433char SPIRVEmitIntrinsics::ID = 0;
436 "SPIRV emit intrinsics",
false,
false)
450 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
463 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
469 B.SetCurrentDebugLocation(
I->getDebugLoc());
470 if (
I->getType()->isVoidTy())
471 B.SetInsertPoint(
I->getNextNode());
473 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
483 if (
I->getType()->isTokenTy())
485 "does not support token type",
490 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
491 expectIgnoredInIRTranslation(
I))
502 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
513 std::vector<Value *> Args = {
516 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
519void SPIRVEmitIntrinsics::replaceAllUsesWith(
Value *Src,
Value *Dest,
523 if (isTodoType(Src)) {
526 insertTodoType(Dest);
530void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
535 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
536 Src->eraseFromParent();
539 if (Named.
insert(Dest).second)
554 V = V->stripPointerCasts();
575Type *SPIRVEmitIntrinsics::reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
576 bool IsPostprocessing) {
580 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
594 if (UnknownElemTypeI8) {
595 if (!IsPostprocessing)
603CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *
F,
Value *
Op,
611 B.SetInsertPointPastAllocas(OpA->getParent());
614 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
616 Type *OpTy =
Op->getType();
620 CallInst *PtrCasted =
621 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
626void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
628 DenseMap<Function *, CallInst *> Ptrcasts) {
630 CallInst *PtrCastedI =
nullptr;
631 auto It = Ptrcasts.
find(
F);
632 if (It == Ptrcasts.
end()) {
633 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
634 Ptrcasts[
F] = PtrCastedI;
636 PtrCastedI = It->second;
638 I->replaceUsesOfWith(
Op, PtrCastedI);
641void SPIRVEmitIntrinsics::propagateElemType(
643 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
644 DenseMap<Function *, CallInst *> Ptrcasts;
646 for (
auto *U :
Users) {
649 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
654 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
655 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
659void SPIRVEmitIntrinsics::propagateElemTypeRec(
661 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
662 SmallPtrSet<Value *, 0> Visited;
663 DenseMap<Function *, CallInst *> Ptrcasts;
664 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
665 std::move(Ptrcasts));
668void SPIRVEmitIntrinsics::propagateElemTypeRec(
670 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
671 SmallPtrSetImpl<Value *> &Visited,
672 DenseMap<Function *, CallInst *> Ptrcasts) {
676 for (
auto *U :
Users) {
679 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
684 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
685 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
693SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
694 bool UnknownElemTypeI8) {
695 SmallPtrSet<Value *, 0> Visited;
696 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
700Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
701 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
702 bool UnknownElemTypeI8) {
707 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
718Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
719 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
731 for (User *OpU :
Op->users()) {
733 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
746 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
755Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I,
756 bool UnknownElemTypeI8) {
757 SmallPtrSet<Value *, 0> Visited;
758 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
761void SPIRVEmitIntrinsics::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
Type *RefTy,
762 bool UnknownElemTypeI8) {
764 if (!UnknownElemTypeI8)
773bool SPIRVEmitIntrinsics::walkLogicalAccessChainDynamic(
774 Type *CurType,
Value *Operand, uint64_t Multiplier,
775 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
776 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
782 if (
ST->getNumElements() == 0)
784 CurType =
ST->getElementType(0);
785 OnLiteralIndexing(CurType, 0);
793 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
794 return AT ==
nullptr;
797bool SPIRVEmitIntrinsics::walkLogicalAccessChainConstant(
799 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
804 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
808 CurType = AT->getElementType();
809 OnLiteralIndexing(CurType, Index);
811 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
814 const auto &STL =
DL.getStructLayout(ST);
815 unsigned Element = STL->getElementContainingOffset(
Offset);
816 Offset -= STL->getElementOffset(Element);
817 CurType =
ST->getElementType(Element);
818 OnLiteralIndexing(CurType, Element);
820 Type *EltTy = VT->getElementType();
821 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
822 assert(EltSizeBits % 8 == 0 &&
823 "Element type size in bits must be a multiple of 8.");
824 uint32_t EltTypeSize = EltSizeBits / 8;
829 OnLiteralIndexing(CurType, Index);
839bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
840 GetElementPtrInst &
GEP,
841 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
842 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
845 std::optional<uint64_t> MultiplierOpt =
846 getByteAddressingMultiplier(
GEP.getSourceElementType());
847 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
848 uint64_t Multiplier = *MultiplierOpt;
851 Value *Src = getPointerRoot(
GEP.getPointerOperand());
852 Type *CurType = deduceElementType(Src,
true);
856 return walkLogicalAccessChainConstant(
857 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
859 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
860 OnLiteralIndexing, OnDynamicIndexing);
864SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP) {
867 B.SetInsertPoint(&
GEP);
869 std::vector<Value *> Indices;
870 Indices.push_back(ConstantInt::get(
871 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
872 walkLogicalAccessChain(
874 [&Indices, &
B](
Type *EltType, uint64_t Index) {
876 ConstantInt::get(
B.getInt64Ty(), Index,
false));
879 uint64_t Multiplier) {
881 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
883 if (Multiplier == EltTypeSize) {
885 }
else if (EltTypeSize % Multiplier == 0) {
888 EltTypeSize / Multiplier,
892 ConstantInt::get(
Offset->getType(), Multiplier,
895 Index =
B.CreateUDiv(Index,
896 ConstantInt::get(
Offset->getType(), EltTypeSize,
900 Indices.push_back(Index);
904 SmallVector<Value *, 4>
Args;
905 Args.push_back(
B.getInt1(
GEP.isInBounds()));
906 Args.push_back(
GEP.getOperand(0));
908 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
909 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
913Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *
GEP) {
915 Type *CurType =
GEP->getResultElementType();
917 bool Interrupted = walkLogicalAccessChain(
918 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
919 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
921 return Interrupted ?
GEP->getResultElementType() : CurType;
924Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *
Ref) {
925 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
927 return getGEPTypeLogical(
Ref);
934 Ty =
Ref->getSourceElementType();
938 Ty =
Ref->getResultElementType();
943Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
944 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
945 bool IgnoreKnownType) {
951 if (!IgnoreKnownType)
963 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
965 Ty = getGEPType(
Ref);
967 Ty = SGEP->getResultElementType();
972 KnownTy =
Op->getType();
974 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
977 Ty = SPIRV::getOriginalFunctionType(*Fn);
980 Ty = deduceElementTypeByValueDeep(
982 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
986 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
988 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
990 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
992 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
994 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
999 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1003 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1005 Type *BestTy =
nullptr;
1007 DenseMap<Type *, unsigned> PhiTys;
1008 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1009 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1016 if (It.first->second > MaxN) {
1017 MaxN = It.first->second;
1025 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1026 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1031 static StringMap<unsigned> ResTypeByArg = {
1035 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1036 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1037 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1038 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1039 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1040 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1044 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1045 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1047 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1048 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1049 for (User *U :
II->users()) {
1054 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1056 Ty = HandleType->getTypeParameter(0);
1057 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1071 }
else if (
II &&
II->getIntrinsicID() ==
1072 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1076 std::string DemangledName =
1078 if (DemangledName.length() > 0)
1079 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1080 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1081 if (AsArgIt != ResTypeByArg.
end())
1082 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1083 Visited, UnknownElemTypeI8);
1090 if (Ty && !IgnoreKnownType) {
1101Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1102 bool UnknownElemTypeI8) {
1103 SmallPtrSet<Value *, 0> Visited;
1104 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1108SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
Type *OrigTy,
1109 SmallPtrSetImpl<Value *> &Visited,
1110 bool UnknownElemTypeI8) {
1119 if (!Visited.
insert(U).second)
1124 bool Change =
false;
1125 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1127 assert(
Op &&
"Operands should not be null.");
1128 Type *OpTy =
Op->getType();
1131 if (
Type *NestedTy =
1132 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1139 Change |= Ty != OpTy;
1147 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1148 Type *OpTy = ArrTy->getElementType();
1151 if (
Type *NestedTy =
1152 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1159 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1165 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1166 Type *OpTy = VecTy->getElementType();
1169 if (
Type *NestedTy =
1170 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1177 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1187Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I,
bool UnknownElemTypeI8) {
1188 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1190 if (!UnknownElemTypeI8)
1193 return IntegerType::getInt8Ty(
I->getContext());
1197 Value *PointerOperand) {
1203 return I->getType();
1211bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1213 Type *&KnownElemTy,
bool &Incomplete) {
1217 std::string DemangledName =
1219 if (DemangledName.length() > 0 &&
1221 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1222 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1223 DemangledName,
ST.getPreferredInstructionSet());
1224 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1225 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1231 KnownElemTy = ElemTy;
1232 Ops.push_back(std::make_pair(
Op, i));
1234 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1241 case SPIRV::OpAtomicFAddEXT:
1242 case SPIRV::OpAtomicFMinEXT:
1243 case SPIRV::OpAtomicFMaxEXT:
1244 case SPIRV::OpAtomicLoad:
1245 case SPIRV::OpAtomicCompareExchangeWeak:
1246 case SPIRV::OpAtomicCompareExchange:
1247 case SPIRV::OpAtomicExchange:
1248 case SPIRV::OpAtomicIAdd:
1249 case SPIRV::OpAtomicISub:
1250 case SPIRV::OpAtomicOr:
1251 case SPIRV::OpAtomicXor:
1252 case SPIRV::OpAtomicAnd:
1253 case SPIRV::OpAtomicUMin:
1254 case SPIRV::OpAtomicUMax:
1255 case SPIRV::OpAtomicSMin:
1256 case SPIRV::OpAtomicSMax: {
1261 Incomplete = isTodoType(
Op);
1262 Ops.push_back(std::make_pair(
Op, 0));
1264 case SPIRV::OpAtomicStore: {
1273 Incomplete = isTodoType(
Op);
1274 Ops.push_back(std::make_pair(
Op, 0));
1283void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1285 Type *&KnownElemTy,
bool IsPostprocessing) {
1289 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1290 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1291 bool IsNewFTy =
false, IsIncomplete =
false;
1294 Type *ArgTy = Arg->getType();
1299 if (isTodoType(Arg))
1300 IsIncomplete =
true;
1302 IsIncomplete =
true;
1305 ArgTy = FTy->getFunctionParamType(ParmIdx);
1309 Type *RetTy = FTy->getReturnType();
1316 IsIncomplete =
true;
1318 IsIncomplete =
true;
1321 if (!IsPostprocessing && IsIncomplete)
1324 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1327bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1328 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1329 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1341 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1342 for (User *U :
F->users()) {
1350 propagateElemType(CI, PrevElemTy, VisitedSubst);
1360 for (Instruction *IncompleteRetI : *IncompleteRets)
1361 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1363 }
else if (IncompleteRets) {
1374void SPIRVEmitIntrinsics::deduceOperandElementType(
1375 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1376 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1378 Type *KnownElemTy =
nullptr;
1379 bool Incomplete =
false;
1385 Incomplete = isTodoType(
I);
1386 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1389 Ops.push_back(std::make_pair(
Op, i));
1395 Incomplete = isTodoType(
I);
1396 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1403 Incomplete = isTodoType(
I);
1404 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1408 KnownElemTy =
Ref->getSourceElementType();
1409 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1414 KnownElemTy =
Ref->getBaseType();
1415 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1418 KnownElemTy =
I->getType();
1425 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1434 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1438 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1443 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1451 Incomplete = isTodoType(
Ref->getPointerOperand());
1452 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1460 Incomplete = isTodoType(
Ref->getPointerOperand());
1461 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1467 Incomplete = isTodoType(
I);
1468 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1471 Ops.push_back(std::make_pair(
Op, i));
1479 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1480 IsPostprocessing, KnownElemTy,
Op,
1483 Incomplete = isTodoType(CurrF);
1484 Ops.push_back(std::make_pair(
Op, 0));
1490 bool Incomplete0 = isTodoType(Op0);
1491 bool Incomplete1 = isTodoType(Op1);
1493 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1495 : GR->findDeducedElementType(Op0);
1497 KnownElemTy = ElemTy0;
1498 Incomplete = Incomplete0;
1499 Ops.push_back(std::make_pair(Op1, 1));
1500 }
else if (ElemTy1) {
1501 KnownElemTy = ElemTy1;
1502 Incomplete = Incomplete1;
1503 Ops.push_back(std::make_pair(Op0, 0));
1507 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1508 else if (HaveFunPtrs)
1509 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1514 if (!KnownElemTy ||
Ops.size() == 0)
1519 for (
auto &OpIt :
Ops) {
1523 Type *AskTy =
nullptr;
1524 CallInst *AskCI =
nullptr;
1525 if (IsPostprocessing && AskOps) {
1531 if (Ty == KnownElemTy)
1534 Type *OpTy =
Op->getType();
1540 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1547 else if (!IsPostprocessing)
1551 if (AssignCI ==
nullptr) {
1560 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1561 std::make_pair(
I,
Op)};
1562 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1566 CallInst *PtrCastI =
1567 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1568 if (OpIt.second == std::numeric_limits<unsigned>::max())
1571 I->setOperand(OpIt.second, PtrCastI);
1577void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1582 if (isAssignTypeInstr(U)) {
1583 B.SetInsertPoint(U);
1584 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1585 CallInst *AssignCI =
1586 B.CreateIntrinsic(Intrinsic::spv_assign_type, {
New->getType()},
Args);
1588 U->eraseFromParent();
1591 U->replaceUsesOfWith(Old, New);
1599 Type *NewArgTy =
New->getType();
1601 if (NewArgTy != ExpectedArgTy) {
1604 M, Intrinsic::spv_abort, {NewArgTy});
1614 "aggregate PHI/select/freeze should have been mutated to value-id "
1616 U->replaceUsesOfWith(Old, New);
1621 New->copyMetadata(*Old);
1625void SPIRVEmitIntrinsics::preprocessUndefs(
IRBuilder<> &
B) {
1629 SmallVector<Instruction *, 16> Insts;
1633 for (Instruction *
I : Insts) {
1634 bool BPrepared =
false;
1635 for (
auto &
Op :
I->operands()) {
1637 if (!AggrUndef || !
Op->getType()->isAggregateType())
1642 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1643 "lowered as undef\n");
1649 auto *IntrUndef =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
1650 I->replaceUsesOfWith(
Op, IntrUndef);
1651 AggrConsts[IntrUndef] = AggrUndef;
1652 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1657void SPIRVEmitIntrinsics::preprocessPoisons(
IRBuilder<> &
B) {
1663 bool BPrepared =
false;
1666 for (
unsigned Idx = 0; Idx <
I.getNumOperands(); ++Idx) {
1669 if (!
Poison ||
Op->getType()->isMetadataTy())
1672 Type *OpTy =
Op->getType();
1673 Value *Replacement =
nullptr;
1680 B.CreateIntrinsic(Intrinsic::spv_poison, {
B.getInt32Ty()}, {});
1682 AggrConstTypes[
Call] = OpTy;
1686 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1687 else if (!BPrepared) {
1691 Replacement =
B.CreateIntrinsic(Intrinsic::spv_poison, {OpTy}, {});
1693 I.setOperand(Idx, Replacement);
1702void SPIRVEmitIntrinsics::simplifyNullAddrSpaceCasts() {
1706 ASC->replaceAllUsesWith(
1708 ASC->eraseFromParent();
1712void SPIRVEmitIntrinsics::preprocessCompositeConstants(
IRBuilder<> &
B) {
1716 std::queue<Instruction *> Worklist;
1720 while (!Worklist.empty()) {
1721 auto *
I = Worklist.front();
1724 bool KeepInst =
false;
1725 for (
const auto &
Op :
I->operands()) {
1727 Type *ResTy =
nullptr;
1730 ResTy = COp->getType();
1742 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1745 auto PrepareInsert = [&]() {
1748 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1749 :
B.SetInsertPoint(
I);
1754 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1755 Args.push_back(COp->getElementAsConstant(i));
1761 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1766 Type *PoisonTy =
Op->getType();
1768 auto *
Call =
B.CreateIntrinsic(Intrinsic::spv_poison,
1769 {
B.getInt32Ty()}, {});
1771 AggrConstTypes[
Call] = PoisonTy;
1774 Op =
B.CreateIntrinsic(Intrinsic::spv_poison, {PoisonTy}, {});
1781 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {
Args});
1785 AggrConsts[CI] = AggrConst;
1786 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1798 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1803 unsigned RoundingModeDeco,
1810 ConstantInt::get(
Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1819 MDNode *SaturatedConversionNode =
1821 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1841 MDString *ConstraintString =
1850 B.SetInsertPoint(&
Call);
1851 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1856void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1859 if (!
RM.has_value())
1861 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1862 switch (
RM.value()) {
1866 case RoundingMode::NearestTiesToEven:
1867 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1869 case RoundingMode::TowardNegative:
1870 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1872 case RoundingMode::TowardPositive:
1873 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1875 case RoundingMode::TowardZero:
1876 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1878 case RoundingMode::Dynamic:
1879 case RoundingMode::NearestTiesToAway:
1883 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1889Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &
I) {
1893 B.SetInsertPoint(&
I);
1894 SmallVector<Value *, 4>
Args;
1896 Args.push_back(
I.getCondition());
1899 for (
auto &Case :
I.cases()) {
1900 Args.push_back(Case.getCaseValue());
1901 BBCases.
push_back(Case.getCaseSuccessor());
1904 CallInst *NewI =
B.CreateIntrinsic(Intrinsic::spv_switch,
1905 {
I.getOperand(0)->getType()}, {
Args});
1909 I.eraseFromParent();
1912 B.SetInsertPoint(ParentBB);
1913 IndirectBrInst *BrI =
B.CreateIndirectBr(
1916 for (BasicBlock *BBCase : BBCases)
1925Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &
I) {
1931 B.SetInsertPoint(&
I);
1933 SmallVector<Value *, 4>
Args;
1934 Args.push_back(
B.getInt1(
true));
1935 Args.push_back(
I.getOperand(0));
1936 Args.push_back(
B.getInt32(0));
1937 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1938 Args.push_back(SGEP->getIndexOperand(J));
1940 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, Types, Args);
1941 replaceAllUsesWithAndErase(
B, &
I, NewI);
1945Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &
I) {
1947 B.SetInsertPoint(&
I);
1952 unsigned N = RetVTy->getNumElements();
1953 Value *PtrOp =
I.getPointerOperand();
1955 Type *ResultPtrTy = RetVTy->getElementType();
1958 Value *InBounds =
B.getInt1(
I.isInBounds());
1959 Type *LanePointeeTy = getGEPType(&
I);
1960 Type *SrcElemTy =
I.getSourceElementType();
1969 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
1970 Value *LaneIdx =
B.getInt32(Lane);
1971 Value *ScalarPtr = PtrOp;
1975 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
1979 SmallVector<Value *, 4>
Args;
1980 Args.push_back(InBounds);
1981 Args.push_back(ScalarPtr);
1982 for (
Value *Idx :
I.indices()) {
1984 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
1986 Args.push_back(Idx);
1988 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
1990 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
1994 replaceAllUsesWithAndErase(
B, &
I, NewI);
2012 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2013 return buildLogicalAccessChainFromGEP(
I);
2018 Value *PtrOp =
I.getPointerOperand();
2019 Type *SrcElemTy =
I.getSourceElementType();
2020 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2023 if (ArrTy->getElementType() == SrcElemTy) {
2025 Type *FirstIdxType =
I.getOperand(1)->getType();
2026 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2027 for (
Value *Idx :
I.indices())
2031 SmallVector<Value *, 4>
Args;
2032 Args.push_back(
B.getInt1(
I.isInBounds()));
2033 Args.push_back(
I.getPointerOperand());
2036 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
2037 replaceAllUsesWithAndErase(
B, &
I, NewI);
2044 SmallVector<Value *, 4>
Args;
2045 Args.push_back(
B.getInt1(
I.isInBounds()));
2047 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
2048 replaceAllUsesWithAndErase(
B, &
I, NewI);
2052Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &
I) {
2054 B.SetInsertPoint(&
I);
2063 I.eraseFromParent();
2069 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_bitcast, {
Types}, {
Args});
2070 replaceAllUsesWithAndErase(
B, &
I, NewI);
2074void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
2076 Type *VTy =
V->getType();
2081 if (ElemTy != AssignedType)
2094 if (CurrentType == AssignedType)
2101 " for value " +
V->getName(),
2109void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
2110 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2115 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2116 if (PointerElemTy == ExpectedElementType ||
2122 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2124 bool FirstPtrCastOrAssignPtrType =
true;
2130 for (
auto User :
Pointer->users()) {
2133 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2134 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2135 II->getOperand(0) != Pointer)
2140 FirstPtrCastOrAssignPtrType =
false;
2141 if (
II->getOperand(1) != VMD ||
2148 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2153 if (
II->getParent() !=
I->getParent())
2156 I->setOperand(OperandToReplace,
II);
2171 if (FirstPtrCastOrAssignPtrType) {
2176 }
else if (isTodoType(Pointer)) {
2177 eraseTodoType(Pointer);
2185 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2186 std::make_pair(
I, Pointer)};
2188 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2200 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2206void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2211 replacePointerOperandWithPtrCast(
2212 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2218 Type *OpTy =
Op->getType();
2221 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2224 if (OpTy ==
Op->getType())
2225 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2226 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2231 Type *OpTy = LI->getType();
2236 Type *NewOpTy = OpTy;
2237 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2238 if (OpTy == NewOpTy)
2239 insertTodoType(Pointer);
2242 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2247 Type *OpTy =
nullptr;
2259 OpTy = GEPI->getSourceElementType();
2261 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2263 insertTodoType(Pointer);
2275 std::string DemangledName =
2279 bool HaveTypes =
false;
2297 for (User *U : CalledArg->
users()) {
2299 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2305 HaveTypes |= ElemTy !=
nullptr;
2310 if (DemangledName.empty() && !HaveTypes)
2328 Type *ExpectedType =
2330 if (!ExpectedType && !DemangledName.empty())
2331 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2332 DemangledName,
OpIdx,
I->getContext());
2333 if (!ExpectedType || ExpectedType->
isVoidTy())
2341 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2345Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &
I) {
2352 I.getOperand(1)->getType(),
2353 I.getOperand(2)->getType()};
2355 B.SetInsertPoint(&
I);
2357 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
2358 replaceAllUsesWithAndErase(
B, &
I, NewI);
2363SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &
I) {
2370 B.SetInsertPoint(&
I);
2372 I.getIndexOperand()->getType()};
2373 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2374 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
2375 replaceAllUsesWithAndErase(
B, &
I, NewI);
2379Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &
I) {
2381 B.SetInsertPoint(&
I);
2384 Value *AggregateOp =
I.getAggregateOperand();
2388 Args.push_back(AggregateOp);
2389 Args.push_back(
I.getInsertedValueOperand());
2390 for (
auto &
Op :
I.indices())
2391 Args.push_back(
B.getInt32(
Op));
2393 B.CreateIntrinsic(Intrinsic::spv_insertv, {
Types}, {
Args});
2394 replaceMemInstrUses(&
I, NewI,
B);
2398Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &
I) {
2400 B.SetInsertPoint(&
I);
2401 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2410 for (
auto &
Op :
I.indices())
2411 Args.push_back(
B.getInt32(
Op));
2413 B.CreateIntrinsic(Intrinsic::spv_extractv, {
I.getType()}, {
Args});
2414 replaceAllUsesWithAndErase(
B, &
I, NewI);
2418 for (
const Use &U : NewI->
uses()) {
2424 if (ArgNo < FT->getNumParams() &&
2425 !FT->getParamType(ArgNo)->isAggregateType()) {
2434Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &
I) {
2435 if (!
I.getType()->isAggregateType())
2438 B.SetInsertPoint(&
I);
2439 TrackConstants =
false;
2444 unsigned IntrinsicId;
2445 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2446 if (!
I.isAtomic()) {
2447 IntrinsicId = Intrinsic::spv_load;
2448 Args.push_back(
B.getInt32(
I.getAlign().value()));
2450 IntrinsicId = Intrinsic::spv_atomic_load;
2451 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2454 B.CreateIntrinsic(IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2456 replaceMemInstrUses(&
I, NewI,
B);
2460Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &
I) {
2464 B.SetInsertPoint(&
I);
2465 TrackConstants =
false;
2469 auto *PtrOp =
I.getPointerOperand();
2471 if (
I.getValueOperand()->getType()->isAggregateType()) {
2479 "Unexpected argument of aggregate type, should be spv_extractv!");
2483 unsigned IntrinsicId;
2484 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2486 if (!
I.isAtomic()) {
2487 IntrinsicId = Intrinsic::spv_store;
2488 Args.push_back(
B.getInt32(
I.getAlign().value()));
2490 IntrinsicId = Intrinsic::spv_atomic_store;
2491 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2493 auto *NewI =
B.CreateIntrinsic(
2494 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2496 I.eraseFromParent();
2500Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &
I) {
2501 Value *ArraySize =
nullptr;
2502 if (
I.isArrayAllocation()) {
2505 SPIRV::Extension::SPV_INTEL_variable_length_array))
2507 "array allocation: this instruction requires the following "
2508 "SPIR-V extension: SPV_INTEL_variable_length_array",
2510 ArraySize =
I.getArraySize();
2513 B.SetInsertPoint(&
I);
2514 TrackConstants =
false;
2515 Type *PtrTy =
I.getType();
2518 ?
B.CreateIntrinsic(Intrinsic::spv_alloca_array,
2519 {PtrTy, ArraySize->
getType()},
2520 {ArraySize,
B.getInt32(
I.getAlign().value())})
2521 :
B.CreateIntrinsic(
Intrinsic::spv_alloca, {PtrTy},
2522 {
B.getInt32(
I.getAlign().value())});
2523 replaceAllUsesWithAndErase(
B, &
I, NewI);
2527Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2528 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2530 B.SetInsertPoint(&
I);
2532 Args.push_back(
B.getInt32(
2533 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2536 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2537 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2538 uint32_t ScSem =
static_cast<uint32_t
>(
2540 Args.push_back(
B.getInt32(
2542 Args.push_back(
B.getInt32(
2544 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
2545 {
I.getPointerOperand()->getType()}, {
Args});
2546 replaceMemInstrUses(&
I, NewI,
B);
2555 case Intrinsic::spv_abort:
2557 case Intrinsic::trap:
2558 case Intrinsic::ubsantrap:
2560 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2580 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2581 "abort-like call must be the last non-debug instruction before its "
2582 "block's terminator");
2586Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &
I) {
2587 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2591 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2600 static const StringSet<> ArtificialGlobals{
"llvm.global.annotations",
2601 "llvm.compiler.used",
"llvm.used"};
2606 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2607 if (UserFunctions.contains(
F))
2612 if (!UserFunctions.empty())
2617 const Module &M = *
F->getParent();
2618 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2619 return F == &FirstDefinition;
2622Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(
Type *AggrTy,
2624 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2625 auto *Leaf =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
2627 AggrConstTypes[Leaf] = ElemTy;
2630 SmallVector<Value *, 4> Elems;
2632 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2635 DenseMap<Type *, Instruction *> LeafByType;
2636 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2638 auto &
Entry = LeafByType[ElemTy];
2640 Entry = MakeLeaf(ElemTy);
2644 auto *Composite =
B.CreateIntrinsic(Intrinsic::spv_const_composite,
2645 {
B.getInt32Ty()}, Elems);
2647 AggrConstTypes[Composite] = AggrTy;
2651void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2661 deduceElementTypeHelper(&GV,
false);
2666 Value *InitOp = Init;
2674 B.CreateIntrinsic(Intrinsic::spv_poison, {
B.getInt32Ty()}, {});
2679 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2684 auto *InitInst =
B.CreateIntrinsic(Intrinsic::spv_init_global,
2686 InitInst->setArgOperand(1, InitOp);
2689 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2695bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *
I,
2697 bool UnknownElemTypeI8) {
2703 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2710void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *
I,
2713 static StringMap<unsigned> ResTypeWellKnown = {
2714 {
"async_work_group_copy", WellKnownTypes::Event},
2715 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2716 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2720 bool IsKnown =
false;
2725 std::string DemangledName =
2728 if (DemangledName.length() > 0)
2730 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2731 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2732 if (ResIt != ResTypeWellKnown.
end()) {
2735 switch (ResIt->second) {
2736 case WellKnownTypes::Event:
2743 switch (DecorationId) {
2746 case FPDecorationId::SAT:
2749 case FPDecorationId::RTE:
2751 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2753 case FPDecorationId::RTZ:
2755 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2757 case FPDecorationId::RTP:
2759 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2761 case FPDecorationId::RTN:
2763 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2769 Type *Ty =
I->getType();
2772 Type *TypeToAssign = Ty;
2775 auto It = AggrConstTypes.
find(
II);
2776 if (It == AggrConstTypes.
end())
2778 TypeToAssign = It->second;
2779 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2780 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2781 TypeToAssign = It->second;
2783 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2784 TypeToAssign = It->second;
2788 for (
const auto &
Op :
I->operands()) {
2795 Type *OpTy =
Op->getType();
2797 CallInst *AssignCI =
2802 Type *OpTy =
Op->getType();
2817 CallInst *AssignCI =
2827bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2828 Instruction *Inst) {
2830 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2840void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *
I,
2842 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2844 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2849 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2850 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2851 if (shouldTryToAddMemAliasingDecoration(
I)) {
2852 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2853 ? SPIRV::Decoration::AliasScopeINTEL
2854 : SPIRV::Decoration::NoAliasINTEL;
2856 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2859 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2860 {
I->getType()}, {
Args});
2864 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2865 processMemAliasingDecoration(LLVMContext::MD_noalias);
2868 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2870 bool AllowFPMaxError =
2872 if (!AllowFPMaxError)
2876 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2880 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
2884 auto &Ctx =
B.getContext();
2886 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
2889 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
2891 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
2892 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
2895 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
2897 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
2899 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2907 &FPFastMathDefaultInfoMap,
2909 auto it = FPFastMathDefaultInfoMap.
find(
F);
2910 if (it != FPFastMathDefaultInfoMap.
end())
2918 SPIRV::FPFastMathMode::None);
2920 SPIRV::FPFastMathMode::None);
2922 SPIRV::FPFastMathMode::None);
2923 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
2929 size_t BitWidth = Ty->getScalarSizeInBits();
2933 assert(Index >= 0 && Index < 3 &&
2934 "Expected FPFastMathDefaultInfo for half, float, or double");
2935 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2936 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2937 return FPFastMathDefaultInfoVec[Index];
2940void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(
Module &M) {
2942 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2951 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
2953 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
2961 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
2964 [[maybe_unused]] GlobalVariable *GV =
2965 new GlobalVariable(M,
2966 Type::getInt32Ty(
M.getContext()),
2980 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
2981 FPFastMathDefaultInfoMap;
2983 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
2992 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2994 "Expected 4 operands for FPFastMathDefault");
3000 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3002 SPIRV::FPFastMathDefaultInfo &
Info =
3005 Info.FPFastMathDefault =
true;
3006 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3008 "Expected no operands for ContractionOff");
3012 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3014 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3015 Info.ContractionOff =
true;
3017 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3019 "Expected 1 operand for SignedZeroInfNanPreserve");
3020 unsigned TargetWidth =
3025 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3029 assert(Index >= 0 && Index < 3 &&
3030 "Expected FPFastMathDefaultInfo for half, float, or double");
3031 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3032 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3033 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3037 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3038 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3039 if (FPFastMathDefaultInfoVec.
empty())
3042 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3043 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3046 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3047 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3051 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3053 "and AllowContract");
3055 if (
Info.SignedZeroInfNanPreserve &&
3057 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3058 SPIRV::FPFastMathMode::NSZ))) {
3059 if (
Info.FPFastMathDefault)
3061 "SignedZeroInfNanPreserve but at least one of "
3062 "NotNaN/NotInf/NSZ is enabled.");
3065 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3066 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3067 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3069 "AllowTransform requires AllowReassoc and "
3070 "AllowContract to be set.");
3073 auto it = GlobalVars.
find(Flags);
3074 GlobalVariable *GV =
nullptr;
3075 if (it != GlobalVars.
end()) {
3081 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3084 GV =
new GlobalVariable(M,
3085 Type::getInt32Ty(
M.getContext()),
3090 GlobalVars[
Flags] = GV;
3096void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *
I,
3099 bool IsConstComposite =
3100 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3101 if (IsConstComposite && TrackConstants) {
3103 auto t = AggrConsts.
find(
I);
3107 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3109 NewOp->setArgOperand(0,
I);
3112 for (
const auto &
Op :
I->operands()) {
3116 unsigned OpNo =
Op.getOperandNo();
3117 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3118 (!
II->isBundleOperand(OpNo) &&
3119 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3123 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3124 :
B.SetInsertPoint(
I);
3127 Type *OpTy =
Op->getType();
3135 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3137 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3138 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3140 SmallVector<Value *, 2>
Args = {
3143 CallInst *PtrCasted =
3144 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
3149 I->setOperand(OpNo, NewOp);
3155Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *
F,
3157 SmallPtrSet<Function *, 0> FVisited;
3158 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3161Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
3162 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3164 if (!FVisited.
insert(
F).second)
3167 SmallPtrSet<Value *, 0> Visited;
3170 for (User *U :
F->users()) {
3182 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3185 for (User *OpU : OpArg->
users()) {
3187 if (!Inst || Inst == CI)
3190 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3197 if (FVisited.
find(OuterF) != FVisited.
end())
3199 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3200 if (OuterF->
getArg(i) == OpArg) {
3201 Lookup.push_back(std::make_pair(OuterF, i));
3208 for (
auto &Pair :
Lookup) {
3209 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3216void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *
F,
3218 B.SetInsertPointPastAllocas(
F);
3225 for (User *U : Arg->
users()) {
3227 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3245 for (User *U :
F->users()) {
3261 for (User *U : Arg->
users()) {
3265 CI->
getParent()->getParent() == CurrF) {
3267 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3278void SPIRVEmitIntrinsics::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3279 B.SetInsertPointPastAllocas(
F);
3285 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3287 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3289 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3301 bool IsNewFTy =
false;
3317bool SPIRVEmitIntrinsics::processFunctionPointers(
Module &M) {
3320 if (
F.isIntrinsic())
3322 if (
F.isDeclaration()) {
3323 for (User *U :
F.users()) {
3336 for (User *U :
F.users()) {
3338 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3340 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3341 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3348 if (Worklist.
empty())
3351 LLVMContext &Ctx =
M.getContext();
3356 for (Function *
F : Worklist) {
3358 for (
const auto &Arg :
F->args())
3360 IRB.CreateCall(
F, Args);
3362 IRB.CreateRetVoid();
3368void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3369 DenseMap<Function *, CallInst *> Ptrcasts;
3370 for (
auto It : FDeclPtrTys) {
3372 for (
auto *U :
F->users()) {
3377 for (
auto [Idx, ElemTy] : It.second) {
3385 B.SetInsertPointPastAllocas(Arg->
getParent());
3389 }
else if (isaGEP(Param)) {
3390 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3399 .getFirstNonPHIOrDbgOrAlloca());
3420SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP) {
3427 Type *SrcTy =
GEP->getSourceElementType();
3428 SmallVector<Value *, 8> Indices(
GEP->indices());
3430 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3431 Indices.erase(Indices.begin());
3432 SrcTy = ArrTy->getElementType();
3434 GEP->getNoWrapFlags(),
"",
3435 GEP->getIterator());
3440void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &
F,
3447 if (
ST->canUseExtension(
3448 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3449 for (BasicBlock &BB :
F) {
3451 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3455 SmallVector<unsigned, 1>
Ops =
3457 unsigned LC =
Ops[0];
3458 if (LC == SPIRV::LoopControl::None)
3462 B.SetInsertPoint(Term);
3463 SmallVector<Value *, 4> IntrArgs;
3464 for (
unsigned Op :
Ops)
3466 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3473 DominatorTree DT(
F);
3478 for (Loop *L : LI.getLoopsInPreorder()) {
3487 SmallVector<unsigned, 1> LoopControlOps =
3489 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3493 B.SetInsertPoint(Header->getTerminator());
3496 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3497 for (
unsigned Imm : LoopControlOps)
3498 Args.emplace_back(
B.getInt32(Imm));
3499 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3503bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3504 if (
Func.isDeclaration())
3508 GR =
ST.getSPIRVGlobalRegistry();
3512 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3517 AggrConstTypes.
clear();
3520 processParamTypesByFunHeader(CurrF,
B);
3524 SmallPtrSet<Instruction *, 4> DeadInsts;
3529 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3533 GR->addDeducedElementType(SGEP,
3538 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3540 GEP->replaceAllUsesWith(NewGEP);
3544 if (
Type *GepTy = getGEPType(
GEP))
3548 for (
auto *
I : DeadInsts) {
3549 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3550 I->eraseFromParent();
3560 Type *ElTy =
SI->getValueOperand()->getType();
3565 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3566 for (
auto &GV :
Func.getParent()->globals())
3567 processGlobalValue(GV,
B);
3569 preprocessUndefs(
B);
3570 preprocessPoisons(
B);
3571 simplifyNullAddrSpaceCasts();
3572 preprocessCompositeConstants(
B);
3580 Type *I32Ty =
B.getInt32Ty();
3584 if (!
I.getType()->isAggregateType())
3586 AggrConstTypes[&
I] =
I.getType();
3587 I.mutateType(I32Ty);
3590 preprocessBoolVectorBitcasts(Func);
3594 applyDemangledPtrArgTypes(
B);
3597 for (
auto &
I : Worklist) {
3599 if (isConvergenceIntrinsic(
I))
3602 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3604 insertAssignTypeIntrs(
I,
B);
3605 insertPtrCastOrAssignTypeInstr(
I,
B);
3609 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3610 insertAssignPtrTypeIntrs(
I,
B,
true);
3613 useRoundingMode(FPI,
B);
3618 SmallPtrSet<Instruction *, 4> IncompleteRets;
3620 deduceOperandElementType(&
I, &IncompleteRets);
3624 for (BasicBlock &BB : Func)
3625 for (PHINode &Phi : BB.
phis())
3627 deduceOperandElementType(&Phi,
nullptr);
3629 for (
auto *
I : Worklist) {
3630 TrackConstants =
true;
3640 if (isConvergenceIntrinsic(
I))
3644 processInstrAfterVisit(
I,
B);
3647 emitUnstructuredLoopControls(Func,
B);
3653bool SPIRVEmitIntrinsics::postprocessTypes(
Module &M) {
3654 if (!GR || TodoTypeSz == 0)
3657 unsigned SzTodo = TodoTypeSz;
3658 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3663 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3664 Type *KnownTy = GR->findDeducedElementType(
Op);
3665 if (!KnownTy || !AssignCI)
3671 SmallPtrSet<Value *, 0> Visited;
3672 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3673 if (ElemTy != KnownTy) {
3674 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3675 propagateElemType(CI, ElemTy, VisitedSubst);
3682 if (
Op->hasUseList()) {
3683 for (User *U :
Op->users()) {
3690 if (TodoTypeSz == 0)
3695 SmallPtrSet<Instruction *, 4> IncompleteRets;
3697 auto It = ToProcess.
find(&
I);
3698 if (It == ToProcess.
end())
3700 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3701 if (It->second.size() == 0)
3703 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3704 if (TodoTypeSz == 0)
3709 return SzTodo > TodoTypeSz;
3713void SPIRVEmitIntrinsics::parseFunDeclarations(
Module &M) {
3715 if (!
F.isDeclaration() ||
F.isIntrinsic())
3719 if (DemangledName.empty())
3723 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3724 DemangledName,
ST.getPreferredInstructionSet());
3725 if (Opcode != SPIRV::OpGroupAsyncCopy)
3728 SmallVector<unsigned> Idxs;
3737 LLVMContext &Ctx =
F.getContext();
3739 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3740 if (!TypeStrs.
size())
3743 for (
unsigned Idx : Idxs) {
3744 if (Idx >= TypeStrs.
size())
3747 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3750 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3755bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3756 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3758 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3759 if (!
ST.canUseExtension(
3760 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3761 I.getContext().emitError(
3762 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3766 I.eraseFromParent();
3772 Value *Ptrs =
I.getArgOperand(0);
3774 Value *Passthru =
I.getArgOperand(2);
3777 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3779 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3784 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3786 I.eraseFromParent();
3790 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3791 if (!
ST.canUseExtension(
3792 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3793 I.getContext().emitError(
3794 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3797 I.eraseFromParent();
3803 Value *Values =
I.getArgOperand(0);
3804 Value *Ptrs =
I.getArgOperand(1);
3809 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3811 SmallVector<Value *, 4>
Args = {Values, Ptrs,
B.getInt32(Alignment),
Mask};
3815 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3816 I.eraseFromParent();
3827void SPIRVEmitIntrinsics::preprocessBoolVectorBitcasts(Function &
F) {
3828 struct BoolVecBitcast {
3830 FixedVectorType *BoolVecTy;
3834 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3836 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3844 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3846 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3850 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3852 Value *Src = BC->getOperand(0);
3853 unsigned BoolVecN = BoolVecTy->getNumElements();
3855 Type *IntTy =
B.getIntNTy(BoolVecN);
3861 IntVal = ConstantInt::get(IntTy, 0);
3862 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3863 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3864 Value *Ext =
B.CreateZExt(Elem, IntTy);
3866 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3867 IntVal =
B.CreateOr(IntVal, Ext);
3873 if (!Src->getType()->isIntegerTy())
3874 IntVal =
B.CreateBitCast(Src, IntTy);
3879 if (!SrcIsBoolVec) {
3882 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3885 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
3886 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
3892 if (!BC->getDestTy()->isIntegerTy())
3893 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
3896 BC->replaceAllUsesWith(Result);
3897 BC->eraseFromParent();
3901bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(
Module &M) {
3905 if (!
F.isIntrinsic())
3908 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
3913 Changed |= processMaskedMemIntrinsic(*
II);
3917 F.eraseFromParent();
3923bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
3926 Changed |= convertMaskedMemIntrinsics(M);
3928 parseFunDeclarations(M);
3929 insertConstantsForFPFastMathDefault(M);
3940 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
3942 processParamTypes(&
F,
B);
3946 CanTodoType =
false;
3947 Changed |= postprocessTypes(M);
3950 Changed |= processFunctionPointers(M);
3957 SPIRVEmitIntrinsics Legacy(TM);
3958 if (Legacy.runOnModule(M))
3964 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 DenseMap class.
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 tracesToPointerAlloca(Value *V)
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool isSpvAggrPlaceholder(const Value *V)
static bool precededByAbortIntrinsic(const UnreachableInst &I, const SPIRVSubtarget &ST)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
This file defines the SmallPtrSet class.
StringSet - A set-like wrapper for the StringMap.
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 getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static 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
iterator find(ConstPtrType Ptr) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator 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)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
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()
iterator_range< use_iterator > uses()
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.
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)
bool isUntypedPointerVectorTy(const Type *T)
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)
bool isPointerTyOrWrapper(const 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)