28#include "llvm/IR/IntrinsicsSPIRV.h"
63#define DEBUG_TYPE "spirv-emit-intrinsics"
67 cl::desc(
"Emit OpName for all instructions"),
71#define GET_BuiltinGroup_DECL
72#include "SPIRVGenTables.inc"
77class GlobalVariableUsers {
78 template <
typename T1,
typename T2>
79 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
81 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
83 void collectGlobalUsers(
84 const GlobalVariable *GV,
85 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
86 &GlobalIsUsedByGlobal) {
88 while (!
Stack.empty()) {
92 GlobalIsUsedByFun[GV].insert(
I->getFunction());
97 GlobalIsUsedByGlobal[GV].insert(UserGV);
102 Stack.append(
C->user_begin(),
C->user_end());
106 bool propagateGlobalToGlobalUsers(
107 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
108 &GlobalIsUsedByGlobal) {
111 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
112 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
113 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
114 auto It = GlobalIsUsedByGlobal.find(UserGV);
115 if (It == GlobalIsUsedByGlobal.end())
123 void propagateGlobalToFunctionReferences(
124 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
125 &GlobalIsUsedByGlobal) {
126 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
127 auto &UserFunctions = GlobalIsUsedByFun[GV];
128 for (
const GlobalVariable *UserGV : UserGlobals) {
129 auto It = GlobalIsUsedByFun.find(UserGV);
130 if (It == GlobalIsUsedByFun.end())
141 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
142 GlobalIsUsedByGlobal;
143 GlobalIsUsedByFun.clear();
144 for (GlobalVariable &GV :
M.globals())
145 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
148 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
151 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
154 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
155 const FunctionSetType &
156 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
157 auto It = GlobalIsUsedByFun.find(&GV);
158 if (It != GlobalIsUsedByFun.end())
161 static const FunctionSetType
Empty{};
166static bool isaGEP(
const Value *V) {
172static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
178 return AT->getNumElements();
184class SPIRVEmitIntrinsicsImpl
185 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
186 const SPIRVTargetMachine &TM;
187 SPIRVGlobalRegistry *GR =
nullptr;
189 bool TrackConstants =
true;
190 bool HaveFunPtrs =
false;
191 bool CanUseAnyVectorRank =
false;
192 DenseMap<Instruction *, Constant *> AggrConsts;
193 DenseMap<Instruction *, Type *> AggrConstTypes;
194 SmallPtrSet<Instruction *, 0> AggrStores;
195 GlobalVariableUsers GVUsers;
196 SmallPtrSet<Value *, 0> Named;
199 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
202 bool CanTodoType =
true;
203 unsigned TodoTypeSz = 0;
204 DenseMap<Value *, bool> TodoType;
205 void insertTodoType(
Value *
Op) {
207 if (CanTodoType && !isaGEP(
Op)) {
208 auto It = TodoType.try_emplace(
Op,
true);
213 void eraseTodoType(
Value *
Op) {
214 auto It = TodoType.find(
Op);
215 if (It != TodoType.end() && It->second) {
223 auto It = TodoType.find(
Op);
224 return It != TodoType.end() && It->second;
228 SmallPtrSet<Instruction *, 0> TypeValidated;
231 enum WellKnownTypes { Event };
234 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
235 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
236 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
237 bool UnknownElemTypeI8,
238 bool IgnoreKnownType =
false);
239 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
240 bool UnknownElemTypeI8);
241 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
242 SmallPtrSetImpl<Value *> &Visited,
243 bool UnknownElemTypeI8);
245 SmallPtrSetImpl<Value *> &Visited,
246 bool UnknownElemTypeI8);
248 bool UnknownElemTypeI8);
251 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
252 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
253 SmallPtrSetImpl<Value *> &Visited,
254 bool UnknownElemTypeI8);
258 deduceOperandElementType(Instruction *
I,
259 SmallPtrSetImpl<Instruction *> *IncompleteRets,
260 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
261 bool IsPostprocessing =
false);
266 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
267 void simplifyNullAddrSpaceCasts();
269 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
270 bool IsPostprocessing);
272 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
274 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
275 bool UnknownElemTypeI8);
277 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
279 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
280 Type *ExpectedElementType,
281 unsigned OperandToReplace,
283 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
284 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
286 void insertConstantsForFPFastMathDefault(
Module &M);
289 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
292 Type *deduceFunParamElementType(
Function *
F,
unsigned OpIdx);
294 SmallPtrSetImpl<Function *> &FVisited);
296 bool deduceOperandElementTypeCalledFunction(
298 Type *&KnownElemTy,
bool &Incomplete);
299 void deduceOperandElementTypeFunctionPointer(
301 Type *&KnownElemTy,
bool IsPostprocessing);
302 bool deduceOperandElementTypeFunctionRet(
303 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
304 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
308 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
309 DenseMap<Function *, CallInst *> Ptrcasts);
311 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
314 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
315 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
316 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
317 SmallPtrSetImpl<Value *> &Visited,
318 DenseMap<Function *, CallInst *> Ptrcasts);
321 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
322 Instruction *Dest,
bool DeleteOld =
true);
326 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
329 bool postprocessTypes(
Module &M);
330 bool processFunctionPointers(
Module &M);
331 void parseFunDeclarations(
Module &M);
332 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
333 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
334 bool convertMaskedMemIntrinsics(
Module &M);
335 void preprocessBoolVectorBitcasts(
Function &
F);
354 bool walkLogicalAccessChain(
355 GetElementPtrInst &
GEP,
356 const std::function<
void(
Type *PointedType,
uint64_t Index)>
359 uint64_t Multiplier)> &OnDynamicIndexing);
361 bool walkLogicalAccessChainDynamic(
363 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
366 bool walkLogicalAccessChainConstant(
368 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing);
374 Type *getGEPType(GetElementPtrInst *
GEP);
381 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
383 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
386 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
389 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
392 Instruction *visitInsertElementInst(InsertElementInst &
I);
393 Instruction *visitExtractElementInst(ExtractElementInst &
I);
395 Instruction *visitExtractValueInst(ExtractValueInst &
I);
399 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
404 bool runOnModule(
Module &M);
407class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
408 const SPIRVTargetMachine &TM;
412 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
413 : ModulePass(ID), TM(TM) {}
415 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
417 bool runOnModule(
Module &M)
override {
418 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
424 Intrinsic::experimental_convergence_loop,
425 Intrinsic::experimental_convergence_anchor>());
428bool expectIgnoredInIRTranslation(
const Instruction *
I) {
430 Intrinsic::spv_resource_handlefrombinding,
431 Intrinsic::spv_resource_getbasepointer,
432 Intrinsic::spv_resource_getpointer>());
439 return getPointerRoot(V);
445char SPIRVEmitIntrinsicsLegacy::ID = 0;
448 "SPIRV emit intrinsics",
false,
false)
462 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
475 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
481 B.SetCurrentDebugLocation(
I->getDebugLoc());
482 if (
I->getType()->isVoidTy())
483 B.SetInsertPoint(
I->getNextNode());
485 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
495 if (
I->getType()->isTokenTy())
497 "does not support token type",
502 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
503 expectIgnoredInIRTranslation(
I))
514 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
525 std::vector<Value *> Args = {
528 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
531void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
535 if (isTodoType(Src)) {
538 insertTodoType(Dest);
542void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
547 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
548 Src->eraseFromParent();
551 if (Named.
insert(Dest).second)
566 V = V->stripPointerCasts();
587Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
588 bool UnknownElemTypeI8,
589 bool IsPostprocessing) {
593 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
607 if (UnknownElemTypeI8) {
608 if (!IsPostprocessing)
624 B.SetInsertPointPastAllocas(OpA->getParent());
627 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
629 Type *OpTy =
Op->getType();
631 SmallVector<Value *, 2>
Args = {
634 CallInst *PtrCasted =
635 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
640void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
642 DenseMap<Function *, CallInst *> Ptrcasts) {
644 CallInst *PtrCastedI =
nullptr;
645 auto It = Ptrcasts.
find(
F);
646 if (It == Ptrcasts.
end()) {
647 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
648 Ptrcasts[
F] = PtrCastedI;
650 PtrCastedI = It->second;
652 I->replaceUsesOfWith(
Op, PtrCastedI);
655void SPIRVEmitIntrinsicsImpl::propagateElemType(
657 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
658 DenseMap<Function *, CallInst *> Ptrcasts;
660 for (
auto *U :
Users) {
663 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
668 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
669 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
673void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
675 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
676 SmallPtrSet<Value *, 0> Visited;
677 DenseMap<Function *, CallInst *> Ptrcasts;
678 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
679 std::move(Ptrcasts));
682void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
684 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
685 SmallPtrSetImpl<Value *> &Visited,
686 DenseMap<Function *, CallInst *> Ptrcasts) {
690 for (
auto *U :
Users) {
693 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
698 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
699 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
706Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
707 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
708 SmallPtrSet<Value *, 0> Visited;
709 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
713Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
714 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
715 bool UnknownElemTypeI8) {
720 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
731Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
732 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
744 for (User *OpU :
Op->users()) {
746 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
758 Function *CalledF,
unsigned OpIdx) {
768Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
769 bool UnknownElemTypeI8) {
770 SmallPtrSet<Value *, 0> Visited;
771 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
774void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
776 bool UnknownElemTypeI8) {
778 if (!UnknownElemTypeI8)
787bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
789 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
796 if (
ST->getNumElements() == 0)
798 CurType =
ST->getElementType(0);
799 OnLiteralIndexing(CurType, 0);
807 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
808 return AT ==
nullptr;
811bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
813 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing) {
818 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
822 CurType = AT->getElementType();
823 OnLiteralIndexing(CurType, Index);
825 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
828 const auto &STL =
DL.getStructLayout(ST);
829 unsigned Element = STL->getElementContainingOffset(
Offset);
830 Offset -= STL->getElementOffset(Element);
831 CurType =
ST->getElementType(Element);
832 OnLiteralIndexing(CurType, Element);
834 Type *EltTy = VT->getElementType();
835 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
836 assert(EltSizeBits % 8 == 0 &&
837 "Element type size in bits must be a multiple of 8.");
838 uint32_t EltTypeSize = EltSizeBits / 8;
843 OnLiteralIndexing(CurType, Index);
853bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
854 GetElementPtrInst &
GEP,
855 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
859 std::optional<uint64_t> MultiplierOpt =
860 getByteAddressingMultiplier(
GEP.getSourceElementType());
861 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
862 uint64_t Multiplier = *MultiplierOpt;
865 Value *Src = getPointerRoot(
GEP.getPointerOperand());
866 Type *CurType = deduceElementType(Src,
true);
870 return walkLogicalAccessChainConstant(
871 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
873 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
874 OnLiteralIndexing, OnDynamicIndexing);
877Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
878 GetElementPtrInst &
GEP) {
881 B.SetInsertPoint(&
GEP);
883 std::vector<Value *> Indices;
884 Indices.push_back(ConstantInt::get(
885 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
886 walkLogicalAccessChain(
890 ConstantInt::get(
B.getInt64Ty(), Index,
false));
895 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
897 if (Multiplier == EltTypeSize) {
899 }
else if (EltTypeSize % Multiplier == 0) {
902 EltTypeSize / Multiplier,
906 ConstantInt::get(
Offset->getType(), Multiplier,
909 Index =
B.CreateUDiv(Index,
910 ConstantInt::get(
Offset->getType(), EltTypeSize,
914 Indices.push_back(Index);
918 SmallVector<Value *, 4>
Args;
919 Args.push_back(
B.getInt1(
GEP.isInBounds()));
920 Args.push_back(
GEP.getOperand(0));
923 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
924 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
928Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
930 Type *CurType =
GEP->getResultElementType();
932 bool Interrupted = walkLogicalAccessChain(
933 *
GEP, [&CurType](
Type *EltType,
uint64_t Index) { CurType = EltType; },
936 return Interrupted ?
GEP->getResultElementType() : CurType;
939Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
940 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
942 return getGEPTypeLogical(
Ref);
949 Ty =
Ref->getSourceElementType();
953 Ty =
Ref->getResultElementType();
958Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
959 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
960 bool IgnoreKnownType) {
966 if (!IgnoreKnownType)
978 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
980 Ty = getGEPType(
Ref);
982 Ty = SGEP->getResultElementType();
987 KnownTy =
Op->getType();
989 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
992 Ty = SPIRV::getOriginalFunctionType(*Fn);
995 Ty = deduceElementTypeByValueDeep(
997 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
1001 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
1003 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1005 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1007 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1009 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1014 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1018 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1020 Type *BestTy =
nullptr;
1022 DenseMap<Type *, unsigned> PhiTys;
1023 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1024 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1031 if (It.first->second > MaxN) {
1032 MaxN = It.first->second;
1040 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1044 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1045 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1050 static StringMap<unsigned> ResTypeByArg = {
1056 {
"__to_private", 0},
1057 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1058 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1059 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1060 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1061 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1062 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1066 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1067 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1069 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1070 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1071 for (User *U :
II->users()) {
1076 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1078 Ty = HandleType->getTypeParameter(0);
1079 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1093 }
else if (
II &&
II->getIntrinsicID() ==
1094 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1098 std::string DemangledName =
1100 if (DemangledName.length() > 0)
1101 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1102 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1103 if (AsArgIt != ResTypeByArg.
end())
1104 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1105 Visited, UnknownElemTypeI8);
1112 if (Ty && !IgnoreKnownType) {
1123Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1124 bool UnknownElemTypeI8) {
1125 SmallPtrSet<Value *, 0> Visited;
1126 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1129Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1130 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1131 bool UnknownElemTypeI8) {
1140 if (!Visited.
insert(U).second)
1145 bool Change =
false;
1146 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1148 assert(
Op &&
"Operands should not be null.");
1149 Type *OpTy =
Op->getType();
1152 if (
Type *NestedTy =
1153 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1160 Change |= Ty != OpTy;
1164 Tys, OrigStructTy->isLiteral() ?
"" : OrigStructTy->getName(),
1165 OrigStructTy->isPacked());
1170 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1171 Type *OpTy = ArrTy->getElementType();
1174 if (
Type *NestedTy =
1175 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1182 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1188 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1189 Type *OpTy = VecTy->getElementType();
1192 if (
Type *NestedTy =
1193 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1200 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1211Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1212 bool UnknownElemTypeI8) {
1213 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1215 if (!UnknownElemTypeI8)
1218 return IntegerType::getInt8Ty(
I->getContext());
1222 Value *PointerOperand) {
1228 return I->getType();
1236bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1238 Type *&KnownElemTy,
bool &Incomplete) {
1242 std::string DemangledName =
1244 if (DemangledName.length() > 0 &&
1246 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1247 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1248 DemangledName,
ST.getPreferredInstructionSet());
1249 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1250 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1256 KnownElemTy = ElemTy;
1257 Ops.push_back(std::make_pair(
Op, i));
1259 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1266 case SPIRV::OpAtomicFAddEXT:
1267 case SPIRV::OpAtomicFMinEXT:
1268 case SPIRV::OpAtomicFMaxEXT:
1269 case SPIRV::OpAtomicLoad:
1270 case SPIRV::OpAtomicCompareExchangeWeak:
1271 case SPIRV::OpAtomicCompareExchange:
1272 case SPIRV::OpAtomicExchange:
1273 case SPIRV::OpAtomicIAdd:
1274 case SPIRV::OpAtomicISub:
1275 case SPIRV::OpAtomicOr:
1276 case SPIRV::OpAtomicXor:
1277 case SPIRV::OpAtomicAnd:
1278 case SPIRV::OpAtomicUMin:
1279 case SPIRV::OpAtomicUMax:
1280 case SPIRV::OpAtomicSMin:
1281 case SPIRV::OpAtomicSMax: {
1286 Incomplete = isTodoType(
Op);
1287 Ops.push_back(std::make_pair(
Op, 0));
1289 case SPIRV::OpAtomicStore: {
1298 Incomplete = isTodoType(
Op);
1299 Ops.push_back(std::make_pair(
Op, 0));
1308void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1310 Type *&KnownElemTy,
bool IsPostprocessing) {
1314 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1315 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1316 bool IsNewFTy =
false, IsIncomplete =
false;
1319 Type *ArgTy = Arg->getType();
1324 if (isTodoType(Arg))
1325 IsIncomplete =
true;
1327 IsIncomplete =
true;
1330 ArgTy = FTy->getFunctionParamType(ParmIdx);
1334 Type *RetTy = FTy->getReturnType();
1341 IsIncomplete =
true;
1343 IsIncomplete =
true;
1346 if (!IsPostprocessing && IsIncomplete)
1349 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1352bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1353 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1354 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1366 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1367 for (User *U :
F->users()) {
1376 propagateElemType(CI, PrevElemTy, VisitedSubst);
1386 for (Instruction *IncompleteRetI : *IncompleteRets)
1387 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1389 }
else if (IncompleteRets) {
1400void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1401 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1402 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1404 Type *KnownElemTy =
nullptr;
1405 bool Incomplete =
false;
1411 Incomplete = isTodoType(
I);
1412 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1415 Ops.push_back(std::make_pair(
Op, i));
1421 Incomplete = isTodoType(
I);
1422 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1429 Incomplete = isTodoType(
I);
1430 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1434 KnownElemTy =
Ref->getSourceElementType();
1435 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1440 KnownElemTy =
Ref->getBaseType();
1441 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1444 KnownElemTy =
I->getType();
1451 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1460 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1464 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1469 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1477 Incomplete = isTodoType(
Ref->getPointerOperand());
1478 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1486 Incomplete = isTodoType(
Ref->getPointerOperand());
1487 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1493 Incomplete = isTodoType(
I);
1494 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1497 Ops.push_back(std::make_pair(
Op, i));
1505 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1506 IsPostprocessing, KnownElemTy,
Op,
1509 Incomplete = isTodoType(CurrF);
1510 Ops.push_back(std::make_pair(
Op, 0));
1516 bool Incomplete0 = isTodoType(Op0);
1517 bool Incomplete1 = isTodoType(Op1);
1519 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1521 : GR->findDeducedElementType(Op0);
1523 KnownElemTy = ElemTy0;
1524 Incomplete = Incomplete0;
1525 Ops.push_back(std::make_pair(Op1, 1));
1526 }
else if (ElemTy1) {
1527 KnownElemTy = ElemTy1;
1528 Incomplete = Incomplete1;
1529 Ops.push_back(std::make_pair(Op0, 0));
1533 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1534 else if (HaveFunPtrs)
1535 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1540 if (!KnownElemTy ||
Ops.size() == 0)
1544 for (
auto &OpIt :
Ops) {
1548 Type *AskTy =
nullptr;
1549 CallInst *AskCI =
nullptr;
1550 if (IsPostprocessing && AskOps) {
1556 if (Ty == KnownElemTy)
1559 Type *OpTy =
Op->getType();
1565 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1573 else if (!IsPostprocessing)
1577 if (AssignCI ==
nullptr) {
1586 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1587 std::make_pair(
I,
Op)};
1588 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1592 CallInst *PtrCastI =
1593 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1594 if (OpIt.second == std::numeric_limits<unsigned>::max())
1597 I->setOperand(OpIt.second, PtrCastI);
1603void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1608 if (isAssignTypeInstr(U)) {
1609 B.SetInsertPoint(U);
1610 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1611 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1612 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1614 U->eraseFromParent();
1617 U->replaceUsesOfWith(Old, New);
1625 Type *NewArgTy =
New->getType();
1627 if (NewArgTy != ExpectedArgTy) {
1630 M, Intrinsic::spv_abort, {NewArgTy});
1640 "aggregate PHI/select/freeze should have been mutated to value-id "
1642 U->replaceUsesOfWith(Old, New);
1647 New->copyMetadata(*Old);
1653 bool HasPoisonExt) {
1660 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1661 "lowered as undef\n");
1663 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1664 Type *Ty = UV->getType();
1670 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1671 :
B.CreateIntrinsicWithoutFolding(IID, {});
1672 AggrConsts[
Call] = UV;
1673 AggrConstTypes[
Call] = Ty;
1678 return B.CreateIntrinsic(IID, {Ty}, {});
1685void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1690 SmallVector<Instruction *, 16> Insts;
1694 for (Instruction *
I : Insts) {
1695 bool BPrepared =
false;
1697 for (
unsigned Idx = 0;
Idx <
I->getNumOperands(); ++
Idx) {
1701 bool IsScalar = !
Op->getType()->isAggregateType();
1704 if (IsScalar && !AsPoison)
1708 if (IsScalar && Phi)
1709 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1710 else if (!BPrepared) {
1714 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1715 I->setOperand(Idx, Repl);
1724void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1728 ASC->replaceAllUsesWith(
1730 ASC->eraseFromParent();
1738 if (!V->getType()->isAggregateType())
1747 I.getType()->isAggregateType();
1753void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1756 for (Use &U :
I->operands()) {
1763 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1768 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1770 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1776void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1780 std::queue<Instruction *> Worklist;
1784 while (!Worklist.empty()) {
1785 auto *
I = Worklist.front();
1788 bool KeepInst =
false;
1789 for (
const auto &
Op :
I->operands()) {
1791 Type *ResTy =
nullptr;
1794 ResTy = COp->getType();
1806 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1809 auto PrepareInsert = [&]() {
1812 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1813 :
B.SetInsertPoint(
I);
1818 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1819 Args.push_back(COp->getElementAsConstant(i));
1825 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1834 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1840 auto *CI =
B.CreateIntrinsicWithoutFolding(
1841 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1845 AggrConsts[CI] = AggrConst;
1846 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1858 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1863 unsigned RoundingModeDeco,
1870 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1879 MDNode *SaturatedConversionNode =
1881 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1901 MDString *ConstraintString =
1906 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1910 B.SetInsertPoint(&
Call);
1911 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1916void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1919 if (!
RM.has_value())
1921 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1922 switch (
RM.value()) {
1926 case RoundingMode::NearestTiesToEven:
1927 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1929 case RoundingMode::TowardNegative:
1930 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1932 case RoundingMode::TowardPositive:
1933 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1935 case RoundingMode::TowardZero:
1936 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1938 case RoundingMode::Dynamic:
1939 case RoundingMode::NearestTiesToAway:
1943 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1949Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1953 B.SetInsertPoint(&
I);
1954 SmallVector<Value *, 4>
Args;
1956 Args.push_back(
I.getCondition());
1959 for (
auto &Case :
I.cases()) {
1960 Args.push_back(Case.getCaseValue());
1961 BBCases.
push_back(Case.getCaseSuccessor());
1964 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1965 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1969 I.eraseFromParent();
1972 B.SetInsertPoint(ParentBB);
1973 IndirectBrInst *BrI =
B.CreateIndirectBr(
1976 for (BasicBlock *BBCase : BBCases)
1985Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
1991 B.SetInsertPoint(&
I);
1993 SmallVector<Value *, 4>
Args;
1994 Args.push_back(
B.getInt1(
true));
1995 Args.push_back(
I.getOperand(0));
1996 Args.push_back(
B.getInt32(0));
1997 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1998 Args.push_back(SGEP->getIndexOperand(J));
2001 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
2002 replaceAllUsesWithAndErase(
B, &
I, NewI);
2007SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2009 B.SetInsertPoint(&
I);
2014 unsigned N = RetVTy->getNumElements();
2015 Value *PtrOp =
I.getPointerOperand();
2017 Type *ResultPtrTy = RetVTy->getElementType();
2020 Value *InBounds =
B.getInt1(
I.isInBounds());
2021 Type *LanePointeeTy = getGEPType(&
I);
2022 Type *SrcElemTy =
I.getSourceElementType();
2031 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2032 Value *LaneIdx =
B.getInt32(Lane);
2033 Value *ScalarPtr = PtrOp;
2037 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2041 SmallVector<Value *, 4>
Args;
2042 Args.push_back(InBounds);
2043 Args.push_back(ScalarPtr);
2044 for (
Value *Idx :
I.indices()) {
2052 Args.push_back(visitExtractElementInst(*EI));
2056 Args.push_back(Idx);
2059 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2061 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2065 replaceAllUsesWithAndErase(
B, &
I, NewI);
2083 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2084 return buildLogicalAccessChainFromGEP(
I);
2089 Value *PtrOp =
I.getPointerOperand();
2090 Type *SrcElemTy =
I.getSourceElementType();
2091 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2094 if (ArrTy->getElementType() == SrcElemTy) {
2096 Type *FirstIdxType =
I.getOperand(1)->getType();
2097 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2098 for (
Value *Idx :
I.indices())
2102 SmallVector<Value *, 4>
Args;
2103 Args.push_back(
B.getInt1(
I.isInBounds()));
2104 Args.push_back(
I.getPointerOperand());
2107 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2109 replaceAllUsesWithAndErase(
B, &
I, NewI);
2116 SmallVector<Value *, 4>
Args;
2117 Args.push_back(
B.getInt1(
I.isInBounds()));
2120 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2121 replaceAllUsesWithAndErase(
B, &
I, NewI);
2125Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2127 B.SetInsertPoint(&
I);
2136 I.eraseFromParent();
2143 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2144 replaceAllUsesWithAndErase(
B, &
I, NewI);
2148void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2150 Type *VTy =
V->getType();
2155 if (ElemTy != AssignedType)
2168 if (CurrentType == AssignedType)
2175 " for value " +
V->getName(),
2184void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2185 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2190 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2191 if (PointerElemTy == ExpectedElementType ||
2196 Value *ExpectedElementVal =
2198 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2200 bool FirstPtrCastOrAssignPtrType =
true;
2206 for (
auto User :
Pointer->users()) {
2209 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2210 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2211 II->getOperand(0) != Pointer)
2216 FirstPtrCastOrAssignPtrType =
false;
2217 if (
II->getOperand(1) != VMD ||
2224 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2229 if (
II->getParent() !=
I->getParent())
2232 I->setOperand(OperandToReplace,
II);
2247 if (FirstPtrCastOrAssignPtrType) {
2252 }
else if (isTodoType(Pointer)) {
2253 eraseTodoType(Pointer);
2261 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2262 std::make_pair(
I, Pointer)};
2264 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2277 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
2283void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2288 replacePointerOperandWithPtrCast(
2289 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2295 Type *OpTy =
Op->getType();
2298 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2301 if (OpTy ==
Op->getType())
2302 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2303 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2308 Type *OpTy = LI->getType();
2319 Type *NewOpTy = OpTy;
2320 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2321 if (OpTy == NewOpTy)
2322 insertTodoType(Pointer);
2325 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2330 Type *OpTy =
nullptr;
2342 OpTy = GEPI->getSourceElementType();
2344 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2346 insertTodoType(Pointer);
2358 std::string DemangledName =
2362 bool HaveTypes =
false;
2363 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2381 for (User *U : CalledArg->
users()) {
2383 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2389 HaveTypes |= ElemTy !=
nullptr;
2394 if (DemangledName.empty() && !HaveTypes)
2398 TM.
getSubtarget<SPIRVSubtarget>(*CalledF).getPreferredInstructionSet();
2400 bool ParseBuiltinTypes =
2401 !DemangledName.empty() &&
2402 (!CalledF->
isDeclaration() || SPIRV::isBuiltin(DemangledName, Set));
2403 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2418 Type *ExpectedType =
2419 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2420 if (!ExpectedType && ParseBuiltinTypes)
2421 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2422 DemangledName, OpIdx,
I->getContext());
2423 if (!ExpectedType || ExpectedType->
isVoidTy())
2431 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2436SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2439 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2443 I.getOperand(1)->getType(),
2444 I.getOperand(2)->getType()};
2446 B.SetInsertPoint(&
I);
2448 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2450 replaceAllUsesWithAndErase(
B, &
I, NewI);
2455SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2458 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2462 B.SetInsertPoint(&
I);
2464 I.getIndexOperand()->getType()};
2465 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2466 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2468 replaceAllUsesWithAndErase(
B, &
I, NewI);
2472Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2474 B.SetInsertPoint(&
I);
2477 Value *AggregateOp =
I.getAggregateOperand();
2481 Args.push_back(AggregateOp);
2482 Args.push_back(
I.getInsertedValueOperand());
2483 for (
auto &
Op :
I.indices())
2484 Args.push_back(
B.getInt32(
Op));
2486 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2487 replaceMemInstrUses(&
I, NewI,
B);
2492SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2494 B.SetInsertPoint(&
I);
2495 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2504 for (
auto &
Op :
I.indices())
2505 Args.push_back(
B.getInt32(
Op));
2506 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2507 {
I.getType()}, {
Args});
2513 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2514 AggrConstTypes[NewI] =
I.getType();
2516 replaceMemInstrUses(&
I, NewI,
B);
2519 replaceAllUsesWithAndErase(
B, &
I, NewI);
2523 for (
const Use &U : NewI->
uses()) {
2524 User *Usr =
U.getUser();
2526 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2537 if (ArgNo < FT->getNumParams() &&
2538 !FT->getParamType(ArgNo)->isAggregateType()) {
2547Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2548 if (!
I.getType()->isAggregateType())
2551 B.SetInsertPoint(&
I);
2552 TrackConstants =
false;
2557 unsigned IntrinsicId;
2558 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2559 if (!
I.isAtomic()) {
2560 IntrinsicId = Intrinsic::spv_load;
2561 Args.push_back(
B.getInt32(
I.getAlign().value()));
2563 IntrinsicId = Intrinsic::spv_atomic_load;
2564 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2566 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2567 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2569 replaceMemInstrUses(&
I, NewI,
B);
2573Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2577 B.SetInsertPoint(&
I);
2578 TrackConstants =
false;
2582 auto *PtrOp =
I.getPointerOperand();
2584 if (
I.getValueOperand()->getType()->isAggregateType()) {
2592 "Unexpected argument of aggregate type, should be spv_extractv!");
2596 unsigned IntrinsicId;
2597 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2599 if (!
I.isAtomic()) {
2600 IntrinsicId = Intrinsic::spv_store;
2601 Args.push_back(
B.getInt32(
I.getAlign().value()));
2603 IntrinsicId = Intrinsic::spv_atomic_store;
2604 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2607 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2609 I.eraseFromParent();
2613Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2614 Value *ArraySize =
nullptr;
2615 if (
I.isArrayAllocation()) {
2618 SPIRV::Extension::SPV_INTEL_variable_length_array))
2620 "array allocation: this instruction requires the following "
2621 "SPIR-V extension: SPV_INTEL_variable_length_array",
2623 ArraySize =
I.getArraySize();
2626 B.SetInsertPoint(&
I);
2627 TrackConstants =
false;
2628 Type *PtrTy =
I.getType();
2631 ?
B.CreateIntrinsicWithoutFolding(
2632 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2633 {ArraySize,
B.getInt32(
I.getAlign().value())})
2634 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2635 {
B.getInt32(
I.getAlign().value())});
2636 replaceAllUsesWithAndErase(
B, &
I, NewI);
2641SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2642 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2644 B.SetInsertPoint(&
I);
2647 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2651 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2652 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2653 uint32_t ScSem =
static_cast<uint32_t
>(
2662 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2663 replaceMemInstrUses(&
I, NewI,
B);
2667Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &
I) {
2668 auto Op =
I.getOperation();
2679 B.SetInsertPoint(&
I);
2681 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2682 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2684 uint32_t
Scope =
static_cast<uint32_t
>(
2685 getMemScope(
M->getTargetTriple(),
I.getContext(),
I.getSyncScopeID()));
2686 uint32_t ScSem =
static_cast<uint32_t
>(
2689 M->getTargetTriple(),
2693 ?
"__translate_spirv_atomic_uinc_wrap"
2694 :
"__translate_spirv_atomic_udec_wrap");
2696 Type *ValTy =
I.getValOperand()->getType();
2697 Type *PtrTy =
I.getPointerOperand()->getType();
2699 raw_svector_ostream OS(FuncName);
2700 OS <<
"_p" << AS <<
"_";
2702 OS <<
"v" << VecTy->getNumElements();
2705 Type *Int32Ty =
B.getInt32Ty();
2706 Type *BoolTy =
B.getInt1Ty();
2708 ValTy, BoolTy, BoolTy};
2709 FunctionType *FT = FunctionType::get(ValTy, ArgTys,
false);
2710 FunctionCallee
FC =
M->getOrInsertFunction(FuncName, FT);
2714 I.getPointerOperand(),
B.getInt32(Scope),
2715 B.getInt32(MemSem),
I.getValOperand(),
2716 B.getInt1(
I.isVolatile()),
B.getInt1(
I.isElementwise())};
2717 CallInst *CI =
B.CreateCall(FC, Args);
2723 replaceAllUsesWithAndErase(
B, &
I, CI);
2732 case Intrinsic::spv_abort:
2734 case Intrinsic::trap:
2735 case Intrinsic::ubsantrap:
2737 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2757 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2758 "abort-like call must be the last non-debug instruction before its "
2759 "block's terminator");
2763Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2764 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2768 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2775 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2789 while (!Stack.empty()) {
2790 const Value *V = Stack.pop_back_val();
2791 if (!Visited.
insert(V).second)
2799 Stack.append(
C->user_begin(),
C->user_end());
2815 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2816 if (UserFunctions.contains(
F))
2821 if (!UserFunctions.empty())
2826 const Module &M = *
F->getParent();
2827 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2828 return F == &FirstDefinition;
2831Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2833 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2834 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2836 AggrConstTypes[Leaf] = ElemTy;
2839 SmallVector<Value *, 4> Elems;
2841 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2844 DenseMap<Type *, Instruction *> LeafByType;
2845 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2847 auto &
Entry = LeafByType[ElemTy];
2849 Entry = MakeLeaf(ElemTy);
2853 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2854 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2856 AggrConstTypes[Composite] = AggrTy;
2865void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2870 for (BasicBlock &BB : Func) {
2874 Value *RetVal = RI->getReturnValue();
2881 B.SetInsertPoint(RI);
2884 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2885 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2887 RI->setOperand(0, Rebuilt);
2891void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2901 deduceElementTypeHelper(&GV,
false);
2906 Value *InitOp = Init;
2913 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2914 {
B.getInt32Ty()}, {});
2919 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2924 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2925 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2931 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2937bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2939 bool UnknownElemTypeI8) {
2945 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2952void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2955 static StringMap<unsigned> ResTypeWellKnown = {
2956 {
"async_work_group_copy", WellKnownTypes::Event},
2957 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2958 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2962 bool IsKnown =
false;
2967 std::string DemangledName =
2970 if (DemangledName.length() > 0)
2972 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2973 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2974 if (ResIt != ResTypeWellKnown.
end()) {
2977 switch (ResIt->second) {
2978 case WellKnownTypes::Event:
2981 CanUseAnyVectorRank);
2986 switch (DecorationId) {
2989 case FPDecorationId::SAT:
2992 case FPDecorationId::RTE:
2994 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2996 case FPDecorationId::RTZ:
2998 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
3000 case FPDecorationId::RTP:
3002 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
3004 case FPDecorationId::RTN:
3006 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
3012 Type *Ty =
I->getType();
3015 Type *TypeToAssign = Ty;
3018 auto It = AggrConstTypes.
find(
II);
3019 if (It == AggrConstTypes.
end())
3021 TypeToAssign = It->second;
3022 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
3023 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
3024 TypeToAssign = It->second;
3026 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
3027 TypeToAssign = It->second;
3031 for (
const auto &
Op :
I->operands()) {
3039 Type *OpTy =
Op->getType();
3041 CallInst *AssignCI =
3046 Type *OpTy =
Op->getType();
3062 Intrinsic::spv_assign_type, {OpTy},
3072bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
3073 Instruction *Inst) {
3075 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3085void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3087 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3089 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3094 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3095 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3096 if (shouldTryToAddMemAliasingDecoration(
I)) {
3097 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3098 ? SPIRV::Decoration::AliasScopeINTEL
3099 : SPIRV::Decoration::NoAliasINTEL;
3101 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3104 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3105 {
I->getType()}, {
Args});
3109 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3110 processMemAliasingDecoration(LLVMContext::MD_noalias);
3113 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3115 bool AllowFPMaxError =
3117 if (!AllowFPMaxError)
3121 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3125 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
3129 auto &Ctx =
B.getContext();
3131 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
3134 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3136 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3137 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3140 if (
I->hasMetadata(LLVMContext::MD_atomic_ignore_denormal_mode))
3142 Ctx, {US,
MDString::get(Ctx,
"atomic.ignore.denormal.mode")}));
3144 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3152 &FPFastMathDefaultInfoMap,
3154 auto it = FPFastMathDefaultInfoMap.
find(
F);
3155 if (it != FPFastMathDefaultInfoMap.
end())
3163 SPIRV::FPFastMathMode::None);
3165 SPIRV::FPFastMathMode::None);
3167 SPIRV::FPFastMathMode::None);
3168 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3174 size_t BitWidth = Ty->getScalarSizeInBits();
3178 assert(Index >= 0 && Index < 3 &&
3179 "Expected FPFastMathDefaultInfo for half, float, or double");
3180 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3181 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3182 return FPFastMathDefaultInfoVec[Index];
3185void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3187 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3196 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3198 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3206 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3209 [[maybe_unused]] GlobalVariable *GV =
3210 new GlobalVariable(M,
3211 Type::getInt32Ty(
M.getContext()),
3225 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3226 FPFastMathDefaultInfoMap;
3228 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3237 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3239 "Expected 4 operands for FPFastMathDefault");
3245 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3247 SPIRV::FPFastMathDefaultInfo &
Info =
3250 Info.FPFastMathDefault =
true;
3251 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3253 "Expected no operands for ContractionOff");
3257 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3259 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3260 Info.ContractionOff =
true;
3262 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3264 "Expected 1 operand for SignedZeroInfNanPreserve");
3265 unsigned TargetWidth =
3270 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3274 assert(Index >= 0 && Index < 3 &&
3275 "Expected FPFastMathDefaultInfo for half, float, or double");
3276 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3277 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3278 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3282 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3283 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3284 if (FPFastMathDefaultInfoVec.
empty())
3287 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3288 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3291 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3292 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3296 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3298 "and AllowContract");
3300 if (
Info.SignedZeroInfNanPreserve &&
3302 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3303 SPIRV::FPFastMathMode::NSZ))) {
3304 if (
Info.FPFastMathDefault)
3306 "SignedZeroInfNanPreserve but at least one of "
3307 "NotNaN/NotInf/NSZ is enabled.");
3310 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3311 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3312 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3314 "AllowTransform requires AllowReassoc and "
3315 "AllowContract to be set.");
3318 auto it = GlobalVars.
find(Flags);
3319 GlobalVariable *GV =
nullptr;
3320 if (it != GlobalVars.
end()) {
3326 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3329 GV =
new GlobalVariable(M,
3330 Type::getInt32Ty(
M.getContext()),
3335 GlobalVars[
Flags] = GV;
3341void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3344 bool IsConstComposite =
3345 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3346 if (IsConstComposite && TrackConstants) {
3348 auto t = AggrConsts.
find(
I);
3352 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3354 NewOp->setArgOperand(0,
I);
3357 for (
const auto &
Op :
I->operands()) {
3361 unsigned OpNo =
Op.getOperandNo();
3362 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3363 (!
II->isBundleOperand(OpNo) &&
3364 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3368 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3369 :
B.SetInsertPoint(
I);
3372 Type *OpTy =
Op->getType();
3380 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3382 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3383 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3385 SmallVector<Value *, 2>
Args = {
3389 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3395 I->setOperand(OpNo, NewOp);
3401Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3403 SmallPtrSet<Function *, 0> FVisited;
3404 return deduceFunParamElementType(
F, OpIdx, FVisited);
3407Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3408 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3410 if (!FVisited.
insert(
F).second)
3413 SmallPtrSet<Value *, 0> Visited;
3416 for (User *U :
F->users()) {
3418 if (!CI || OpIdx >= CI->
arg_size())
3428 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3431 for (User *OpU : OpArg->
users()) {
3433 if (!Inst || Inst == CI)
3436 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3443 if (FVisited.
find(OuterF) != FVisited.
end())
3445 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3446 if (OuterF->
getArg(i) == OpArg) {
3447 Lookup.push_back(std::make_pair(OuterF, i));
3454 for (
auto &Pair :
Lookup) {
3455 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3462void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3464 B.SetInsertPointPastAllocas(
F);
3465 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3471 for (User *U : Arg->
users()) {
3473 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3491 for (User *U :
F->users()) {
3493 if (!CI || OpIdx >= CI->
arg_size())
3507 for (User *U : Arg->
users()) {
3511 CI->
getParent()->getParent() == CurrF) {
3513 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3525 B.SetInsertPointPastAllocas(
F);
3526 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3531 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3533 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3537 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3549 bool IsNewFTy =
false;
3565bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3568 if (
F.isIntrinsic())
3570 if (
F.isDeclaration()) {
3571 for (User *U :
F.users()) {
3584 for (User *U :
F.users()) {
3586 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3588 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3589 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3597 if (Worklist.
empty())
3600 LLVMContext &Ctx =
M.getContext();
3607 for (
const auto &Arg :
F->args())
3610 IRB.CreateCall(
F, Args);
3612 IRB.CreateRetVoid();
3618void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3619 DenseMap<Function *, CallInst *> Ptrcasts;
3620 for (
auto It : FDeclPtrTys) {
3622 for (
auto *U :
F->users()) {
3627 for (
auto [Idx, ElemTy] : It.second) {
3635 B.SetInsertPointPastAllocas(Arg->
getParent());
3639 }
else if (isaGEP(Param)) {
3640 replaceUsesOfWithSpvPtrcast(
3641 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3650 .getFirstNonPHIOrDbgOrAlloca());
3668 FDeclPtrTys.
clear();
3671GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3672 GetElementPtrInst *
GEP) {
3679 Type *SrcTy =
GEP->getSourceElementType();
3680 SmallVector<Value *, 8> Indices(
GEP->indices());
3682 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3683 Indices.erase(Indices.begin());
3684 SrcTy = ArrTy->getElementType();
3686 GEP->getNoWrapFlags(),
"",
3687 GEP->getIterator());
3692void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3699 if (
ST->canUseExtension(
3700 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3701 for (BasicBlock &BB :
F) {
3703 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3707 SmallVector<unsigned, 1>
Ops =
3709 unsigned LC =
Ops[0];
3710 if (LC == SPIRV::LoopControl::None)
3714 B.SetInsertPoint(Term);
3715 SmallVector<Value *, 4> IntrArgs;
3716 for (
unsigned Op :
Ops)
3718 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3730 SmallPtrSet<BasicBlock *, 8> UsedMergeBlocks;
3737 SmallVector<unsigned, 1> LoopControlOps =
3739 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3752 for (BasicBlock *BB : {Latch, Header}) {
3756 if (!
L->contains(Succ) && !UsedMergeBlocks.
contains(Succ))
3759 if (!MergeBlock || !UsedMergeBlocks.
insert(MergeBlock).second)
3762 B.SetInsertPoint(Header->getTerminator());
3765 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3766 for (
unsigned Imm : LoopControlOps)
3767 Args.emplace_back(
B.getInt32(
Imm));
3768 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3772bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3773 if (
Func.isDeclaration())
3782 GR =
ST.getSPIRVGlobalRegistry();
3786 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3788 CanUseAnyVectorRank =
3789 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3793 AggrConstTypes.
clear();
3796 processParamTypesByFunHeader(CurrF,
B);
3800 SmallPtrSet<Instruction *, 4> DeadInsts;
3803 Type *ElTy =
SI->getValueOperand()->getType();
3818 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3822 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3824 GEP->replaceAllUsesWith(NewGEP);
3828 if (
Type *GepTy = getGEPType(
GEP))
3832 for (
auto *
I : DeadInsts) {
3833 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3834 I->eraseFromParent();
3837 B.SetInsertPoint(
Func.getEntryBlock().begin());
3838 for (
auto &GV :
Func.getParent()->globals())
3839 processGlobalValue(GV,
B);
3841 reconstructAggregateReturns(Func,
B);
3842 preprocessUndefsAndPoisons(
B);
3843 simplifyNullAddrSpaceCasts();
3844 preprocessCompositeConstants(
B);
3852 Type *I32Ty =
B.getInt32Ty();
3857 insertCompositeAggregateArms(&
I,
B);
3858 AggrConstTypes[&
I] =
I.getType();
3859 I.mutateType(I32Ty);
3862 preprocessBoolVectorBitcasts(Func);
3863 SmallVector<Instruction *> Worklist(
3866 applyDemangledPtrArgTypes(
B);
3869 for (
auto &
I : Worklist) {
3871 if (isConvergenceIntrinsic(
I))
3874 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3876 insertAssignTypeIntrs(
I,
B);
3877 insertPtrCastOrAssignTypeInstr(
I,
B);
3882 insertAssignPtrTypeIntrs(
I,
B,
true);
3885 useRoundingMode(FPI,
B);
3890 SmallPtrSet<Instruction *, 4> IncompleteRets;
3892 deduceOperandElementType(&
I, &IncompleteRets);
3896 for (BasicBlock &BB : Func)
3897 for (PHINode &Phi : BB.
phis())
3899 deduceOperandElementType(&Phi,
nullptr);
3901 for (
auto *
I : Worklist) {
3902 TrackConstants =
true;
3912 if (isConvergenceIntrinsic(
I))
3916 processInstrAfterVisit(
I,
B);
3919 emitUnstructuredLoopControls(Func,
B);
3925bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3926 if (!GR || TodoTypeSz == 0)
3929 unsigned SzTodo = TodoTypeSz;
3930 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3937 if (!KnownTy || !AssignCI)
3943 SmallPtrSet<Value *, 0> Visited;
3944 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3945 if (ElemTy != KnownTy) {
3946 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3947 propagateElemType(CI, ElemTy, VisitedSubst);
3954 if (
Op->hasUseList()) {
3955 for (User *U :
Op->users()) {
3962 if (TodoTypeSz == 0)
3967 SmallPtrSet<Instruction *, 4> IncompleteRets;
3969 auto It = ToProcess.
find(&
I);
3970 if (It == ToProcess.
end())
3972 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3973 if (It->second.size() == 0)
3975 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3976 if (TodoTypeSz == 0)
3981 return SzTodo > TodoTypeSz;
3995 .Cases({
"char",
"signed char",
"unsigned char",
"short",
3996 "unsigned short",
"int",
"unsigned int",
"_Float16",
"float",
4004 unsigned NumElts = 0;
4005 if (
Count.getAsInteger(10, NumElts) || NumElts == 0)
4012 TypeStr.
split(Quals,
' ', -1,
false);
4015 if (Qual !=
"const" && Qual !=
"volatile" && Qual !=
"restrict" &&
4016 !(Qual.consume_front(
"AS") && !Qual.getAsInteger(10, AS)))
4023void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
4025 if (!
F.isDeclaration() ||
F.isIntrinsic())
4028 if (DemangledName.empty())
4031 auto Set =
ST.getPreferredInstructionSet();
4032 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(DemangledName, Set);
4034 const bool IsBuiltin = Grp >= 0 || SPIRV::isBuiltin(DemangledName, Set);
4035 if (IsBuiltin && Opcode != SPIRV::OpGroupAsyncCopy)
4037 SmallVector<unsigned> Idxs;
4038 for (Argument &Arg :
F.args())
4043 LLVMContext &Ctx =
F.getContext();
4045 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
4046 if (TypeStrs.
empty())
4049 if (!IsBuiltin && (!
F.getName().starts_with(
"_Z") ||
F.hasStructRetAttr() ||
4050 StringRef(DemangledName).
count(
'(') != 1 ||
4051 StringRef(DemangledName).
count(
')') != 1 ||
4052 StringRef(DemangledName).
contains(
'<') ||
4053 TypeStrs.
size() !=
F.arg_size()))
4055 bool AllowLongVectors =
4056 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
4057 for (
unsigned Idx : Idxs) {
4058 if (Idx >= TypeStrs.
size())
4060 StringRef TypeStr = TypeStrs[
Idx].trim();
4061 Type *ElemTy = IsBuiltin
4062 ? SPIRV::parseBuiltinCallArgumentType(TypeStr, Ctx)
4072 FDeclPtrTys[&
F].emplace_back(Idx, ElemTy);
4074 ST.getSPIRVGlobalRegistry()->addDeducedElementType(
F.getArg(Idx),
4080bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
4081 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
4083 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
4084 if (!
ST.canUseExtension(
4085 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4086 I.getContext().emitError(
4087 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
4091 I.eraseFromParent();
4097 Value *Ptrs =
I.getArgOperand(0);
4099 Value *Passthru =
I.getArgOperand(2);
4102 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
4104 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
4109 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
4111 I.eraseFromParent();
4115 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
4116 if (!
ST.canUseExtension(
4117 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4118 I.getContext().emitError(
4119 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
4122 I.eraseFromParent();
4129 Value *Ptrs =
I.getArgOperand(1);
4134 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
4136 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
4140 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
4141 I.eraseFromParent();
4152void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
4153 struct BoolVecBitcast {
4155 FixedVectorType *BoolVecTy;
4159 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4161 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4169 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4171 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4175 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4177 Value *Src = BC->getOperand(0);
4178 unsigned BoolVecN = BoolVecTy->getNumElements();
4180 Type *IntTy =
B.getIntNTy(BoolVecN);
4186 IntVal = ConstantInt::get(IntTy, 0);
4187 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4188 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
4189 Value *Ext =
B.CreateZExt(Elem, IntTy);
4191 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
4192 IntVal =
B.CreateOr(IntVal, Ext);
4198 if (!Src->getType()->isIntegerTy())
4199 IntVal =
B.CreateBitCast(Src, IntTy);
4204 if (!SrcIsBoolVec) {
4207 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4210 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
4211 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4217 if (!BC->getDestTy()->isIntegerTy())
4218 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4221 BC->replaceAllUsesWith(Result);
4222 BC->eraseFromParent();
4226bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4230 if (!
F.isIntrinsic())
4233 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4238 Changed |= processMaskedMemIntrinsic(*
II);
4242 F.eraseFromParent();
4248bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4251 Changed |= convertMaskedMemIntrinsics(M);
4253 parseFunDeclarations(M);
4254 insertConstantsForFPFastMathDefault(M);
4265 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4267 processParamTypes(&
F,
B);
4271 CanTodoType =
false;
4272 Changed |= postprocessTypes(M);
4275 Changed |= processFunctionPointers(M);
4282 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4288 return new SPIRVEmitIntrinsicsLegacy(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void replaceAllUsesWith(Value *Old, Value *New, SmallPtrSet< BasicBlock *, 32 > &FreshBBs, bool IsHuge)
Replace all old uses with new ones, and push the updated BBs into FreshBBs.
static Type * getPointeeType(Value *Ptr, const DataLayout &DL)
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
static bool runOnFunction(Function &F, bool PostInlining)
iv Induction Variable Users
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Machine Check Debug Module
uint64_t IntrinsicInst * II
OptimizedStructLayoutField Field
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrConstForceInt32(const Value *V)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, DenseMap< Function *, SPIRV::FPFastMathDefaultInfoVector > &FPFastMathDefaultInfoMap, Function *F)
static Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static void emitAssignName(Instruction *I, IRBuilder<> &B)
static bool isArtificialGlobal(StringRef Name)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void createRoundingModeDecoration(Instruction *I, unsigned RoundingModeDeco, IRBuilder<> &B)
static void createDecorationIntrinsic(Instruction *I, MDNode *Node, IRBuilder<> &B)
static bool hasOnlyArtificialUses(const GlobalVariable &GV)
static bool isAggregateValueIdInstr(const Instruction &I)
static SPIRV::FPFastMathDefaultInfo & getFPFastMathDefaultInfo(SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty)
static bool isAbortCall(const Instruction &I, const SPIRVSubtarget &ST)
static cl::opt< bool > SpirvEmitOpNames("spirv-emit-op-names", cl::desc("Emit OpName for all instructions"), cl::init(false))
static bool tracesToPointerAlloca(Value *V)
static bool isUseListGlobal(StringRef Name)
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool isSpvAggrPlaceholder(const Value *V)
static bool precededByAbortIntrinsic(const UnreachableInst &I, const SPIRVSubtarget &ST)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static bool isMultiRegisterAggregate(Value *V)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static Type * parseDeclPtrElemType(StringRef TypeStr, LLVMContext &Ctx)
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)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the SmallPtrSet class.
This file defines the SmallString class.
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
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
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
@ UIncWrap
Increment one up to a maximum value.
@ UDecWrap
Decrement one until a minimum value or zero.
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.
void setCallingConv(CallingConv::ID CC)
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static 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 > insert(const std::pair< KeyT, ValueT > &KV)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
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()
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Module * getParent()
Get the module that this global value is contained inside of...
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()
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()
SmallVector< LoopT *, 4 > getLoopsInPreorder() const
Return all of the loops in the function in preorder across the loop nests, with siblings in forward p...
void analyze(ParentT F)
Create the loop forest for a function.
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 buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg, bool CanUseAnyVectorRank)
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg)
Type * findDeducedCompositeType(const Value *Val)
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld=true)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
iterator find(ConstPtrType Ptr) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator find(StringRef Key)
Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
Check if the string is empty.
constexpr size_t size() const
Get the string size.
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
A switch()-like statement whose cases are string literals.
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 Triple & getTargetTriple() const
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
VendorType getVendor() const
Get the parsed vendor type of this triple.
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.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element 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.
@ 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)
auto m_Value()
Match an arbitrary value and ignore it.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
std::string lookupBuiltinNameHelper(StringRef DemangledCall, FPDecorationId *DecorationId)
Parses the name part of the demangled builtin call.
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
unsigned getNumElements(Type *Ty)
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.
ModulePass * createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
RelativeUniformCounterPtr Values
uint32_t getMemSemanticsWithStorageClass(const Triple &TT, uint32_t OrderSem, uint32_t StorageClassSem)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
bool isUntypedPointerVectorTy(const Type *T)
bool isLongVectorEXT(const Type *Ty)
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...
bool sortBlocks(Function &F)
SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx, SyncScope::ID Id)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
bool isNestedPointer(const Type *Ty)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
Type * normalizeType(Type *Ty, bool CanUseAnyVectorRank)
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.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
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)
@ Ref
The access may reference the value stored in memory.
@ And
Bitwise or logical AND of integers.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Type * parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx)
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)
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 CanUseAnyVectorRank)
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)