24#include "llvm/IR/IntrinsicsSPIRV.h"
32#include <unordered_set>
56 cl::desc(
"Emit OpName for all instructions"),
60#define GET_BuiltinGroup_DECL
61#include "SPIRVGenTables.inc"
66class GlobalVariableUsers {
67 template <
typename T1,
typename T2>
68 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
70 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
72 void collectGlobalUsers(
73 const GlobalVariable *GV,
74 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
75 &GlobalIsUsedByGlobal) {
77 while (!
Stack.empty()) {
81 GlobalIsUsedByFun[GV].insert(
I->getFunction());
86 GlobalIsUsedByGlobal[GV].insert(UserGV);
91 Stack.append(
C->user_begin(),
C->user_end());
95 bool propagateGlobalToGlobalUsers(
96 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
97 &GlobalIsUsedByGlobal) {
100 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
101 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
102 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
103 auto It = GlobalIsUsedByGlobal.find(UserGV);
104 if (It == GlobalIsUsedByGlobal.end())
112 void propagateGlobalToFunctionReferences(
113 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
114 &GlobalIsUsedByGlobal) {
115 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
116 auto &UserFunctions = GlobalIsUsedByFun[GV];
117 for (
const GlobalVariable *UserGV : UserGlobals) {
118 auto It = GlobalIsUsedByFun.find(UserGV);
119 if (It == GlobalIsUsedByFun.end())
130 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
131 GlobalIsUsedByGlobal;
132 GlobalIsUsedByFun.clear();
133 for (GlobalVariable &GV :
M.globals())
134 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
137 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
140 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
143 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
144 const FunctionSetType &
145 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
146 auto It = GlobalIsUsedByFun.find(&GV);
147 if (It != GlobalIsUsedByFun.end())
150 static const FunctionSetType
Empty{};
155static bool isaGEP(
const Value *V) {
159class SPIRVEmitIntrinsics
161 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
162 SPIRVTargetMachine *TM =
nullptr;
163 SPIRVGlobalRegistry *GR =
nullptr;
165 bool TrackConstants =
true;
166 bool HaveFunPtrs =
false;
167 DenseMap<Instruction *, Constant *> AggrConsts;
168 DenseMap<Instruction *, Type *> AggrConstTypes;
169 DenseSet<Instruction *> AggrStores;
170 GlobalVariableUsers GVUsers;
171 std::unordered_set<Value *> Named;
174 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
177 bool CanTodoType =
true;
178 unsigned TodoTypeSz = 0;
179 DenseMap<Value *, bool> TodoType;
180 void insertTodoType(
Value *
Op) {
182 if (CanTodoType && !isaGEP(
Op)) {
183 auto It = TodoType.try_emplace(
Op,
true);
188 void eraseTodoType(
Value *
Op) {
189 auto It = TodoType.find(
Op);
190 if (It != TodoType.end() && It->second) {
198 auto It = TodoType.find(
Op);
199 return It != TodoType.end() && It->second;
203 std::unordered_set<Instruction *> TypeValidated;
206 enum WellKnownTypes { Event };
209 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
210 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
211 Type *deduceElementTypeHelper(
Value *
I, std::unordered_set<Value *> &Visited,
212 bool UnknownElemTypeI8,
213 bool IgnoreKnownType =
false);
214 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
215 bool UnknownElemTypeI8);
216 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
217 std::unordered_set<Value *> &Visited,
218 bool UnknownElemTypeI8);
220 std::unordered_set<Value *> &Visited,
221 bool UnknownElemTypeI8);
223 bool UnknownElemTypeI8);
226 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
227 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
228 std::unordered_set<Value *> &Visited,
229 bool UnknownElemTypeI8);
232 void deduceOperandElementType(Instruction *
I,
233 SmallPtrSet<Instruction *, 4> *IncompleteRets,
234 const SmallPtrSet<Value *, 4> *AskOps =
nullptr,
235 bool IsPostprocessing =
false);
240 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
241 bool IsPostprocessing);
243 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
245 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
246 bool UnknownElemTypeI8);
248 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
250 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
251 Type *ExpectedElementType,
252 unsigned OperandToReplace,
254 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
255 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
257 void insertConstantsForFPFastMathDefault(
Module &M);
259 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
261 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
262 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
263 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx,
264 std::unordered_set<Function *> &FVisited);
266 bool deduceOperandElementTypeCalledFunction(
268 Type *&KnownElemTy,
bool &Incomplete);
269 void deduceOperandElementTypeFunctionPointer(
271 Type *&KnownElemTy,
bool IsPostprocessing);
272 bool deduceOperandElementTypeFunctionRet(
273 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
274 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
277 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
278 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
279 DenseMap<Function *, CallInst *> Ptrcasts);
281 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
284 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
285 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
286 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
287 std::unordered_set<Value *> &Visited,
288 DenseMap<Function *, CallInst *> Ptrcasts);
291 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
292 Instruction *Dest,
bool DeleteOld =
true);
296 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
299 bool postprocessTypes(
Module &M);
300 bool processFunctionPointers(
Module &M);
301 void parseFunDeclarations(
Module &M);
302 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
303 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
304 bool convertMaskedMemIntrinsics(
Module &M);
306 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
322 bool walkLogicalAccessChain(
323 GetElementPtrInst &
GEP,
324 const std::function<
void(
Type *PointedType, uint64_t Index)>
333 Type *getGEPType(GetElementPtrInst *
GEP);
340 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
342 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
346 SPIRVEmitIntrinsics(SPIRVTargetMachine *TM =
nullptr)
347 : ModulePass(ID), TM(TM) {}
350 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
353 Instruction *visitInsertElementInst(InsertElementInst &
I);
354 Instruction *visitExtractElementInst(ExtractElementInst &
I);
356 Instruction *visitExtractValueInst(ExtractValueInst &
I);
360 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
364 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
366 bool runOnModule(
Module &M)
override;
368 void getAnalysisUsage(AnalysisUsage &AU)
const override {
369 ModulePass::getAnalysisUsage(AU);
378 return II->getIntrinsicID() == Intrinsic::experimental_convergence_entry ||
379 II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||
380 II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor;
383bool expectIgnoredInIRTranslation(
const Instruction *
I) {
387 switch (
II->getIntrinsicID()) {
388 case Intrinsic::invariant_start:
389 case Intrinsic::spv_resource_handlefrombinding:
390 case Intrinsic::spv_resource_getpointer:
400 if (
II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
401 Value *V =
II->getArgOperand(0);
402 return getPointerRoot(V);
410char SPIRVEmitIntrinsics::ID = 0;
428 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
435 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
441 B.SetCurrentDebugLocation(
I->getDebugLoc());
442 if (
I->getType()->isVoidTy())
443 B.SetInsertPoint(
I->getNextNode());
445 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
450 switch (Intr->getIntrinsicID()) {
451 case Intrinsic::invariant_start:
452 case Intrinsic::invariant_end:
460 if (
I->getType()->isTokenTy())
462 "does not support token type",
467 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
468 expectIgnoredInIRTranslation(
I))
479 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
490 std::vector<Value *> Args = {
493 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
496void SPIRVEmitIntrinsics::replaceAllUsesWith(
Value *Src,
Value *Dest,
500 if (isTodoType(Src)) {
503 insertTodoType(Dest);
507void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
512 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
513 Src->eraseFromParent();
516 if (Named.insert(Dest).second)
541Type *SPIRVEmitIntrinsics::reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
542 bool IsPostprocessing) {
557 if (UnknownElemTypeI8) {
558 if (!IsPostprocessing)
566CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *
F,
Value *
Op,
574 B.SetInsertPointPastAllocas(OpA->getParent());
577 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
579 Type *OpTy =
Op->getType();
583 CallInst *PtrCasted =
584 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
589void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
591 DenseMap<Function *, CallInst *> Ptrcasts) {
593 CallInst *PtrCastedI =
nullptr;
594 auto It = Ptrcasts.
find(
F);
595 if (It == Ptrcasts.
end()) {
596 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
597 Ptrcasts[
F] = PtrCastedI;
599 PtrCastedI = It->second;
601 I->replaceUsesOfWith(
Op, PtrCastedI);
604void SPIRVEmitIntrinsics::propagateElemType(
606 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
607 DenseMap<Function *, CallInst *> Ptrcasts;
609 for (
auto *U :
Users) {
612 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
617 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
618 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
622void SPIRVEmitIntrinsics::propagateElemTypeRec(
624 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
625 std::unordered_set<Value *> Visited;
626 DenseMap<Function *, CallInst *> Ptrcasts;
627 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
628 std::move(Ptrcasts));
631void SPIRVEmitIntrinsics::propagateElemTypeRec(
633 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
634 std::unordered_set<Value *> &Visited,
635 DenseMap<Function *, CallInst *> Ptrcasts) {
636 if (!Visited.insert(
Op).second)
639 for (
auto *U :
Users) {
642 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
647 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
648 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
656SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
657 bool UnknownElemTypeI8) {
658 std::unordered_set<Value *> Visited;
659 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
663Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
664 Type *ValueTy,
Value *Operand, std::unordered_set<Value *> &Visited,
665 bool UnknownElemTypeI8) {
670 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
681Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
682 Value *
Op, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8) {
694 for (User *OpU :
Op->users()) {
696 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
709 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
718Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I,
719 bool UnknownElemTypeI8) {
720 std::unordered_set<Value *> Visited;
721 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
724void SPIRVEmitIntrinsics::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
Type *RefTy,
725 bool UnknownElemTypeI8) {
727 if (!UnknownElemTypeI8)
734bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
735 GetElementPtrInst &
GEP,
736 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
737 const std::function<
void(
Type *,
Value *)> &OnDynamicIndexing) {
745 Value *Src = getPointerRoot(
GEP.getPointerOperand());
746 Type *CurType = deduceElementType(Src,
true);
755 OnDynamicIndexing(AT->getElementType(), Operand);
756 return AT ==
nullptr;
764 uint32_t EltTypeSize =
DL.getTypeSizeInBits(AT->getElementType()) / 8;
768 CurType = AT->getElementType();
769 OnLiteralIndexing(CurType, Index);
771 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
774 const auto &STL =
DL.getStructLayout(ST);
775 unsigned Element = STL->getElementContainingOffset(
Offset);
776 Offset -= STL->getElementOffset(Element);
777 CurType =
ST->getElementType(Element);
778 OnLiteralIndexing(CurType, Element);
780 Type *EltTy = VT->getElementType();
781 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
782 assert(EltSizeBits % 8 == 0 &&
783 "Element type size in bits must be a multiple of 8.");
784 uint32_t EltTypeSize = EltSizeBits / 8;
789 OnLiteralIndexing(CurType, Index);
801SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP) {
804 B.SetInsertPoint(&
GEP);
806 std::vector<Value *> Indices;
807 Indices.push_back(ConstantInt::get(
808 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
809 walkLogicalAccessChain(
811 [&Indices, &
B](
Type *EltType, uint64_t Index) {
813 ConstantInt::get(
B.getInt64Ty(), Index,
false));
816 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
818 Offset, ConstantInt::get(
Offset->getType(), EltTypeSize,
820 Indices.push_back(Index);
824 SmallVector<Value *, 4>
Args;
825 Args.push_back(
B.getInt1(
GEP.isInBounds()));
826 Args.push_back(
GEP.getOperand(0));
828 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
829 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
833Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *
GEP) {
835 Type *CurType =
GEP->getResultElementType();
837 bool Interrupted = walkLogicalAccessChain(
838 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
841 return Interrupted ?
GEP->getResultElementType() : CurType;
844Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *
Ref) {
845 if (
Ref->getSourceElementType() ==
846 IntegerType::getInt8Ty(CurrF->
getContext()) &&
848 return getGEPTypeLogical(
Ref);
855 Ty =
Ref->getSourceElementType();
859 Ty =
Ref->getResultElementType();
864Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
865 Value *
I, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8,
866 bool IgnoreKnownType) {
872 if (!IgnoreKnownType)
877 if (!Visited.insert(
I).second)
884 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
886 Ty = getGEPType(
Ref);
888 Ty = SGEP->getResultElementType();
893 KnownTy =
Op->getType();
895 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
898 Ty = SPIRV::getOriginalFunctionType(*Fn);
901 Ty = deduceElementTypeByValueDeep(
903 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
907 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
909 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
911 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
913 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
915 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
920 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
924 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
926 Type *BestTy =
nullptr;
928 DenseMap<Type *, unsigned> PhiTys;
929 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
930 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
937 if (It.first->second > MaxN) {
938 MaxN = It.first->second;
946 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
947 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
952 static StringMap<unsigned> ResTypeByArg = {
956 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
957 {
"__spirv_GenericCastToPtr_ToLocal", 0},
958 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
959 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
960 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
961 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
965 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
967 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
968 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
969 for (User *U :
II->users()) {
974 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
976 Ty = HandleType->getTypeParameter(0);
988 }
else if (
II &&
II->getIntrinsicID() ==
989 Intrinsic::spv_generic_cast_to_ptr_explicit) {
990 Ty = deduceElementTypeHelper(CI->getArgOperand(0), Visited,
992 }
else if (Function *CalledF = CI->getCalledFunction()) {
993 std::string DemangledName =
995 if (DemangledName.length() > 0)
996 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
997 auto AsArgIt = ResTypeByArg.
find(DemangledName);
998 if (AsArgIt != ResTypeByArg.
end())
999 Ty = deduceElementTypeHelper(CI->getArgOperand(AsArgIt->second),
1000 Visited, UnknownElemTypeI8);
1007 if (Ty && !IgnoreKnownType) {
1018Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1019 bool UnknownElemTypeI8) {
1020 std::unordered_set<Value *> Visited;
1021 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1024Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
1025 User *U,
Type *OrigTy, std::unordered_set<Value *> &Visited,
1026 bool UnknownElemTypeI8) {
1035 if (!Visited.insert(U).second)
1040 bool Change =
false;
1041 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1043 assert(
Op &&
"Operands should not be null.");
1044 Type *OpTy =
Op->getType();
1047 if (
Type *NestedTy =
1048 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1055 Change |= Ty != OpTy;
1063 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1064 Type *OpTy = ArrTy->getElementType();
1067 if (
Type *NestedTy =
1068 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1075 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1081 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1082 Type *OpTy = VecTy->getElementType();
1085 if (
Type *NestedTy =
1086 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1093 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1103Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I,
bool UnknownElemTypeI8) {
1104 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1106 if (!UnknownElemTypeI8)
1109 return IntegerType::getInt8Ty(
I->getContext());
1113 Value *PointerOperand) {
1119 return I->getType();
1127bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1129 Type *&KnownElemTy,
bool &Incomplete) {
1133 std::string DemangledName =
1135 if (DemangledName.length() > 0 &&
1137 const SPIRVSubtarget &
ST = TM->
getSubtarget<SPIRVSubtarget>(*CalledF);
1138 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1139 DemangledName,
ST.getPreferredInstructionSet());
1140 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1141 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1147 KnownElemTy = ElemTy;
1148 Ops.push_back(std::make_pair(
Op, i));
1150 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1157 case SPIRV::OpAtomicFAddEXT:
1158 case SPIRV::OpAtomicFMinEXT:
1159 case SPIRV::OpAtomicFMaxEXT:
1160 case SPIRV::OpAtomicLoad:
1161 case SPIRV::OpAtomicCompareExchangeWeak:
1162 case SPIRV::OpAtomicCompareExchange:
1163 case SPIRV::OpAtomicExchange:
1164 case SPIRV::OpAtomicIAdd:
1165 case SPIRV::OpAtomicISub:
1166 case SPIRV::OpAtomicOr:
1167 case SPIRV::OpAtomicXor:
1168 case SPIRV::OpAtomicAnd:
1169 case SPIRV::OpAtomicUMin:
1170 case SPIRV::OpAtomicUMax:
1171 case SPIRV::OpAtomicSMin:
1172 case SPIRV::OpAtomicSMax: {
1177 Incomplete = isTodoType(
Op);
1178 Ops.push_back(std::make_pair(
Op, 0));
1180 case SPIRV::OpAtomicStore: {
1189 Incomplete = isTodoType(
Op);
1190 Ops.push_back(std::make_pair(
Op, 0));
1199void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1201 Type *&KnownElemTy,
bool IsPostprocessing) {
1205 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1206 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1207 bool IsNewFTy =
false, IsIncomplete =
false;
1210 Type *ArgTy = Arg->getType();
1215 if (isTodoType(Arg))
1216 IsIncomplete =
true;
1218 IsIncomplete =
true;
1221 ArgTy = FTy->getFunctionParamType(ParmIdx);
1225 Type *RetTy = FTy->getReturnType();
1232 IsIncomplete =
true;
1234 IsIncomplete =
true;
1237 if (!IsPostprocessing && IsIncomplete)
1240 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1243bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1244 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1245 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
1257 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1258 for (User *U :
F->users()) {
1266 propagateElemType(CI, PrevElemTy, VisitedSubst);
1276 for (Instruction *IncompleteRetI : *IncompleteRets)
1277 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1279 }
else if (IncompleteRets) {
1282 TypeValidated.insert(
I);
1290void SPIRVEmitIntrinsics::deduceOperandElementType(
1291 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1292 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing) {
1294 Type *KnownElemTy =
nullptr;
1295 bool Incomplete =
false;
1301 Incomplete = isTodoType(
I);
1302 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1305 Ops.push_back(std::make_pair(
Op, i));
1311 Incomplete = isTodoType(
I);
1312 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1319 Incomplete = isTodoType(
I);
1320 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1324 KnownElemTy =
Ref->getSourceElementType();
1325 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1330 KnownElemTy =
Ref->getBaseType();
1331 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1334 KnownElemTy =
I->getType();
1340 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1344 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1349 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1357 Incomplete = isTodoType(
Ref->getPointerOperand());
1358 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1366 Incomplete = isTodoType(
Ref->getPointerOperand());
1367 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1373 Incomplete = isTodoType(
I);
1374 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1377 Ops.push_back(std::make_pair(
Op, i));
1385 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1386 IsPostprocessing, KnownElemTy,
Op,
1389 Incomplete = isTodoType(CurrF);
1390 Ops.push_back(std::make_pair(
Op, 0));
1396 bool Incomplete0 = isTodoType(Op0);
1397 bool Incomplete1 = isTodoType(Op1);
1399 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1401 : GR->findDeducedElementType(Op0);
1403 KnownElemTy = ElemTy0;
1404 Incomplete = Incomplete0;
1405 Ops.push_back(std::make_pair(Op1, 1));
1406 }
else if (ElemTy1) {
1407 KnownElemTy = ElemTy1;
1408 Incomplete = Incomplete1;
1409 Ops.push_back(std::make_pair(Op0, 0));
1413 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1414 else if (HaveFunPtrs)
1415 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1420 if (!KnownElemTy ||
Ops.size() == 0)
1425 for (
auto &OpIt :
Ops) {
1429 Type *AskTy =
nullptr;
1430 CallInst *AskCI =
nullptr;
1431 if (IsPostprocessing && AskOps) {
1437 if (Ty == KnownElemTy)
1440 Type *OpTy =
Op->getType();
1441 if (
Op->hasUseList() &&
1448 else if (!IsPostprocessing)
1452 if (AssignCI ==
nullptr) {
1461 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1462 std::make_pair(
I,
Op)};
1463 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1467 CallInst *PtrCastI =
1468 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1469 if (OpIt.second == std::numeric_limits<unsigned>::max())
1472 I->setOperand(OpIt.second, PtrCastI);
1475 TypeValidated.insert(
I);
1478void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1483 if (isAssignTypeInstr(U)) {
1484 B.SetInsertPoint(U);
1485 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1486 CallInst *AssignCI =
1487 B.CreateIntrinsic(Intrinsic::spv_assign_type, {
New->getType()},
Args);
1489 U->eraseFromParent();
1492 U->replaceUsesOfWith(Old, New);
1497 New->copyMetadata(*Old);
1501void SPIRVEmitIntrinsics::preprocessUndefs(
IRBuilder<> &
B) {
1502 std::queue<Instruction *> Worklist;
1506 while (!Worklist.empty()) {
1508 bool BPrepared =
false;
1511 for (
auto &
Op :
I->operands()) {
1513 if (!AggrUndef || !
Op->getType()->isAggregateType())
1520 auto *IntrUndef =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
1521 Worklist.push(IntrUndef);
1522 I->replaceUsesOfWith(
Op, IntrUndef);
1523 AggrConsts[IntrUndef] = AggrUndef;
1524 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1529void SPIRVEmitIntrinsics::preprocessCompositeConstants(
IRBuilder<> &
B) {
1530 std::queue<Instruction *> Worklist;
1534 while (!Worklist.empty()) {
1535 auto *
I = Worklist.front();
1538 bool KeepInst =
false;
1539 for (
const auto &
Op :
I->operands()) {
1541 Type *ResTy =
nullptr;
1544 ResTy = COp->getType();
1556 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1561 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1562 Args.push_back(COp->getElementAsConstant(i));
1566 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1567 :
B.SetInsertPoint(
I);
1571 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {
Args});
1575 AggrConsts[CI] = AggrConst;
1576 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1588 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1593 unsigned RoundingModeDeco,
1600 ConstantInt::get(
Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1609 MDNode *SaturatedConversionNode =
1611 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1618 if (Fu->isIntrinsic()) {
1619 unsigned const int IntrinsicId = Fu->getIntrinsicID();
1620 switch (IntrinsicId) {
1621 case Intrinsic::fptosi_sat:
1622 case Intrinsic::fptoui_sat:
1641 MDString *ConstraintString =
MDString::get(Ctx,
IA->getConstraintString());
1649 B.SetInsertPoint(&
Call);
1650 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1655void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1658 if (!
RM.has_value())
1660 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1661 switch (
RM.value()) {
1665 case RoundingMode::NearestTiesToEven:
1666 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1668 case RoundingMode::TowardNegative:
1669 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1671 case RoundingMode::TowardPositive:
1672 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1674 case RoundingMode::TowardZero:
1675 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1677 case RoundingMode::Dynamic:
1678 case RoundingMode::NearestTiesToAway:
1682 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1688Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &
I) {
1692 B.SetInsertPoint(&
I);
1693 SmallVector<Value *, 4>
Args;
1695 Args.push_back(
I.getCondition());
1698 for (
auto &Case :
I.cases()) {
1699 Args.push_back(Case.getCaseValue());
1700 BBCases.
push_back(Case.getCaseSuccessor());
1703 CallInst *NewI =
B.CreateIntrinsic(Intrinsic::spv_switch,
1704 {
I.getOperand(0)->getType()}, {
Args});
1708 I.eraseFromParent();
1711 B.SetInsertPoint(ParentBB);
1712 IndirectBrInst *BrI =
B.CreateIndirectBr(
1715 for (BasicBlock *BBCase : BBCases)
1721 if (
GEP->getNumIndices() == 0)
1724 return CI->getZExtValue() == 0;
1729Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &
I) {
1735 B.SetInsertPoint(&
I);
1737 SmallVector<Value *, 4>
Args;
1738 Args.push_back(
B.getInt1(
true));
1739 Args.push_back(
I.getOperand(0));
1740 Args.push_back(
B.getInt32(0));
1741 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1742 Args.push_back(SGEP->getIndexOperand(J));
1744 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, Types, Args);
1745 replaceAllUsesWithAndErase(
B, &
I, NewI);
1749Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &
I) {
1751 B.SetInsertPoint(&
I);
1759 if (
I.getSourceElementType() ==
1760 IntegerType::getInt8Ty(CurrF->
getContext())) {
1761 return buildLogicalAccessChainFromGEP(
I);
1766 Value *PtrOp =
I.getPointerOperand();
1767 Type *SrcElemTy =
I.getSourceElementType();
1768 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
1771 if (ArrTy->getElementType() == SrcElemTy) {
1773 Type *FirstIdxType =
I.getOperand(1)->getType();
1774 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
1775 for (
Value *Idx :
I.indices())
1779 SmallVector<Value *, 4>
Args;
1780 Args.push_back(
B.getInt1(
I.isInBounds()));
1781 Args.push_back(
I.getPointerOperand());
1784 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
1785 replaceAllUsesWithAndErase(
B, &
I, NewI);
1792 SmallVector<Value *, 4>
Args;
1793 Args.push_back(
B.getInt1(
I.isInBounds()));
1795 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
1796 replaceAllUsesWithAndErase(
B, &
I, NewI);
1800Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &
I) {
1802 B.SetInsertPoint(&
I);
1811 I.eraseFromParent();
1817 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_bitcast, {
Types}, {
Args});
1818 replaceAllUsesWithAndErase(
B, &
I, NewI);
1822void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
1824 Type *VTy =
V->getType();
1829 if (ElemTy != AssignedType)
1842 if (CurrentType == AssignedType)
1849 " for value " +
V->getName(),
1857void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
1858 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
1860 TypeValidated.insert(
I);
1863 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
1864 if (PointerElemTy == ExpectedElementType ||
1870 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
1872 bool FirstPtrCastOrAssignPtrType =
true;
1878 for (
auto User :
Pointer->users()) {
1881 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
1882 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
1883 II->getOperand(0) != Pointer)
1888 FirstPtrCastOrAssignPtrType =
false;
1889 if (
II->getOperand(1) != VMD ||
1896 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
1901 if (
II->getParent() !=
I->getParent())
1904 I->setOperand(OperandToReplace,
II);
1910 if (FirstPtrCastOrAssignPtrType) {
1915 }
else if (isTodoType(Pointer)) {
1916 eraseTodoType(Pointer);
1924 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1925 std::make_pair(
I, Pointer)};
1927 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
1939 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
1945void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *
I,
1950 replacePointerOperandWithPtrCast(
1951 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
1957 Type *OpTy =
Op->getType();
1960 if (OpTy ==
Op->getType())
1961 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
1962 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
1967 Type *OpTy = LI->getType();
1972 Type *NewOpTy = OpTy;
1973 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
1974 if (OpTy == NewOpTy)
1975 insertTodoType(Pointer);
1978 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
1983 Type *OpTy =
nullptr;
1995 OpTy = GEPI->getSourceElementType();
1997 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
1999 insertTodoType(Pointer);
2011 std::string DemangledName =
2015 bool HaveTypes =
false;
2033 for (User *U : CalledArg->
users()) {
2035 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2041 HaveTypes |= ElemTy !=
nullptr;
2046 if (DemangledName.empty() && !HaveTypes)
2064 Type *ExpectedType =
2066 if (!ExpectedType && !DemangledName.empty())
2067 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2068 DemangledName,
OpIdx,
I->getContext());
2069 if (!ExpectedType || ExpectedType->
isVoidTy())
2077 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2081Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &
I) {
2088 I.getOperand(1)->getType(),
2089 I.getOperand(2)->getType()};
2091 B.SetInsertPoint(&
I);
2093 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
2094 replaceAllUsesWithAndErase(
B, &
I, NewI);
2099SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &
I) {
2106 B.SetInsertPoint(&
I);
2108 I.getIndexOperand()->getType()};
2109 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2110 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
2111 replaceAllUsesWithAndErase(
B, &
I, NewI);
2115Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &
I) {
2117 B.SetInsertPoint(&
I);
2120 Value *AggregateOp =
I.getAggregateOperand();
2124 Args.push_back(AggregateOp);
2125 Args.push_back(
I.getInsertedValueOperand());
2126 for (
auto &
Op :
I.indices())
2127 Args.push_back(
B.getInt32(
Op));
2129 B.CreateIntrinsic(Intrinsic::spv_insertv, {
Types}, {
Args});
2130 replaceMemInstrUses(&
I, NewI,
B);
2134Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &
I) {
2135 if (
I.getAggregateOperand()->getType()->isAggregateType())
2138 B.SetInsertPoint(&
I);
2140 for (
auto &
Op :
I.indices())
2141 Args.push_back(
B.getInt32(
Op));
2143 B.CreateIntrinsic(Intrinsic::spv_extractv, {
I.getType()}, {
Args});
2144 replaceAllUsesWithAndErase(
B, &
I, NewI);
2148Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &
I) {
2149 if (!
I.getType()->isAggregateType())
2152 B.SetInsertPoint(&
I);
2153 TrackConstants =
false;
2158 B.CreateIntrinsic(Intrinsic::spv_load, {
I.getOperand(0)->getType()},
2159 {
I.getPointerOperand(),
B.getInt16(Flags),
2160 B.getInt32(
I.getAlign().value())});
2161 replaceMemInstrUses(&
I, NewI,
B);
2165Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &
I) {
2169 B.SetInsertPoint(&
I);
2170 TrackConstants =
false;
2174 auto *PtrOp =
I.getPointerOperand();
2176 if (
I.getValueOperand()->getType()->isAggregateType()) {
2184 "Unexpected argument of aggregate type, should be spv_extractv!");
2188 auto *NewI =
B.CreateIntrinsic(
2189 Intrinsic::spv_store, {
I.getValueOperand()->getType(), PtrOp->
getType()},
2190 {
I.getValueOperand(), PtrOp,
B.getInt16(Flags),
2191 B.getInt32(
I.getAlign().value())});
2193 I.eraseFromParent();
2197Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &
I) {
2198 Value *ArraySize =
nullptr;
2199 if (
I.isArrayAllocation()) {
2202 SPIRV::Extension::SPV_INTEL_variable_length_array))
2204 "array allocation: this instruction requires the following "
2205 "SPIR-V extension: SPV_INTEL_variable_length_array",
2207 ArraySize =
I.getArraySize();
2210 B.SetInsertPoint(&
I);
2211 TrackConstants =
false;
2212 Type *PtrTy =
I.getType();
2215 ?
B.CreateIntrinsic(Intrinsic::spv_alloca_array,
2216 {PtrTy, ArraySize->
getType()},
2217 {ArraySize,
B.getInt32(
I.getAlign().value())})
2218 :
B.CreateIntrinsic(
Intrinsic::spv_alloca, {PtrTy},
2219 {
B.getInt32(
I.getAlign().value())});
2220 replaceAllUsesWithAndErase(
B, &
I, NewI);
2224Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2225 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2227 B.SetInsertPoint(&
I);
2229 Args.push_back(
B.getInt32(
2230 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2231 Args.push_back(
B.getInt32(
2233 Args.push_back(
B.getInt32(
2235 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
2236 {
I.getPointerOperand()->getType()}, {
Args});
2237 replaceMemInstrUses(&
I, NewI,
B);
2241Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &
I) {
2243 B.SetInsertPoint(&
I);
2244 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2253 static const StringSet<> ArtificialGlobals{
"llvm.global.annotations",
2254 "llvm.compiler.used",
"llvm.used"};
2259 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2260 if (UserFunctions.contains(
F))
2265 if (!UserFunctions.empty())
2270 const Module &M = *
F->getParent();
2271 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2272 return F == &FirstDefinition;
2275Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(
Type *AggrTy,
2277 SmallVector<Value *, 4> Elems;
2279 Type *ElemTy = ArrTy->getElementType();
2280 auto *UI =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
2282 AggrConstTypes[UI] = ElemTy;
2283 Elems.
assign(ArrTy->getNumElements(), UI);
2286 DenseMap<Type *, Instruction *> UndefByType;
2287 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2289 auto &
Entry = UndefByType[ElemTy];
2291 Entry =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
2293 AggrConstTypes[
Entry] = ElemTy;
2298 auto *Composite =
B.CreateIntrinsic(Intrinsic::spv_const_composite,
2299 {
B.getInt32Ty()}, Elems);
2301 AggrConstTypes[Composite] = AggrTy;
2305void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2316 deduceElementTypeHelper(&GV,
false);
2318 Value *InitOp = Init;
2320 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2323 auto *InitInst =
B.CreateIntrinsic(Intrinsic::spv_init_global,
2325 InitInst->setArgOperand(1, InitOp);
2328 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2334bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *
I,
2336 bool UnknownElemTypeI8) {
2342 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2349void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *
I,
2352 static StringMap<unsigned> ResTypeWellKnown = {
2353 {
"async_work_group_copy", WellKnownTypes::Event},
2354 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2355 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2359 bool IsKnown =
false;
2364 std::string DemangledName =
2367 if (DemangledName.length() > 0)
2369 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2370 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2371 if (ResIt != ResTypeWellKnown.
end()) {
2374 switch (ResIt->second) {
2375 case WellKnownTypes::Event:
2382 switch (DecorationId) {
2385 case FPDecorationId::SAT:
2388 case FPDecorationId::RTE:
2390 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2392 case FPDecorationId::RTZ:
2394 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2396 case FPDecorationId::RTP:
2398 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2400 case FPDecorationId::RTN:
2402 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2408 Type *Ty =
I->getType();
2411 Type *TypeToAssign = Ty;
2413 if (
II->getIntrinsicID() == Intrinsic::spv_const_composite ||
2414 II->getIntrinsicID() == Intrinsic::spv_undef) {
2415 auto It = AggrConstTypes.
find(
II);
2416 if (It == AggrConstTypes.
end())
2418 TypeToAssign = It->second;
2424 for (
const auto &
Op :
I->operands()) {
2431 Type *OpTy =
Op->getType();
2433 CallInst *AssignCI =
2438 Type *OpTy =
Op->getType();
2453 CallInst *AssignCI =
2463bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2464 Instruction *Inst) {
2466 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2477 case Intrinsic::spv_load:
2478 case Intrinsic::spv_store:
2485 const std::string
Prefix =
"__spirv_Atomic";
2486 const bool IsAtomic =
Name.find(Prefix) == 0;
2494void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *
I,
2496 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2498 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2503 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2504 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2505 if (shouldTryToAddMemAliasingDecoration(
I)) {
2506 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2507 ? SPIRV::Decoration::AliasScopeINTEL
2508 : SPIRV::Decoration::NoAliasINTEL;
2510 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2513 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2514 {
I->getType()}, {
Args});
2518 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2519 processMemAliasingDecoration(LLVMContext::MD_noalias);
2522 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2524 bool AllowFPMaxError =
2526 if (!AllowFPMaxError)
2530 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2539 &FPFastMathDefaultInfoMap,
2541 auto it = FPFastMathDefaultInfoMap.
find(
F);
2542 if (it != FPFastMathDefaultInfoMap.
end())
2550 SPIRV::FPFastMathMode::None);
2552 SPIRV::FPFastMathMode::None);
2554 SPIRV::FPFastMathMode::None);
2555 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
2561 size_t BitWidth = Ty->getScalarSizeInBits();
2565 assert(Index >= 0 && Index < 3 &&
2566 "Expected FPFastMathDefaultInfo for half, float, or double");
2567 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2568 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2569 return FPFastMathDefaultInfoVec[Index];
2572void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(
Module &M) {
2574 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2583 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
2585 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
2593 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
2596 [[maybe_unused]] GlobalVariable *GV =
2597 new GlobalVariable(M,
2598 Type::getInt32Ty(
M.getContext()),
2612 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
2613 FPFastMathDefaultInfoMap;
2615 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
2624 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2626 "Expected 4 operands for FPFastMathDefault");
2632 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2634 SPIRV::FPFastMathDefaultInfo &
Info =
2637 Info.FPFastMathDefault =
true;
2638 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
2640 "Expected no operands for ContractionOff");
2644 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2646 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2647 Info.ContractionOff =
true;
2649 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
2651 "Expected 1 operand for SignedZeroInfNanPreserve");
2652 unsigned TargetWidth =
2657 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2661 assert(Index >= 0 && Index < 3 &&
2662 "Expected FPFastMathDefaultInfo for half, float, or double");
2663 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2664 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2665 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
2669 std::unordered_map<unsigned, GlobalVariable *> GlobalVars;
2670 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
2671 if (FPFastMathDefaultInfoVec.
empty())
2674 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2675 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
2678 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
2679 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
2683 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
2685 "and AllowContract");
2687 if (
Info.SignedZeroInfNanPreserve &&
2689 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2690 SPIRV::FPFastMathMode::NSZ))) {
2691 if (
Info.FPFastMathDefault)
2693 "SignedZeroInfNanPreserve but at least one of "
2694 "NotNaN/NotInf/NSZ is enabled.");
2697 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
2698 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
2699 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
2701 "AllowTransform requires AllowReassoc and "
2702 "AllowContract to be set.");
2705 auto it = GlobalVars.find(Flags);
2706 GlobalVariable *GV =
nullptr;
2707 if (it != GlobalVars.end()) {
2713 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
2716 GV =
new GlobalVariable(M,
2717 Type::getInt32Ty(
M.getContext()),
2722 GlobalVars[
Flags] = GV;
2728void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *
I,
2731 bool IsConstComposite =
2732 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
2733 if (IsConstComposite && TrackConstants) {
2735 auto t = AggrConsts.
find(
I);
2739 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
2741 NewOp->setArgOperand(0,
I);
2744 for (
const auto &
Op :
I->operands()) {
2748 unsigned OpNo =
Op.getOperandNo();
2749 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
2750 (!
II->isBundleOperand(OpNo) &&
2751 II->paramHasAttr(OpNo, Attribute::ImmArg))))
2755 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
2756 :
B.SetInsertPoint(
I);
2759 Type *OpTy =
Op->getType();
2767 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
2769 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
2770 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
2772 SmallVector<Value *, 2>
Args = {
2775 CallInst *PtrCasted =
2776 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2781 I->setOperand(OpNo, NewOp);
2783 if (Named.insert(
I).second)
2787Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *
F,
2789 std::unordered_set<Function *> FVisited;
2790 return deduceFunParamElementType(
F,
OpIdx, FVisited);
2793Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
2794 Function *
F,
unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
2796 if (!FVisited.insert(
F).second)
2799 std::unordered_set<Value *> Visited;
2802 for (User *U :
F->users()) {
2814 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
2817 for (User *OpU : OpArg->
users()) {
2819 if (!Inst || Inst == CI)
2822 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
2829 if (FVisited.find(OuterF) != FVisited.end())
2831 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
2832 if (OuterF->
getArg(i) == OpArg) {
2833 Lookup.push_back(std::make_pair(OuterF, i));
2840 for (
auto &Pair :
Lookup) {
2841 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
2848void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *
F,
2850 B.SetInsertPointPastAllocas(
F);
2864 for (User *U :
F->users()) {
2880 for (User *U : Arg->
users()) {
2884 CI->
getParent()->getParent() == CurrF) {
2886 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
2897void SPIRVEmitIntrinsics::processParamTypes(Function *
F,
IRBuilder<> &
B) {
2898 B.SetInsertPointPastAllocas(
F);
2904 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
2906 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
2908 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
2920 bool IsNewFTy =
false;
2936bool SPIRVEmitIntrinsics::processFunctionPointers(
Module &M) {
2939 if (
F.isIntrinsic())
2941 if (
F.isDeclaration()) {
2942 for (User *U :
F.users()) {
2955 for (User *U :
F.users()) {
2957 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
2959 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
2960 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
2967 if (Worklist.
empty())
2970 LLVMContext &Ctx =
M.getContext();
2975 for (Function *
F : Worklist) {
2977 for (
const auto &Arg :
F->args())
2979 IRB.CreateCall(
F, Args);
2981 IRB.CreateRetVoid();
2987void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
2988 DenseMap<Function *, CallInst *> Ptrcasts;
2989 for (
auto It : FDeclPtrTys) {
2991 for (
auto *U :
F->users()) {
2996 for (
auto [Idx, ElemTy] : It.second) {
3004 B.SetInsertPointPastAllocas(Arg->
getParent());
3008 }
else if (isaGEP(Param)) {
3009 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3018 .getFirstNonPHIOrDbgOrAlloca());
3039SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP) {
3046 Type *SrcTy =
GEP->getSourceElementType();
3047 SmallVector<Value *, 8> Indices(
GEP->indices());
3049 if (ArrTy && ArrTy->getNumElements() == 0 &&
3051 Indices.erase(Indices.begin());
3052 SrcTy = ArrTy->getElementType();
3054 GEP->getNoWrapFlags(),
"",
3055 GEP->getIterator());
3060void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &
F,
3066 if (!
ST->canUseExtension(
3067 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls))
3070 for (BasicBlock &BB :
F) {
3072 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3078 unsigned LC =
Ops[0];
3079 if (LC == SPIRV::LoopControl::None)
3083 B.SetInsertPoint(Term);
3084 SmallVector<Value *, 4> IntrArgs;
3086 for (
unsigned I = 1;
I <
Ops.size(); ++
I)
3088 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3092bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3093 if (
Func.isDeclaration())
3097 GR =
ST.getSPIRVGlobalRegistry();
3101 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3106 AggrConstTypes.
clear();
3111 SmallPtrSet<Instruction *, 4> DeadInsts;
3116 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3120 GR->addDeducedElementType(SGEP,
3125 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3127 GEP->replaceAllUsesWith(NewGEP);
3131 if (
Type *GepTy = getGEPType(
GEP))
3135 for (
auto *
I : DeadInsts) {
3136 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3137 I->eraseFromParent();
3140 processParamTypesByFunHeader(CurrF,
B);
3149 Type *ElTy =
SI->getValueOperand()->getType();
3154 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3155 for (
auto &GV :
Func.getParent()->globals())
3156 processGlobalValue(GV,
B);
3158 preprocessUndefs(
B);
3159 preprocessCompositeConstants(
B);
3163 applyDemangledPtrArgTypes(
B);
3166 for (
auto &
I : Worklist) {
3168 if (isConvergenceIntrinsic(
I))
3171 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3173 insertAssignTypeIntrs(
I,
B);
3174 insertPtrCastOrAssignTypeInstr(
I,
B);
3178 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3179 insertAssignPtrTypeIntrs(
I,
B,
true);
3182 useRoundingMode(FPI,
B);
3187 SmallPtrSet<Instruction *, 4> IncompleteRets;
3189 deduceOperandElementType(&
I, &IncompleteRets);
3193 for (BasicBlock &BB : Func)
3194 for (PHINode &Phi : BB.
phis())
3196 deduceOperandElementType(&Phi,
nullptr);
3198 for (
auto *
I : Worklist) {
3199 TrackConstants =
true;
3209 if (isConvergenceIntrinsic(
I))
3213 processInstrAfterVisit(
I,
B);
3216 emitUnstructuredLoopControls(Func,
B);
3222bool SPIRVEmitIntrinsics::postprocessTypes(
Module &M) {
3223 if (!GR || TodoTypeSz == 0)
3226 unsigned SzTodo = TodoTypeSz;
3227 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3232 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3233 Type *KnownTy = GR->findDeducedElementType(
Op);
3234 if (!KnownTy || !AssignCI)
3240 std::unordered_set<Value *> Visited;
3241 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3242 if (ElemTy != KnownTy) {
3243 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3244 propagateElemType(CI, ElemTy, VisitedSubst);
3251 if (
Op->hasUseList()) {
3252 for (User *U :
Op->users()) {
3259 if (TodoTypeSz == 0)
3264 SmallPtrSet<Instruction *, 4> IncompleteRets;
3266 auto It = ToProcess.
find(&
I);
3267 if (It == ToProcess.
end())
3269 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3270 if (It->second.size() == 0)
3272 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3273 if (TodoTypeSz == 0)
3278 return SzTodo > TodoTypeSz;
3282void SPIRVEmitIntrinsics::parseFunDeclarations(
Module &M) {
3284 if (!
F.isDeclaration() ||
F.isIntrinsic())
3288 if (DemangledName.empty())
3292 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3293 DemangledName,
ST.getPreferredInstructionSet());
3294 if (Opcode != SPIRV::OpGroupAsyncCopy)
3297 SmallVector<unsigned> Idxs;
3306 LLVMContext &Ctx =
F.getContext();
3308 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3309 if (!TypeStrs.
size())
3312 for (
unsigned Idx : Idxs) {
3313 if (Idx >= TypeStrs.
size())
3316 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3319 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3324bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3325 const SPIRVSubtarget &
ST = TM->
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3327 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3328 if (!
ST.canUseExtension(
3329 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3330 I.getContext().emitError(
3331 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3335 I.eraseFromParent();
3341 Value *Ptrs =
I.getArgOperand(0);
3343 Value *Passthru =
I.getArgOperand(2);
3346 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3348 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3353 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3355 I.eraseFromParent();
3359 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3360 if (!
ST.canUseExtension(
3361 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3362 I.getContext().emitError(
3363 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3366 I.eraseFromParent();
3372 Value *Values =
I.getArgOperand(0);
3373 Value *Ptrs =
I.getArgOperand(1);
3378 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3380 SmallVector<Value *, 4>
Args = {Values, Ptrs,
B.getInt32(Alignment),
Mask};
3384 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3385 I.eraseFromParent();
3392bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(
Module &M) {
3396 if (!
F.isIntrinsic())
3399 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
3404 Changed |= processMaskedMemIntrinsic(*
II);
3408 F.eraseFromParent();
3414bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
3417 Changed |= convertMaskedMemIntrinsics(M);
3419 parseFunDeclarations(M);
3420 insertConstantsForFPFastMathDefault(M);
3431 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
3433 processParamTypes(&
F,
B);
3437 CanTodoType =
false;
3438 Changed |= postprocessTypes(M);
3441 Changed |= processFunctionPointers(M);
3447 return new SPIRVEmitIntrinsics(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void replaceAllUsesWith(Value *Old, Value *New, SmallPtrSet< BasicBlock *, 32 > &FreshBBs, bool IsHuge)
Replace all old uses with new ones, and push the updated BBs into FreshBBs.
static Type * getPointeeType(Value *Ptr, const DataLayout &DL)
This file defines the DenseSet and SmallDenseSet classes.
static bool runOnFunction(Function &F, bool PostInlining)
iv Induction Variable Users
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Machine Check Debug Module
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static unsigned getNumElements(Type *Ty)
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrConstForceInt32(const Value *V)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, DenseMap< Function *, SPIRV::FPFastMathDefaultInfoVector > &FPFastMathDefaultInfoMap, Function *F)
static Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static void emitAssignName(Instruction *I, IRBuilder<> &B)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void createRoundingModeDecoration(Instruction *I, unsigned RoundingModeDeco, IRBuilder<> &B)
static void createDecorationIntrinsic(Instruction *I, MDNode *Node, IRBuilder<> &B)
static SPIRV::FPFastMathDefaultInfo & getFPFastMathDefaultInfo(SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty)
static cl::opt< bool > SpirvEmitOpNames("spirv-emit-op-names", cl::desc("Emit OpName for all instructions"), cl::init(false))
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
StringSet - A set-like wrapper for the StringMap.
static SymbolRef::Type getType(const Symbol *Sym)
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
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 if the block is well formed or null if the block is not well forme...
static LLVM_ABI BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned arg_size() const
This class represents a function call, abstracting a target machine's calling convention.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI std::optional< RoundingMode > getRoundingMode() const
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Type * getReturnType() const
Returns the type of the ret val.
Argument * getArg(unsigned i) const
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static LLVM_ABI Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static unsigned getPointerOperandIndex()
PointerType * getType() const
Global values are always pointers.
@ InternalLinkage
Rename collisions when linking (static functions).
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI void addDestination(BasicBlock *Dest)
Add a destination.
Base class for instruction visitors.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
static unsigned getPointerOperandIndex()
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Flags
Flags values. These may be or'd together.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg)
Type * findDeducedCompositeType(const Value *Val)
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld=true)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator find(StringRef Key)
StringRef - Represent a constant reference to a string, i.e.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
StringSet - A wrapper for StringMap that provides set-like functionality.
bool contains(StringRef key) const
Check if the set contains the given key.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getArrayElementType() const
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
bool isStructTy() const
True if this is an instance of StructType.
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
void setOperand(unsigned i, Value *Val)
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
const ParentTy * getParent() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ SPIR_KERNEL
Used for SPIR kernel functions.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
bool match(Val *V, const Pattern &P)
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
initializer< Ty > init(const Ty &Val)
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
ModulePass * createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM)
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
bool isNestedPointer(const Type *Ty)
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
auto reverse(ContainerTy &&C)
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
bool isPointerTy(const Type *T)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
@ Ref
The access may reference the value stored in memory.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
bool hasInitializer(const GlobalVariable *GV)
Type * normalizeType(Type *Ty)
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
PoisonValue * getNormalizedPoisonValue(Type *Ty)
bool isUntypedPointerTy(const Type *T)
Type * reconstitutePeeledArrayType(Type *Ty)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)