27#include "llvm/IR/IntrinsicsSPIRV.h"
60#define DEBUG_TYPE "spirv-emit-intrinsics"
64 cl::desc(
"Emit OpName for all instructions"),
68#define GET_BuiltinGroup_DECL
69#include "SPIRVGenTables.inc"
74class GlobalVariableUsers {
75 template <
typename T1,
typename T2>
76 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
78 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
80 void collectGlobalUsers(
81 const GlobalVariable *GV,
82 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
83 &GlobalIsUsedByGlobal) {
85 while (!
Stack.empty()) {
89 GlobalIsUsedByFun[GV].insert(
I->getFunction());
94 GlobalIsUsedByGlobal[GV].insert(UserGV);
99 Stack.append(
C->user_begin(),
C->user_end());
103 bool propagateGlobalToGlobalUsers(
104 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
105 &GlobalIsUsedByGlobal) {
108 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
109 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
110 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
111 auto It = GlobalIsUsedByGlobal.find(UserGV);
112 if (It == GlobalIsUsedByGlobal.end())
120 void propagateGlobalToFunctionReferences(
121 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
122 &GlobalIsUsedByGlobal) {
123 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
124 auto &UserFunctions = GlobalIsUsedByFun[GV];
125 for (
const GlobalVariable *UserGV : UserGlobals) {
126 auto It = GlobalIsUsedByFun.find(UserGV);
127 if (It == GlobalIsUsedByFun.end())
138 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
139 GlobalIsUsedByGlobal;
140 GlobalIsUsedByFun.clear();
141 for (GlobalVariable &GV :
M.globals())
142 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
145 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
148 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
151 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
152 const FunctionSetType &
153 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
154 auto It = GlobalIsUsedByFun.find(&GV);
155 if (It != GlobalIsUsedByFun.end())
158 static const FunctionSetType
Empty{};
163static bool isaGEP(
const Value *V) {
169static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
175 return AT->getNumElements();
181class SPIRVEmitIntrinsicsImpl
182 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
183 const SPIRVTargetMachine &TM;
184 SPIRVGlobalRegistry *GR =
nullptr;
186 bool TrackConstants =
true;
187 bool HaveFunPtrs =
false;
188 bool CanUseAnyVectorRank =
false;
189 DenseMap<Instruction *, Constant *> AggrConsts;
190 DenseMap<Instruction *, Type *> AggrConstTypes;
191 SmallPtrSet<Instruction *, 0> AggrStores;
192 GlobalVariableUsers GVUsers;
193 SmallPtrSet<Value *, 0> Named;
196 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
199 bool CanTodoType =
true;
200 unsigned TodoTypeSz = 0;
201 DenseMap<Value *, bool> TodoType;
202 void insertTodoType(
Value *
Op) {
204 if (CanTodoType && !isaGEP(
Op)) {
205 auto It = TodoType.try_emplace(
Op,
true);
210 void eraseTodoType(
Value *
Op) {
211 auto It = TodoType.find(
Op);
212 if (It != TodoType.end() && It->second) {
220 auto It = TodoType.find(
Op);
221 return It != TodoType.end() && It->second;
225 SmallPtrSet<Instruction *, 0> TypeValidated;
228 enum WellKnownTypes { Event };
231 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
232 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
233 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
234 bool UnknownElemTypeI8,
235 bool IgnoreKnownType =
false);
236 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
237 bool UnknownElemTypeI8);
238 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
239 SmallPtrSetImpl<Value *> &Visited,
240 bool UnknownElemTypeI8);
242 SmallPtrSetImpl<Value *> &Visited,
243 bool UnknownElemTypeI8);
245 bool UnknownElemTypeI8);
248 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
249 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
250 SmallPtrSetImpl<Value *> &Visited,
251 bool UnknownElemTypeI8);
255 deduceOperandElementType(Instruction *
I,
256 SmallPtrSetImpl<Instruction *> *IncompleteRets,
257 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
258 bool IsPostprocessing =
false);
263 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
264 void simplifyNullAddrSpaceCasts();
266 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
267 bool IsPostprocessing);
269 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
271 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
272 bool UnknownElemTypeI8);
274 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
276 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
277 Type *ExpectedElementType,
278 unsigned OperandToReplace,
280 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
281 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
283 void insertConstantsForFPFastMathDefault(
Module &M);
286 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
289 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,
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);
351 bool walkLogicalAccessChain(
352 GetElementPtrInst &
GEP,
353 const std::function<
void(
Type *PointedType,
uint64_t Index)>
356 uint64_t Multiplier)> &OnDynamicIndexing);
358 bool walkLogicalAccessChainDynamic(
360 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
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);
383 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
386 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
389 Instruction *visitInsertElementInst(InsertElementInst &
I);
390 Instruction *visitExtractElementInst(ExtractElementInst &
I);
392 Instruction *visitExtractValueInst(ExtractValueInst &
I);
396 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
400 bool runOnModule(
Module &M);
403class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
404 const SPIRVTargetMachine &TM;
408 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
409 : ModulePass(ID), TM(TM) {}
411 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
413 bool runOnModule(
Module &M)
override {
414 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
420 Intrinsic::experimental_convergence_loop,
421 Intrinsic::experimental_convergence_anchor>());
424bool expectIgnoredInIRTranslation(
const Instruction *
I) {
426 Intrinsic::spv_resource_handlefrombinding,
427 Intrinsic::spv_resource_getbasepointer,
428 Intrinsic::spv_resource_getpointer>());
435 return getPointerRoot(V);
441char SPIRVEmitIntrinsicsLegacy::ID = 0;
444 "SPIRV emit intrinsics",
false,
false)
458 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
471 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
477 B.SetCurrentDebugLocation(
I->getDebugLoc());
478 if (
I->getType()->isVoidTy())
479 B.SetInsertPoint(
I->getNextNode());
481 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
491 if (
I->getType()->isTokenTy())
493 "does not support token type",
498 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
499 expectIgnoredInIRTranslation(
I))
510 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
521 std::vector<Value *> Args = {
524 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
527void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
531 if (isTodoType(Src)) {
534 insertTodoType(Dest);
538void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
543 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
544 Src->eraseFromParent();
547 if (Named.
insert(Dest).second)
562 V = V->stripPointerCasts();
583Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
584 bool UnknownElemTypeI8,
585 bool IsPostprocessing) {
589 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
603 if (UnknownElemTypeI8) {
604 if (!IsPostprocessing)
620 B.SetInsertPointPastAllocas(OpA->getParent());
623 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
625 Type *OpTy =
Op->getType();
627 SmallVector<Value *, 2>
Args = {
630 CallInst *PtrCasted =
631 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
636void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
638 DenseMap<Function *, CallInst *> Ptrcasts) {
640 CallInst *PtrCastedI =
nullptr;
641 auto It = Ptrcasts.
find(
F);
642 if (It == Ptrcasts.
end()) {
643 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
644 Ptrcasts[
F] = PtrCastedI;
646 PtrCastedI = It->second;
648 I->replaceUsesOfWith(
Op, PtrCastedI);
651void SPIRVEmitIntrinsicsImpl::propagateElemType(
653 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
654 DenseMap<Function *, CallInst *> Ptrcasts;
656 for (
auto *U :
Users) {
659 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
664 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
665 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
669void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
671 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
672 SmallPtrSet<Value *, 0> Visited;
673 DenseMap<Function *, CallInst *> Ptrcasts;
674 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
675 std::move(Ptrcasts));
678void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
680 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
681 SmallPtrSetImpl<Value *> &Visited,
682 DenseMap<Function *, CallInst *> Ptrcasts) {
686 for (
auto *U :
Users) {
689 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
694 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
695 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
702Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
703 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
704 SmallPtrSet<Value *, 0> Visited;
705 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
709Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
710 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
711 bool UnknownElemTypeI8) {
716 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
727Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
728 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
740 for (User *OpU :
Op->users()) {
742 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
754 Function *CalledF,
unsigned OpIdx) {
755 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
764Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
765 bool UnknownElemTypeI8) {
766 SmallPtrSet<Value *, 0> Visited;
767 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
770void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
772 bool UnknownElemTypeI8) {
774 if (!UnknownElemTypeI8)
783bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
785 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
792 if (
ST->getNumElements() == 0)
794 CurType =
ST->getElementType(0);
795 OnLiteralIndexing(CurType, 0);
803 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
804 return AT ==
nullptr;
807bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
809 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing) {
814 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
818 CurType = AT->getElementType();
819 OnLiteralIndexing(CurType, Index);
821 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
824 const auto &STL =
DL.getStructLayout(ST);
825 unsigned Element = STL->getElementContainingOffset(
Offset);
826 Offset -= STL->getElementOffset(Element);
827 CurType =
ST->getElementType(Element);
828 OnLiteralIndexing(CurType, Element);
830 Type *EltTy = VT->getElementType();
831 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
832 assert(EltSizeBits % 8 == 0 &&
833 "Element type size in bits must be a multiple of 8.");
834 uint32_t EltTypeSize = EltSizeBits / 8;
839 OnLiteralIndexing(CurType, Index);
849bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
850 GetElementPtrInst &
GEP,
851 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
855 std::optional<uint64_t> MultiplierOpt =
856 getByteAddressingMultiplier(
GEP.getSourceElementType());
857 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
858 uint64_t Multiplier = *MultiplierOpt;
861 Value *Src = getPointerRoot(
GEP.getPointerOperand());
862 Type *CurType = deduceElementType(Src,
true);
866 return walkLogicalAccessChainConstant(
867 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
869 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
870 OnLiteralIndexing, OnDynamicIndexing);
873Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
874 GetElementPtrInst &
GEP) {
877 B.SetInsertPoint(&
GEP);
879 std::vector<Value *> Indices;
880 Indices.push_back(ConstantInt::get(
881 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
882 walkLogicalAccessChain(
886 ConstantInt::get(
B.getInt64Ty(), Index,
false));
891 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
893 if (Multiplier == EltTypeSize) {
895 }
else if (EltTypeSize % Multiplier == 0) {
898 EltTypeSize / Multiplier,
902 ConstantInt::get(
Offset->getType(), Multiplier,
905 Index =
B.CreateUDiv(Index,
906 ConstantInt::get(
Offset->getType(), EltTypeSize,
910 Indices.push_back(Index);
914 SmallVector<Value *, 4>
Args;
915 Args.push_back(
B.getInt1(
GEP.isInBounds()));
916 Args.push_back(
GEP.getOperand(0));
919 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
920 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
924Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
926 Type *CurType =
GEP->getResultElementType();
928 bool Interrupted = walkLogicalAccessChain(
929 *
GEP, [&CurType](
Type *EltType,
uint64_t Index) { CurType = EltType; },
932 return Interrupted ?
GEP->getResultElementType() : CurType;
935Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
936 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
938 return getGEPTypeLogical(
Ref);
945 Ty =
Ref->getSourceElementType();
949 Ty =
Ref->getResultElementType();
954Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
955 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
956 bool IgnoreKnownType) {
962 if (!IgnoreKnownType)
974 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
976 Ty = getGEPType(
Ref);
978 Ty = SGEP->getResultElementType();
983 KnownTy =
Op->getType();
985 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
988 Ty = SPIRV::getOriginalFunctionType(*Fn);
991 Ty = deduceElementTypeByValueDeep(
993 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
997 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
999 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1001 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1003 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1005 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1010 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1014 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1016 Type *BestTy =
nullptr;
1018 DenseMap<Type *, unsigned> PhiTys;
1019 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1020 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1027 if (It.first->second > MaxN) {
1028 MaxN = It.first->second;
1036 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1040 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1041 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1046 static StringMap<unsigned> ResTypeByArg = {
1050 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1051 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1052 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1053 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1054 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1055 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1059 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1060 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1062 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1063 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1064 for (User *U :
II->users()) {
1069 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1071 Ty = HandleType->getTypeParameter(0);
1072 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1086 }
else if (
II &&
II->getIntrinsicID() ==
1087 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1091 std::string DemangledName =
1093 if (DemangledName.length() > 0)
1094 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1095 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1096 if (AsArgIt != ResTypeByArg.
end())
1097 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1098 Visited, UnknownElemTypeI8);
1105 if (Ty && !IgnoreKnownType) {
1116Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1117 bool UnknownElemTypeI8) {
1118 SmallPtrSet<Value *, 0> Visited;
1119 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1122Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1123 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1124 bool UnknownElemTypeI8) {
1133 if (!Visited.
insert(U).second)
1138 bool Change =
false;
1139 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1141 assert(
Op &&
"Operands should not be null.");
1142 Type *OpTy =
Op->getType();
1145 if (
Type *NestedTy =
1146 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1153 Change |= Ty != OpTy;
1161 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1162 Type *OpTy = ArrTy->getElementType();
1165 if (
Type *NestedTy =
1166 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1173 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1179 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1180 Type *OpTy = VecTy->getElementType();
1183 if (
Type *NestedTy =
1184 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1191 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1202Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1203 bool UnknownElemTypeI8) {
1204 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1206 if (!UnknownElemTypeI8)
1209 return IntegerType::getInt8Ty(
I->getContext());
1213 Value *PointerOperand) {
1219 return I->getType();
1227bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1229 Type *&KnownElemTy,
bool &Incomplete) {
1233 std::string DemangledName =
1235 if (DemangledName.length() > 0 &&
1237 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1238 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1239 DemangledName,
ST.getPreferredInstructionSet());
1240 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1241 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1247 KnownElemTy = ElemTy;
1248 Ops.push_back(std::make_pair(
Op, i));
1250 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1257 case SPIRV::OpAtomicFAddEXT:
1258 case SPIRV::OpAtomicFMinEXT:
1259 case SPIRV::OpAtomicFMaxEXT:
1260 case SPIRV::OpAtomicLoad:
1261 case SPIRV::OpAtomicCompareExchangeWeak:
1262 case SPIRV::OpAtomicCompareExchange:
1263 case SPIRV::OpAtomicExchange:
1264 case SPIRV::OpAtomicIAdd:
1265 case SPIRV::OpAtomicISub:
1266 case SPIRV::OpAtomicOr:
1267 case SPIRV::OpAtomicXor:
1268 case SPIRV::OpAtomicAnd:
1269 case SPIRV::OpAtomicUMin:
1270 case SPIRV::OpAtomicUMax:
1271 case SPIRV::OpAtomicSMin:
1272 case SPIRV::OpAtomicSMax: {
1277 Incomplete = isTodoType(
Op);
1278 Ops.push_back(std::make_pair(
Op, 0));
1280 case SPIRV::OpAtomicStore: {
1289 Incomplete = isTodoType(
Op);
1290 Ops.push_back(std::make_pair(
Op, 0));
1299void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1301 Type *&KnownElemTy,
bool IsPostprocessing) {
1305 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1306 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1307 bool IsNewFTy =
false, IsIncomplete =
false;
1310 Type *ArgTy = Arg->getType();
1315 if (isTodoType(Arg))
1316 IsIncomplete =
true;
1318 IsIncomplete =
true;
1321 ArgTy = FTy->getFunctionParamType(ParmIdx);
1325 Type *RetTy = FTy->getReturnType();
1332 IsIncomplete =
true;
1334 IsIncomplete =
true;
1337 if (!IsPostprocessing && IsIncomplete)
1340 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1343bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1344 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1345 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1357 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1358 for (User *U :
F->users()) {
1367 propagateElemType(CI, PrevElemTy, VisitedSubst);
1377 for (Instruction *IncompleteRetI : *IncompleteRets)
1378 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1380 }
else if (IncompleteRets) {
1391void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1392 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1393 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1395 Type *KnownElemTy =
nullptr;
1396 bool Incomplete =
false;
1402 Incomplete = isTodoType(
I);
1403 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1406 Ops.push_back(std::make_pair(
Op, i));
1412 Incomplete = isTodoType(
I);
1413 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1420 Incomplete = isTodoType(
I);
1421 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1425 KnownElemTy =
Ref->getSourceElementType();
1426 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1431 KnownElemTy =
Ref->getBaseType();
1432 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1435 KnownElemTy =
I->getType();
1442 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1451 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1455 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1460 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1468 Incomplete = isTodoType(
Ref->getPointerOperand());
1469 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1477 Incomplete = isTodoType(
Ref->getPointerOperand());
1478 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1484 Incomplete = isTodoType(
I);
1485 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1488 Ops.push_back(std::make_pair(
Op, i));
1496 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1497 IsPostprocessing, KnownElemTy,
Op,
1500 Incomplete = isTodoType(CurrF);
1501 Ops.push_back(std::make_pair(
Op, 0));
1507 bool Incomplete0 = isTodoType(Op0);
1508 bool Incomplete1 = isTodoType(Op1);
1510 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1512 : GR->findDeducedElementType(Op0);
1514 KnownElemTy = ElemTy0;
1515 Incomplete = Incomplete0;
1516 Ops.push_back(std::make_pair(Op1, 1));
1517 }
else if (ElemTy1) {
1518 KnownElemTy = ElemTy1;
1519 Incomplete = Incomplete1;
1520 Ops.push_back(std::make_pair(Op0, 0));
1524 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1525 else if (HaveFunPtrs)
1526 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1531 if (!KnownElemTy ||
Ops.size() == 0)
1536 for (
auto &OpIt :
Ops) {
1540 Type *AskTy =
nullptr;
1541 CallInst *AskCI =
nullptr;
1542 if (IsPostprocessing && AskOps) {
1548 if (Ty == KnownElemTy)
1551 Type *OpTy =
Op->getType();
1557 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1565 else if (!IsPostprocessing)
1569 if (AssignCI ==
nullptr) {
1578 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1579 std::make_pair(
I,
Op)};
1580 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1584 CallInst *PtrCastI =
1585 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1586 if (OpIt.second == std::numeric_limits<unsigned>::max())
1589 I->setOperand(OpIt.second, PtrCastI);
1595void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1600 if (isAssignTypeInstr(U)) {
1601 B.SetInsertPoint(U);
1602 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1603 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1604 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1606 U->eraseFromParent();
1609 U->replaceUsesOfWith(Old, New);
1617 Type *NewArgTy =
New->getType();
1619 if (NewArgTy != ExpectedArgTy) {
1622 M, Intrinsic::spv_abort, {NewArgTy});
1632 "aggregate PHI/select/freeze should have been mutated to value-id "
1634 U->replaceUsesOfWith(Old, New);
1639 New->copyMetadata(*Old);
1645 bool HasPoisonExt) {
1652 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1653 "lowered as undef\n");
1655 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1656 Type *Ty = UV->getType();
1662 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1663 :
B.CreateIntrinsicWithoutFolding(IID, {});
1664 AggrConsts[
Call] = UV;
1665 AggrConstTypes[
Call] = Ty;
1670 return B.CreateIntrinsic(IID, {Ty}, {});
1677void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1682 SmallVector<Instruction *, 16> Insts;
1686 for (Instruction *
I : Insts) {
1687 bool BPrepared =
false;
1689 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1693 bool IsScalar = !
Op->getType()->isAggregateType();
1696 if (IsScalar && !AsPoison)
1700 if (IsScalar && Phi)
1701 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1702 else if (!BPrepared) {
1706 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1707 I->setOperand(Idx, Repl);
1716void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1720 ASC->replaceAllUsesWith(
1722 ASC->eraseFromParent();
1730 if (!V->getType()->isAggregateType())
1739 I.getType()->isAggregateType();
1745void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1748 for (Use &U :
I->operands()) {
1755 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1760 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1762 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1768void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1772 std::queue<Instruction *> Worklist;
1776 while (!Worklist.empty()) {
1777 auto *
I = Worklist.front();
1780 bool KeepInst =
false;
1781 for (
const auto &
Op :
I->operands()) {
1783 Type *ResTy =
nullptr;
1786 ResTy = COp->getType();
1798 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1801 auto PrepareInsert = [&]() {
1804 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1805 :
B.SetInsertPoint(
I);
1810 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1811 Args.push_back(COp->getElementAsConstant(i));
1817 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1826 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1832 auto *CI =
B.CreateIntrinsicWithoutFolding(
1833 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1837 AggrConsts[CI] = AggrConst;
1838 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1850 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1855 unsigned RoundingModeDeco,
1862 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1871 MDNode *SaturatedConversionNode =
1873 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1893 MDString *ConstraintString =
1898 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1902 B.SetInsertPoint(&
Call);
1903 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1908void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1911 if (!
RM.has_value())
1913 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1914 switch (
RM.value()) {
1918 case RoundingMode::NearestTiesToEven:
1919 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1921 case RoundingMode::TowardNegative:
1922 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1924 case RoundingMode::TowardPositive:
1925 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1927 case RoundingMode::TowardZero:
1928 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1930 case RoundingMode::Dynamic:
1931 case RoundingMode::NearestTiesToAway:
1935 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1941Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1945 B.SetInsertPoint(&
I);
1946 SmallVector<Value *, 4>
Args;
1948 Args.push_back(
I.getCondition());
1951 for (
auto &Case :
I.cases()) {
1952 Args.push_back(Case.getCaseValue());
1953 BBCases.
push_back(Case.getCaseSuccessor());
1956 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1957 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1961 I.eraseFromParent();
1964 B.SetInsertPoint(ParentBB);
1965 IndirectBrInst *BrI =
B.CreateIndirectBr(
1968 for (BasicBlock *BBCase : BBCases)
1977Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
1983 B.SetInsertPoint(&
I);
1985 SmallVector<Value *, 4>
Args;
1986 Args.push_back(
B.getInt1(
true));
1987 Args.push_back(
I.getOperand(0));
1988 Args.push_back(
B.getInt32(0));
1989 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1990 Args.push_back(SGEP->getIndexOperand(J));
1993 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1994 replaceAllUsesWithAndErase(
B, &
I, NewI);
1999SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2001 B.SetInsertPoint(&
I);
2006 unsigned N = RetVTy->getNumElements();
2007 Value *PtrOp =
I.getPointerOperand();
2009 Type *ResultPtrTy = RetVTy->getElementType();
2012 Value *InBounds =
B.getInt1(
I.isInBounds());
2013 Type *LanePointeeTy = getGEPType(&
I);
2014 Type *SrcElemTy =
I.getSourceElementType();
2023 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2024 Value *LaneIdx =
B.getInt32(Lane);
2025 Value *ScalarPtr = PtrOp;
2029 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2033 SmallVector<Value *, 4>
Args;
2034 Args.push_back(InBounds);
2035 Args.push_back(ScalarPtr);
2036 for (
Value *Idx :
I.indices()) {
2044 Args.push_back(visitExtractElementInst(*EI));
2048 Args.push_back(Idx);
2051 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2053 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2057 replaceAllUsesWithAndErase(
B, &
I, NewI);
2075 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2076 return buildLogicalAccessChainFromGEP(
I);
2081 Value *PtrOp =
I.getPointerOperand();
2082 Type *SrcElemTy =
I.getSourceElementType();
2083 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2086 if (ArrTy->getElementType() == SrcElemTy) {
2088 Type *FirstIdxType =
I.getOperand(1)->getType();
2089 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2090 for (
Value *Idx :
I.indices())
2094 SmallVector<Value *, 4>
Args;
2095 Args.push_back(
B.getInt1(
I.isInBounds()));
2096 Args.push_back(
I.getPointerOperand());
2099 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2101 replaceAllUsesWithAndErase(
B, &
I, NewI);
2108 SmallVector<Value *, 4>
Args;
2109 Args.push_back(
B.getInt1(
I.isInBounds()));
2112 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2113 replaceAllUsesWithAndErase(
B, &
I, NewI);
2117Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2119 B.SetInsertPoint(&
I);
2128 I.eraseFromParent();
2135 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2136 replaceAllUsesWithAndErase(
B, &
I, NewI);
2140void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2142 Type *VTy =
V->getType();
2147 if (ElemTy != AssignedType)
2160 if (CurrentType == AssignedType)
2167 " for value " +
V->getName(),
2176void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2177 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2182 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2183 if (PointerElemTy == ExpectedElementType ||
2188 Value *ExpectedElementVal =
2190 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2192 bool FirstPtrCastOrAssignPtrType =
true;
2198 for (
auto User :
Pointer->users()) {
2201 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2202 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2203 II->getOperand(0) != Pointer)
2208 FirstPtrCastOrAssignPtrType =
false;
2209 if (
II->getOperand(1) != VMD ||
2216 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2221 if (
II->getParent() !=
I->getParent())
2224 I->setOperand(OperandToReplace,
II);
2239 if (FirstPtrCastOrAssignPtrType) {
2244 }
else if (isTodoType(Pointer)) {
2245 eraseTodoType(Pointer);
2253 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2254 std::make_pair(
I, Pointer)};
2256 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2268 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2274void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2279 replacePointerOperandWithPtrCast(
2280 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2286 Type *OpTy =
Op->getType();
2289 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2292 if (OpTy ==
Op->getType())
2293 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2294 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2299 Type *OpTy = LI->getType();
2304 Type *NewOpTy = OpTy;
2305 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2306 if (OpTy == NewOpTy)
2307 insertTodoType(Pointer);
2310 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2315 Type *OpTy =
nullptr;
2327 OpTy = GEPI->getSourceElementType();
2329 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2331 insertTodoType(Pointer);
2343 std::string DemangledName =
2347 bool HaveTypes =
false;
2348 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2366 for (User *U : CalledArg->
users()) {
2368 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2374 HaveTypes |= ElemTy !=
nullptr;
2379 if (DemangledName.empty() && !HaveTypes)
2382 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2397 Type *ExpectedType =
2398 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2399 if (!ExpectedType && !DemangledName.empty())
2400 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2401 DemangledName, OpIdx,
I->getContext());
2402 if (!ExpectedType || ExpectedType->
isVoidTy())
2410 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2415SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2418 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2422 I.getOperand(1)->getType(),
2423 I.getOperand(2)->getType()};
2425 B.SetInsertPoint(&
I);
2427 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2429 replaceAllUsesWithAndErase(
B, &
I, NewI);
2434SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2437 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2441 B.SetInsertPoint(&
I);
2443 I.getIndexOperand()->getType()};
2444 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2445 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2447 replaceAllUsesWithAndErase(
B, &
I, NewI);
2451Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2453 B.SetInsertPoint(&
I);
2456 Value *AggregateOp =
I.getAggregateOperand();
2460 Args.push_back(AggregateOp);
2461 Args.push_back(
I.getInsertedValueOperand());
2462 for (
auto &
Op :
I.indices())
2463 Args.push_back(
B.getInt32(
Op));
2465 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2466 replaceMemInstrUses(&
I, NewI,
B);
2471SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2473 B.SetInsertPoint(&
I);
2474 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2483 for (
auto &
Op :
I.indices())
2484 Args.push_back(
B.getInt32(
Op));
2485 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2486 {
I.getType()}, {
Args});
2492 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2493 AggrConstTypes[NewI] =
I.getType();
2495 replaceMemInstrUses(&
I, NewI,
B);
2498 replaceAllUsesWithAndErase(
B, &
I, NewI);
2502 for (
const Use &U : NewI->
uses()) {
2503 User *Usr =
U.getUser();
2505 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2516 if (ArgNo < FT->getNumParams() &&
2517 !FT->getParamType(ArgNo)->isAggregateType()) {
2526Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2527 if (!
I.getType()->isAggregateType())
2530 B.SetInsertPoint(&
I);
2531 TrackConstants =
false;
2536 unsigned IntrinsicId;
2537 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2538 if (!
I.isAtomic()) {
2539 IntrinsicId = Intrinsic::spv_load;
2540 Args.push_back(
B.getInt32(
I.getAlign().value()));
2542 IntrinsicId = Intrinsic::spv_atomic_load;
2543 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2545 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2546 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2548 replaceMemInstrUses(&
I, NewI,
B);
2552Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2556 B.SetInsertPoint(&
I);
2557 TrackConstants =
false;
2561 auto *PtrOp =
I.getPointerOperand();
2563 if (
I.getValueOperand()->getType()->isAggregateType()) {
2571 "Unexpected argument of aggregate type, should be spv_extractv!");
2575 unsigned IntrinsicId;
2576 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2578 if (!
I.isAtomic()) {
2579 IntrinsicId = Intrinsic::spv_store;
2580 Args.push_back(
B.getInt32(
I.getAlign().value()));
2582 IntrinsicId = Intrinsic::spv_atomic_store;
2583 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2586 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2588 I.eraseFromParent();
2592Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2593 Value *ArraySize =
nullptr;
2594 if (
I.isArrayAllocation()) {
2597 SPIRV::Extension::SPV_INTEL_variable_length_array))
2599 "array allocation: this instruction requires the following "
2600 "SPIR-V extension: SPV_INTEL_variable_length_array",
2602 ArraySize =
I.getArraySize();
2605 B.SetInsertPoint(&
I);
2606 TrackConstants =
false;
2607 Type *PtrTy =
I.getType();
2610 ?
B.CreateIntrinsicWithoutFolding(
2611 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2612 {ArraySize,
B.getInt32(
I.getAlign().value())})
2613 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2614 {
B.getInt32(
I.getAlign().value())});
2615 replaceAllUsesWithAndErase(
B, &
I, NewI);
2620SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2621 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2623 B.SetInsertPoint(&
I);
2626 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2630 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2631 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2632 uint32_t ScSem =
static_cast<uint32_t
>(
2641 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2642 replaceMemInstrUses(&
I, NewI,
B);
2651 case Intrinsic::spv_abort:
2653 case Intrinsic::trap:
2654 case Intrinsic::ubsantrap:
2656 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2676 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2677 "abort-like call must be the last non-debug instruction before its "
2678 "block's terminator");
2682Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2683 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2687 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2694 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2708 while (!Stack.empty()) {
2709 const Value *V = Stack.pop_back_val();
2710 if (!Visited.
insert(V).second)
2718 Stack.append(
C->user_begin(),
C->user_end());
2734 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2735 if (UserFunctions.contains(
F))
2740 if (!UserFunctions.empty())
2745 const Module &M = *
F->getParent();
2746 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2747 return F == &FirstDefinition;
2750Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2752 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2753 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2755 AggrConstTypes[Leaf] = ElemTy;
2758 SmallVector<Value *, 4> Elems;
2760 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2763 DenseMap<Type *, Instruction *> LeafByType;
2764 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2766 auto &
Entry = LeafByType[ElemTy];
2768 Entry = MakeLeaf(ElemTy);
2772 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2773 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2775 AggrConstTypes[Composite] = AggrTy;
2784void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2789 for (BasicBlock &BB : Func) {
2793 Value *RetVal = RI->getReturnValue();
2800 B.SetInsertPoint(RI);
2803 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2804 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2806 RI->setOperand(0, Rebuilt);
2810void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2820 deduceElementTypeHelper(&GV,
false);
2825 Value *InitOp = Init;
2832 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2833 {
B.getInt32Ty()}, {});
2838 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2843 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2844 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2850 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2856bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2858 bool UnknownElemTypeI8) {
2864 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2871void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2874 static StringMap<unsigned> ResTypeWellKnown = {
2875 {
"async_work_group_copy", WellKnownTypes::Event},
2876 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2877 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2881 bool IsKnown =
false;
2886 std::string DemangledName =
2889 if (DemangledName.length() > 0)
2891 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2892 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2893 if (ResIt != ResTypeWellKnown.
end()) {
2896 switch (ResIt->second) {
2897 case WellKnownTypes::Event:
2900 CanUseAnyVectorRank);
2905 switch (DecorationId) {
2908 case FPDecorationId::SAT:
2911 case FPDecorationId::RTE:
2913 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2915 case FPDecorationId::RTZ:
2917 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2919 case FPDecorationId::RTP:
2921 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2923 case FPDecorationId::RTN:
2925 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2931 Type *Ty =
I->getType();
2934 Type *TypeToAssign = Ty;
2937 auto It = AggrConstTypes.
find(
II);
2938 if (It == AggrConstTypes.
end())
2940 TypeToAssign = It->second;
2941 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2942 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2943 TypeToAssign = It->second;
2945 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2946 TypeToAssign = It->second;
2950 for (
const auto &
Op :
I->operands()) {
2958 Type *OpTy =
Op->getType();
2960 CallInst *AssignCI =
2965 Type *OpTy =
Op->getType();
2981 Intrinsic::spv_assign_type, {OpTy},
2991bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
2992 Instruction *Inst) {
2994 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3004void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3006 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3008 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3013 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3014 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3015 if (shouldTryToAddMemAliasingDecoration(
I)) {
3016 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3017 ? SPIRV::Decoration::AliasScopeINTEL
3018 : SPIRV::Decoration::NoAliasINTEL;
3020 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3023 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3024 {
I->getType()}, {
Args});
3028 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3029 processMemAliasingDecoration(LLVMContext::MD_noalias);
3032 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3034 bool AllowFPMaxError =
3036 if (!AllowFPMaxError)
3040 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3044 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
3048 auto &Ctx =
B.getContext();
3050 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
3053 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3055 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3056 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3059 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
3061 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
3063 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3071 &FPFastMathDefaultInfoMap,
3073 auto it = FPFastMathDefaultInfoMap.
find(
F);
3074 if (it != FPFastMathDefaultInfoMap.
end())
3082 SPIRV::FPFastMathMode::None);
3084 SPIRV::FPFastMathMode::None);
3086 SPIRV::FPFastMathMode::None);
3087 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3093 size_t BitWidth = Ty->getScalarSizeInBits();
3097 assert(Index >= 0 && Index < 3 &&
3098 "Expected FPFastMathDefaultInfo for half, float, or double");
3099 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3100 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3101 return FPFastMathDefaultInfoVec[Index];
3104void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3106 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3115 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3117 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3125 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3128 [[maybe_unused]] GlobalVariable *GV =
3129 new GlobalVariable(M,
3130 Type::getInt32Ty(
M.getContext()),
3144 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3145 FPFastMathDefaultInfoMap;
3147 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3156 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3158 "Expected 4 operands for FPFastMathDefault");
3164 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3166 SPIRV::FPFastMathDefaultInfo &
Info =
3169 Info.FPFastMathDefault =
true;
3170 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3172 "Expected no operands for ContractionOff");
3176 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3178 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3179 Info.ContractionOff =
true;
3181 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3183 "Expected 1 operand for SignedZeroInfNanPreserve");
3184 unsigned TargetWidth =
3189 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3193 assert(Index >= 0 && Index < 3 &&
3194 "Expected FPFastMathDefaultInfo for half, float, or double");
3195 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3196 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3197 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3201 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3202 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3203 if (FPFastMathDefaultInfoVec.
empty())
3206 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3207 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3210 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3211 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3215 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3217 "and AllowContract");
3219 if (
Info.SignedZeroInfNanPreserve &&
3221 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3222 SPIRV::FPFastMathMode::NSZ))) {
3223 if (
Info.FPFastMathDefault)
3225 "SignedZeroInfNanPreserve but at least one of "
3226 "NotNaN/NotInf/NSZ is enabled.");
3229 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3230 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3231 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3233 "AllowTransform requires AllowReassoc and "
3234 "AllowContract to be set.");
3237 auto it = GlobalVars.
find(Flags);
3238 GlobalVariable *GV =
nullptr;
3239 if (it != GlobalVars.
end()) {
3245 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3248 GV =
new GlobalVariable(M,
3249 Type::getInt32Ty(
M.getContext()),
3254 GlobalVars[
Flags] = GV;
3260void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3263 bool IsConstComposite =
3264 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3265 if (IsConstComposite && TrackConstants) {
3267 auto t = AggrConsts.
find(
I);
3271 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3273 NewOp->setArgOperand(0,
I);
3276 for (
const auto &
Op :
I->operands()) {
3280 unsigned OpNo =
Op.getOperandNo();
3281 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3282 (!
II->isBundleOperand(OpNo) &&
3283 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3287 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3288 :
B.SetInsertPoint(
I);
3291 Type *OpTy =
Op->getType();
3299 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3301 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3302 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3304 SmallVector<Value *, 2>
Args = {
3308 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3314 I->setOperand(OpNo, NewOp);
3320Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3322 SmallPtrSet<Function *, 0> FVisited;
3323 return deduceFunParamElementType(
F, OpIdx, FVisited);
3326Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3327 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3329 if (!FVisited.
insert(
F).second)
3332 SmallPtrSet<Value *, 0> Visited;
3335 for (User *U :
F->users()) {
3337 if (!CI || OpIdx >= CI->
arg_size())
3347 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3350 for (User *OpU : OpArg->
users()) {
3352 if (!Inst || Inst == CI)
3355 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3362 if (FVisited.
find(OuterF) != FVisited.
end())
3364 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3365 if (OuterF->
getArg(i) == OpArg) {
3366 Lookup.push_back(std::make_pair(OuterF, i));
3373 for (
auto &Pair :
Lookup) {
3374 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3381void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3383 B.SetInsertPointPastAllocas(
F);
3384 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3390 for (User *U : Arg->
users()) {
3392 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3410 for (User *U :
F->users()) {
3412 if (!CI || OpIdx >= CI->
arg_size())
3426 for (User *U : Arg->
users()) {
3430 CI->
getParent()->getParent() == CurrF) {
3432 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3444 B.SetInsertPointPastAllocas(
F);
3445 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3450 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3452 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3456 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3468 bool IsNewFTy =
false;
3484bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3487 if (
F.isIntrinsic())
3489 if (
F.isDeclaration()) {
3490 for (User *U :
F.users()) {
3503 for (User *U :
F.users()) {
3505 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3507 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3508 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3516 if (Worklist.
empty())
3519 LLVMContext &Ctx =
M.getContext();
3526 for (
const auto &Arg :
F->args())
3529 IRB.CreateCall(
F, Args);
3531 IRB.CreateRetVoid();
3537void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3538 DenseMap<Function *, CallInst *> Ptrcasts;
3539 for (
auto It : FDeclPtrTys) {
3541 for (
auto *U :
F->users()) {
3546 for (
auto [Idx, ElemTy] : It.second) {
3554 B.SetInsertPointPastAllocas(Arg->
getParent());
3558 }
else if (isaGEP(Param)) {
3559 replaceUsesOfWithSpvPtrcast(
3560 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3569 .getFirstNonPHIOrDbgOrAlloca());
3589GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3590 GetElementPtrInst *
GEP) {
3597 Type *SrcTy =
GEP->getSourceElementType();
3598 SmallVector<Value *, 8> Indices(
GEP->indices());
3600 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3601 Indices.erase(Indices.begin());
3602 SrcTy = ArrTy->getElementType();
3604 GEP->getNoWrapFlags(),
"",
3605 GEP->getIterator());
3610void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3617 if (
ST->canUseExtension(
3618 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3619 for (BasicBlock &BB :
F) {
3621 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3625 SmallVector<unsigned, 1>
Ops =
3627 unsigned LC =
Ops[0];
3628 if (LC == SPIRV::LoopControl::None)
3632 B.SetInsertPoint(Term);
3633 SmallVector<Value *, 4> IntrArgs;
3634 for (
unsigned Op :
Ops)
3636 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3657 SmallVector<unsigned, 1> LoopControlOps =
3659 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3663 B.SetInsertPoint(Header->getTerminator());
3666 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3667 for (
unsigned Imm : LoopControlOps)
3668 Args.emplace_back(
B.getInt32(
Imm));
3669 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3673bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3674 if (
Func.isDeclaration())
3678 GR =
ST.getSPIRVGlobalRegistry();
3682 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3684 CanUseAnyVectorRank =
3685 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3689 AggrConstTypes.
clear();
3692 processParamTypesByFunHeader(CurrF,
B);
3696 SmallPtrSet<Instruction *, 4> DeadInsts;
3699 Type *ElTy =
SI->getValueOperand()->getType();
3708 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3712 GR->addDeducedElementType(
3714 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3718 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3720 GEP->replaceAllUsesWith(NewGEP);
3724 if (
Type *GepTy = getGEPType(
GEP))
3728 for (
auto *
I : DeadInsts) {
3729 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3730 I->eraseFromParent();
3733 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3734 for (
auto &GV :
Func.getParent()->globals())
3735 processGlobalValue(GV,
B);
3737 reconstructAggregateReturns(Func,
B);
3738 preprocessUndefsAndPoisons(
B);
3739 simplifyNullAddrSpaceCasts();
3740 preprocessCompositeConstants(
B);
3748 Type *I32Ty =
B.getInt32Ty();
3753 insertCompositeAggregateArms(&
I,
B);
3754 AggrConstTypes[&
I] =
I.getType();
3755 I.mutateType(I32Ty);
3758 preprocessBoolVectorBitcasts(Func);
3759 SmallVector<Instruction *> Worklist(
3762 applyDemangledPtrArgTypes(
B);
3765 for (
auto &
I : Worklist) {
3767 if (isConvergenceIntrinsic(
I))
3770 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3772 insertAssignTypeIntrs(
I,
B);
3773 insertPtrCastOrAssignTypeInstr(
I,
B);
3777 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3778 insertAssignPtrTypeIntrs(
I,
B,
true);
3781 useRoundingMode(FPI,
B);
3786 SmallPtrSet<Instruction *, 4> IncompleteRets;
3788 deduceOperandElementType(&
I, &IncompleteRets);
3792 for (BasicBlock &BB : Func)
3793 for (PHINode &Phi : BB.
phis())
3795 deduceOperandElementType(&Phi,
nullptr);
3797 for (
auto *
I : Worklist) {
3798 TrackConstants =
true;
3808 if (isConvergenceIntrinsic(
I))
3812 processInstrAfterVisit(
I,
B);
3815 emitUnstructuredLoopControls(Func,
B);
3821bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3822 if (!GR || TodoTypeSz == 0)
3825 unsigned SzTodo = TodoTypeSz;
3826 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3831 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3832 Type *KnownTy = GR->findDeducedElementType(
Op);
3833 if (!KnownTy || !AssignCI)
3839 SmallPtrSet<Value *, 0> Visited;
3840 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3841 if (ElemTy != KnownTy) {
3842 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3843 propagateElemType(CI, ElemTy, VisitedSubst);
3850 if (
Op->hasUseList()) {
3851 for (User *U :
Op->users()) {
3858 if (TodoTypeSz == 0)
3863 SmallPtrSet<Instruction *, 4> IncompleteRets;
3865 auto It = ToProcess.
find(&
I);
3866 if (It == ToProcess.
end())
3868 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3869 if (It->second.size() == 0)
3871 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3872 if (TodoTypeSz == 0)
3877 return SzTodo > TodoTypeSz;
3881void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
3883 if (!
F.isDeclaration() ||
F.isIntrinsic())
3887 if (DemangledName.empty())
3891 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3892 DemangledName,
ST.getPreferredInstructionSet());
3893 if (Opcode != SPIRV::OpGroupAsyncCopy)
3896 SmallVector<unsigned> Idxs;
3897 for (
unsigned OpIdx = 0; OpIdx <
F.arg_size(); ++OpIdx) {
3905 LLVMContext &Ctx =
F.getContext();
3907 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3908 if (!TypeStrs.
size())
3911 for (
unsigned Idx : Idxs) {
3912 if (Idx >= TypeStrs.
size())
3915 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3918 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3923bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3924 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3926 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3927 if (!
ST.canUseExtension(
3928 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3929 I.getContext().emitError(
3930 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3934 I.eraseFromParent();
3940 Value *Ptrs =
I.getArgOperand(0);
3942 Value *Passthru =
I.getArgOperand(2);
3945 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
3947 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3952 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3954 I.eraseFromParent();
3958 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3959 if (!
ST.canUseExtension(
3960 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3961 I.getContext().emitError(
3962 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3965 I.eraseFromParent();
3972 Value *Ptrs =
I.getArgOperand(1);
3977 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
3979 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
3983 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3984 I.eraseFromParent();
3995void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
3996 struct BoolVecBitcast {
3998 FixedVectorType *BoolVecTy;
4002 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4004 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4012 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4014 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4018 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4020 Value *Src = BC->getOperand(0);
4021 unsigned BoolVecN = BoolVecTy->getNumElements();
4023 Type *IntTy =
B.getIntNTy(BoolVecN);
4029 IntVal = ConstantInt::get(IntTy, 0);
4030 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4031 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
4032 Value *Ext =
B.CreateZExt(Elem, IntTy);
4034 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
4035 IntVal =
B.CreateOr(IntVal, Ext);
4041 if (!Src->getType()->isIntegerTy())
4042 IntVal =
B.CreateBitCast(Src, IntTy);
4047 if (!SrcIsBoolVec) {
4050 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4053 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
4054 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4060 if (!BC->getDestTy()->isIntegerTy())
4061 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4064 BC->replaceAllUsesWith(Result);
4065 BC->eraseFromParent();
4069bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4073 if (!
F.isIntrinsic())
4076 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4081 Changed |= processMaskedMemIntrinsic(*
II);
4085 F.eraseFromParent();
4091bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4094 Changed |= convertMaskedMemIntrinsics(M);
4096 parseFunDeclarations(M);
4097 insertConstantsForFPFastMathDefault(M);
4108 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4110 processParamTypes(&
F,
B);
4114 CanTodoType =
false;
4115 Changed |= postprocessTypes(M);
4118 Changed |= processFunctionPointers(M);
4125 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4131 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 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
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 > 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()
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.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
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.
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.
@ 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.
@ 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.
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.
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::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.
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.
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)
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)