26#include "llvm/IR/IntrinsicsSPIRV.h"
59#define DEBUG_TYPE "spirv-emit-intrinsics"
63 cl::desc(
"Emit OpName for all instructions"),
67#define GET_BuiltinGroup_DECL
68#include "SPIRVGenTables.inc"
73class GlobalVariableUsers {
74 template <
typename T1,
typename T2>
75 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
77 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
79 void collectGlobalUsers(
80 const GlobalVariable *GV,
81 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
82 &GlobalIsUsedByGlobal) {
84 while (!
Stack.empty()) {
88 GlobalIsUsedByFun[GV].insert(
I->getFunction());
93 GlobalIsUsedByGlobal[GV].insert(UserGV);
98 Stack.append(
C->user_begin(),
C->user_end());
102 bool propagateGlobalToGlobalUsers(
103 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
104 &GlobalIsUsedByGlobal) {
107 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
108 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
109 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
110 auto It = GlobalIsUsedByGlobal.find(UserGV);
111 if (It == GlobalIsUsedByGlobal.end())
119 void propagateGlobalToFunctionReferences(
120 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
121 &GlobalIsUsedByGlobal) {
122 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
123 auto &UserFunctions = GlobalIsUsedByFun[GV];
124 for (
const GlobalVariable *UserGV : UserGlobals) {
125 auto It = GlobalIsUsedByFun.find(UserGV);
126 if (It == GlobalIsUsedByFun.end())
137 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
138 GlobalIsUsedByGlobal;
139 GlobalIsUsedByFun.clear();
140 for (GlobalVariable &GV :
M.globals())
141 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
144 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
147 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
150 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
151 const FunctionSetType &
152 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
153 auto It = GlobalIsUsedByFun.find(&GV);
154 if (It != GlobalIsUsedByFun.end())
157 static const FunctionSetType
Empty{};
162static bool isaGEP(
const Value *V) {
168static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
174 return AT->getNumElements();
180class SPIRVEmitIntrinsicsImpl
181 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
182 const SPIRVTargetMachine &TM;
183 SPIRVGlobalRegistry *GR =
nullptr;
185 bool TrackConstants =
true;
186 bool HaveFunPtrs =
false;
187 bool CanUseAnyVectorRank =
false;
188 DenseMap<Instruction *, Constant *> AggrConsts;
189 DenseMap<Instruction *, Type *> AggrConstTypes;
190 SmallPtrSet<Instruction *, 0> AggrStores;
191 GlobalVariableUsers GVUsers;
192 SmallPtrSet<Value *, 0> Named;
195 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
198 bool CanTodoType =
true;
199 unsigned TodoTypeSz = 0;
200 DenseMap<Value *, bool> TodoType;
201 void insertTodoType(
Value *
Op) {
203 if (CanTodoType && !isaGEP(
Op)) {
204 auto It = TodoType.try_emplace(
Op,
true);
209 void eraseTodoType(
Value *
Op) {
210 auto It = TodoType.find(
Op);
211 if (It != TodoType.end() && It->second) {
219 auto It = TodoType.find(
Op);
220 return It != TodoType.end() && It->second;
224 SmallPtrSet<Instruction *, 0> TypeValidated;
227 enum WellKnownTypes { Event };
230 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
231 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
232 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
233 bool UnknownElemTypeI8,
234 bool IgnoreKnownType =
false);
235 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
236 bool UnknownElemTypeI8);
237 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
238 SmallPtrSetImpl<Value *> &Visited,
239 bool UnknownElemTypeI8);
241 SmallPtrSetImpl<Value *> &Visited,
242 bool UnknownElemTypeI8);
244 bool UnknownElemTypeI8);
247 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
248 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
249 SmallPtrSetImpl<Value *> &Visited,
250 bool UnknownElemTypeI8);
254 deduceOperandElementType(Instruction *
I,
255 SmallPtrSetImpl<Instruction *> *IncompleteRets,
256 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
257 bool IsPostprocessing =
false);
262 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
263 void simplifyNullAddrSpaceCasts();
265 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
266 bool IsPostprocessing);
268 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
270 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
271 bool UnknownElemTypeI8);
273 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
275 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
276 Type *ExpectedElementType,
277 unsigned OperandToReplace,
279 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
280 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
282 void insertConstantsForFPFastMathDefault(
Module &M);
285 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
288 Type *deduceFunParamElementType(
Function *
F,
unsigned OpIdx);
290 SmallPtrSetImpl<Function *> &FVisited);
292 bool deduceOperandElementTypeCalledFunction(
294 Type *&KnownElemTy,
bool &Incomplete);
295 void deduceOperandElementTypeFunctionPointer(
297 Type *&KnownElemTy,
bool IsPostprocessing);
298 bool deduceOperandElementTypeFunctionRet(
299 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
300 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
304 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
305 DenseMap<Function *, CallInst *> Ptrcasts);
307 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
310 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
311 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
312 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
313 SmallPtrSetImpl<Value *> &Visited,
314 DenseMap<Function *, CallInst *> Ptrcasts);
317 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
318 Instruction *Dest,
bool DeleteOld =
true);
322 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
325 bool postprocessTypes(
Module &M);
326 bool processFunctionPointers(
Module &M);
327 void parseFunDeclarations(
Module &M);
328 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
329 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
330 bool convertMaskedMemIntrinsics(
Module &M);
331 void preprocessBoolVectorBitcasts(
Function &
F);
350 bool walkLogicalAccessChain(
351 GetElementPtrInst &
GEP,
352 const std::function<
void(
Type *PointedType,
uint64_t Index)>
355 uint64_t Multiplier)> &OnDynamicIndexing);
357 bool walkLogicalAccessChainDynamic(
359 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
362 bool walkLogicalAccessChainConstant(
364 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing);
370 Type *getGEPType(GetElementPtrInst *
GEP);
377 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
379 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
382 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
385 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
388 Instruction *visitInsertElementInst(InsertElementInst &
I);
389 Instruction *visitExtractElementInst(ExtractElementInst &
I);
391 Instruction *visitExtractValueInst(ExtractValueInst &
I);
395 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
399 bool runOnModule(
Module &M);
402class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
403 const SPIRVTargetMachine &TM;
407 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
408 : ModulePass(ID), TM(TM) {}
410 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
412 bool runOnModule(
Module &M)
override {
413 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
419 Intrinsic::experimental_convergence_loop,
420 Intrinsic::experimental_convergence_anchor>());
423bool expectIgnoredInIRTranslation(
const Instruction *
I) {
425 Intrinsic::spv_resource_handlefrombinding,
426 Intrinsic::spv_resource_getbasepointer,
427 Intrinsic::spv_resource_getpointer>());
434 return getPointerRoot(V);
440char SPIRVEmitIntrinsicsLegacy::ID = 0;
443 "SPIRV emit intrinsics",
false,
false)
457 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
470 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
476 B.SetCurrentDebugLocation(
I->getDebugLoc());
477 if (
I->getType()->isVoidTy())
478 B.SetInsertPoint(
I->getNextNode());
480 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
490 if (
I->getType()->isTokenTy())
492 "does not support token type",
497 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
498 expectIgnoredInIRTranslation(
I))
509 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
520 std::vector<Value *> Args = {
523 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
526void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
530 if (isTodoType(Src)) {
533 insertTodoType(Dest);
537void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
542 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
543 Src->eraseFromParent();
546 if (Named.
insert(Dest).second)
561 V = V->stripPointerCasts();
582Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
583 bool UnknownElemTypeI8,
584 bool IsPostprocessing) {
588 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
602 if (UnknownElemTypeI8) {
603 if (!IsPostprocessing)
619 B.SetInsertPointPastAllocas(OpA->getParent());
622 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
624 Type *OpTy =
Op->getType();
626 SmallVector<Value *, 2>
Args = {
629 CallInst *PtrCasted =
630 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
635void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
637 DenseMap<Function *, CallInst *> Ptrcasts) {
639 CallInst *PtrCastedI =
nullptr;
640 auto It = Ptrcasts.
find(
F);
641 if (It == Ptrcasts.
end()) {
642 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
643 Ptrcasts[
F] = PtrCastedI;
645 PtrCastedI = It->second;
647 I->replaceUsesOfWith(
Op, PtrCastedI);
650void SPIRVEmitIntrinsicsImpl::propagateElemType(
652 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
653 DenseMap<Function *, CallInst *> Ptrcasts;
655 for (
auto *U :
Users) {
658 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
663 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
664 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
668void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
670 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
671 SmallPtrSet<Value *, 0> Visited;
672 DenseMap<Function *, CallInst *> Ptrcasts;
673 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
674 std::move(Ptrcasts));
677void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
679 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
680 SmallPtrSetImpl<Value *> &Visited,
681 DenseMap<Function *, CallInst *> Ptrcasts) {
685 for (
auto *U :
Users) {
688 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
693 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
694 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
701Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
702 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
703 SmallPtrSet<Value *, 0> Visited;
704 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
708Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
709 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
710 bool UnknownElemTypeI8) {
715 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
726Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
727 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
739 for (User *OpU :
Op->users()) {
741 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
753 Function *CalledF,
unsigned OpIdx) {
754 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
763Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
764 bool UnknownElemTypeI8) {
765 SmallPtrSet<Value *, 0> Visited;
766 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
769void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
771 bool UnknownElemTypeI8) {
773 if (!UnknownElemTypeI8)
782bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
784 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
791 if (
ST->getNumElements() == 0)
793 CurType =
ST->getElementType(0);
794 OnLiteralIndexing(CurType, 0);
802 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
803 return AT ==
nullptr;
806bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
808 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing) {
813 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
817 CurType = AT->getElementType();
818 OnLiteralIndexing(CurType, Index);
820 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
823 const auto &STL =
DL.getStructLayout(ST);
824 unsigned Element = STL->getElementContainingOffset(
Offset);
825 Offset -= STL->getElementOffset(Element);
826 CurType =
ST->getElementType(Element);
827 OnLiteralIndexing(CurType, Element);
829 Type *EltTy = VT->getElementType();
830 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
831 assert(EltSizeBits % 8 == 0 &&
832 "Element type size in bits must be a multiple of 8.");
833 uint32_t EltTypeSize = EltSizeBits / 8;
838 OnLiteralIndexing(CurType, Index);
848bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
849 GetElementPtrInst &
GEP,
850 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
854 std::optional<uint64_t> MultiplierOpt =
855 getByteAddressingMultiplier(
GEP.getSourceElementType());
856 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
857 uint64_t Multiplier = *MultiplierOpt;
860 Value *Src = getPointerRoot(
GEP.getPointerOperand());
861 Type *CurType = deduceElementType(Src,
true);
865 return walkLogicalAccessChainConstant(
866 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
868 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
869 OnLiteralIndexing, OnDynamicIndexing);
872Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
873 GetElementPtrInst &
GEP) {
876 B.SetInsertPoint(&
GEP);
878 std::vector<Value *> Indices;
879 Indices.push_back(ConstantInt::get(
880 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
881 walkLogicalAccessChain(
885 ConstantInt::get(
B.getInt64Ty(), Index,
false));
890 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
892 if (Multiplier == EltTypeSize) {
894 }
else if (EltTypeSize % Multiplier == 0) {
897 EltTypeSize / Multiplier,
901 ConstantInt::get(
Offset->getType(), Multiplier,
904 Index =
B.CreateUDiv(Index,
905 ConstantInt::get(
Offset->getType(), EltTypeSize,
909 Indices.push_back(Index);
913 SmallVector<Value *, 4>
Args;
914 Args.push_back(
B.getInt1(
GEP.isInBounds()));
915 Args.push_back(
GEP.getOperand(0));
918 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
919 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
923Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
925 Type *CurType =
GEP->getResultElementType();
927 bool Interrupted = walkLogicalAccessChain(
928 *
GEP, [&CurType](
Type *EltType,
uint64_t Index) { CurType = EltType; },
931 return Interrupted ?
GEP->getResultElementType() : CurType;
934Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
935 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
937 return getGEPTypeLogical(
Ref);
944 Ty =
Ref->getSourceElementType();
948 Ty =
Ref->getResultElementType();
953Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
954 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
955 bool IgnoreKnownType) {
961 if (!IgnoreKnownType)
973 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
975 Ty = getGEPType(
Ref);
977 Ty = SGEP->getResultElementType();
982 KnownTy =
Op->getType();
984 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
987 Ty = SPIRV::getOriginalFunctionType(*Fn);
990 Ty = deduceElementTypeByValueDeep(
992 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
996 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
998 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1000 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1002 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1004 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1009 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1013 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1015 Type *BestTy =
nullptr;
1017 DenseMap<Type *, unsigned> PhiTys;
1018 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1019 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1026 if (It.first->second > MaxN) {
1027 MaxN = It.first->second;
1035 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1039 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1040 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1045 static StringMap<unsigned> ResTypeByArg = {
1049 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1050 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1051 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1052 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1053 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1054 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1058 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1059 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1061 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1062 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1063 for (User *U :
II->users()) {
1068 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1070 Ty = HandleType->getTypeParameter(0);
1071 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1085 }
else if (
II &&
II->getIntrinsicID() ==
1086 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1090 std::string DemangledName =
1092 if (DemangledName.length() > 0)
1093 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1094 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1095 if (AsArgIt != ResTypeByArg.
end())
1096 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1097 Visited, UnknownElemTypeI8);
1104 if (Ty && !IgnoreKnownType) {
1115Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1116 bool UnknownElemTypeI8) {
1117 SmallPtrSet<Value *, 0> Visited;
1118 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1121Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1122 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1123 bool UnknownElemTypeI8) {
1132 if (!Visited.
insert(U).second)
1137 bool Change =
false;
1138 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1140 assert(
Op &&
"Operands should not be null.");
1141 Type *OpTy =
Op->getType();
1144 if (
Type *NestedTy =
1145 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1152 Change |= Ty != OpTy;
1160 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1161 Type *OpTy = ArrTy->getElementType();
1164 if (
Type *NestedTy =
1165 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1172 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1178 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1179 Type *OpTy = VecTy->getElementType();
1182 if (
Type *NestedTy =
1183 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1190 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1201Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1202 bool UnknownElemTypeI8) {
1203 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1205 if (!UnknownElemTypeI8)
1208 return IntegerType::getInt8Ty(
I->getContext());
1212 Value *PointerOperand) {
1218 return I->getType();
1226bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1228 Type *&KnownElemTy,
bool &Incomplete) {
1232 std::string DemangledName =
1234 if (DemangledName.length() > 0 &&
1236 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1237 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1238 DemangledName,
ST.getPreferredInstructionSet());
1239 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1240 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1246 KnownElemTy = ElemTy;
1247 Ops.push_back(std::make_pair(
Op, i));
1249 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1256 case SPIRV::OpAtomicFAddEXT:
1257 case SPIRV::OpAtomicFMinEXT:
1258 case SPIRV::OpAtomicFMaxEXT:
1259 case SPIRV::OpAtomicLoad:
1260 case SPIRV::OpAtomicCompareExchangeWeak:
1261 case SPIRV::OpAtomicCompareExchange:
1262 case SPIRV::OpAtomicExchange:
1263 case SPIRV::OpAtomicIAdd:
1264 case SPIRV::OpAtomicISub:
1265 case SPIRV::OpAtomicOr:
1266 case SPIRV::OpAtomicXor:
1267 case SPIRV::OpAtomicAnd:
1268 case SPIRV::OpAtomicUMin:
1269 case SPIRV::OpAtomicUMax:
1270 case SPIRV::OpAtomicSMin:
1271 case SPIRV::OpAtomicSMax: {
1276 Incomplete = isTodoType(
Op);
1277 Ops.push_back(std::make_pair(
Op, 0));
1279 case SPIRV::OpAtomicStore: {
1288 Incomplete = isTodoType(
Op);
1289 Ops.push_back(std::make_pair(
Op, 0));
1298void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1300 Type *&KnownElemTy,
bool IsPostprocessing) {
1304 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1305 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1306 bool IsNewFTy =
false, IsIncomplete =
false;
1309 Type *ArgTy = Arg->getType();
1314 if (isTodoType(Arg))
1315 IsIncomplete =
true;
1317 IsIncomplete =
true;
1320 ArgTy = FTy->getFunctionParamType(ParmIdx);
1324 Type *RetTy = FTy->getReturnType();
1331 IsIncomplete =
true;
1333 IsIncomplete =
true;
1336 if (!IsPostprocessing && IsIncomplete)
1339 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1342bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1343 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1344 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1356 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1357 for (User *U :
F->users()) {
1366 propagateElemType(CI, PrevElemTy, VisitedSubst);
1376 for (Instruction *IncompleteRetI : *IncompleteRets)
1377 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1379 }
else if (IncompleteRets) {
1390void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1391 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1392 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1394 Type *KnownElemTy =
nullptr;
1395 bool Incomplete =
false;
1401 Incomplete = isTodoType(
I);
1402 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1405 Ops.push_back(std::make_pair(
Op, i));
1411 Incomplete = isTodoType(
I);
1412 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1419 Incomplete = isTodoType(
I);
1420 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1424 KnownElemTy =
Ref->getSourceElementType();
1425 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1430 KnownElemTy =
Ref->getBaseType();
1431 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1434 KnownElemTy =
I->getType();
1441 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1450 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1454 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1459 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1467 Incomplete = isTodoType(
Ref->getPointerOperand());
1468 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1476 Incomplete = isTodoType(
Ref->getPointerOperand());
1477 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1483 Incomplete = isTodoType(
I);
1484 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1487 Ops.push_back(std::make_pair(
Op, i));
1495 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1496 IsPostprocessing, KnownElemTy,
Op,
1499 Incomplete = isTodoType(CurrF);
1500 Ops.push_back(std::make_pair(
Op, 0));
1506 bool Incomplete0 = isTodoType(Op0);
1507 bool Incomplete1 = isTodoType(Op1);
1509 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1511 : GR->findDeducedElementType(Op0);
1513 KnownElemTy = ElemTy0;
1514 Incomplete = Incomplete0;
1515 Ops.push_back(std::make_pair(Op1, 1));
1516 }
else if (ElemTy1) {
1517 KnownElemTy = ElemTy1;
1518 Incomplete = Incomplete1;
1519 Ops.push_back(std::make_pair(Op0, 0));
1523 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1524 else if (HaveFunPtrs)
1525 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1530 if (!KnownElemTy ||
Ops.size() == 0)
1535 for (
auto &OpIt :
Ops) {
1539 Type *AskTy =
nullptr;
1540 CallInst *AskCI =
nullptr;
1541 if (IsPostprocessing && AskOps) {
1547 if (Ty == KnownElemTy)
1550 Type *OpTy =
Op->getType();
1556 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1564 else if (!IsPostprocessing)
1568 if (AssignCI ==
nullptr) {
1577 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1578 std::make_pair(
I,
Op)};
1579 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1583 CallInst *PtrCastI =
1584 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1585 if (OpIt.second == std::numeric_limits<unsigned>::max())
1588 I->setOperand(OpIt.second, PtrCastI);
1594void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1599 if (isAssignTypeInstr(U)) {
1600 B.SetInsertPoint(U);
1601 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1602 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1603 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1605 U->eraseFromParent();
1608 U->replaceUsesOfWith(Old, New);
1616 Type *NewArgTy =
New->getType();
1618 if (NewArgTy != ExpectedArgTy) {
1621 M, Intrinsic::spv_abort, {NewArgTy});
1631 "aggregate PHI/select/freeze should have been mutated to value-id "
1633 U->replaceUsesOfWith(Old, New);
1638 New->copyMetadata(*Old);
1644 bool HasPoisonExt) {
1651 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1652 "lowered as undef\n");
1654 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1655 Type *Ty = UV->getType();
1661 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1662 :
B.CreateIntrinsicWithoutFolding(IID, {});
1663 AggrConsts[
Call] = UV;
1664 AggrConstTypes[
Call] = Ty;
1669 return B.CreateIntrinsic(IID, {Ty}, {});
1676void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1681 SmallVector<Instruction *, 16> Insts;
1685 for (Instruction *
I : Insts) {
1686 bool BPrepared =
false;
1688 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1692 bool IsScalar = !
Op->getType()->isAggregateType();
1695 if (IsScalar && !AsPoison)
1699 if (IsScalar && Phi)
1700 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1701 else if (!BPrepared) {
1705 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1706 I->setOperand(Idx, Repl);
1715void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1719 ASC->replaceAllUsesWith(
1721 ASC->eraseFromParent();
1729 if (!V->getType()->isAggregateType())
1738 I.getType()->isAggregateType();
1744void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1747 for (Use &U :
I->operands()) {
1754 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1759 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1761 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1767void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1771 std::queue<Instruction *> Worklist;
1775 while (!Worklist.empty()) {
1776 auto *
I = Worklist.front();
1779 bool KeepInst =
false;
1780 for (
const auto &
Op :
I->operands()) {
1782 Type *ResTy =
nullptr;
1785 ResTy = COp->getType();
1797 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1800 auto PrepareInsert = [&]() {
1803 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1804 :
B.SetInsertPoint(
I);
1809 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1810 Args.push_back(COp->getElementAsConstant(i));
1816 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1825 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1831 auto *CI =
B.CreateIntrinsicWithoutFolding(
1832 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1836 AggrConsts[CI] = AggrConst;
1837 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1849 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1854 unsigned RoundingModeDeco,
1861 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1870 MDNode *SaturatedConversionNode =
1872 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1892 MDString *ConstraintString =
1897 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1901 B.SetInsertPoint(&
Call);
1902 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1907void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1910 if (!
RM.has_value())
1912 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1913 switch (
RM.value()) {
1917 case RoundingMode::NearestTiesToEven:
1918 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1920 case RoundingMode::TowardNegative:
1921 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1923 case RoundingMode::TowardPositive:
1924 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1926 case RoundingMode::TowardZero:
1927 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1929 case RoundingMode::Dynamic:
1930 case RoundingMode::NearestTiesToAway:
1934 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1940Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1944 B.SetInsertPoint(&
I);
1945 SmallVector<Value *, 4>
Args;
1947 Args.push_back(
I.getCondition());
1950 for (
auto &Case :
I.cases()) {
1951 Args.push_back(Case.getCaseValue());
1952 BBCases.
push_back(Case.getCaseSuccessor());
1955 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1956 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1960 I.eraseFromParent();
1963 B.SetInsertPoint(ParentBB);
1964 IndirectBrInst *BrI =
B.CreateIndirectBr(
1967 for (BasicBlock *BBCase : BBCases)
1976Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
1982 B.SetInsertPoint(&
I);
1984 SmallVector<Value *, 4>
Args;
1985 Args.push_back(
B.getInt1(
true));
1986 Args.push_back(
I.getOperand(0));
1987 Args.push_back(
B.getInt32(0));
1988 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1989 Args.push_back(SGEP->getIndexOperand(J));
1992 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1993 replaceAllUsesWithAndErase(
B, &
I, NewI);
1998SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2000 B.SetInsertPoint(&
I);
2005 unsigned N = RetVTy->getNumElements();
2006 Value *PtrOp =
I.getPointerOperand();
2008 Type *ResultPtrTy = RetVTy->getElementType();
2011 Value *InBounds =
B.getInt1(
I.isInBounds());
2012 Type *LanePointeeTy = getGEPType(&
I);
2013 Type *SrcElemTy =
I.getSourceElementType();
2022 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2023 Value *LaneIdx =
B.getInt32(Lane);
2024 Value *ScalarPtr = PtrOp;
2028 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2032 SmallVector<Value *, 4>
Args;
2033 Args.push_back(InBounds);
2034 Args.push_back(ScalarPtr);
2035 for (
Value *Idx :
I.indices()) {
2043 Args.push_back(visitExtractElementInst(*EI));
2047 Args.push_back(Idx);
2050 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2052 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2056 replaceAllUsesWithAndErase(
B, &
I, NewI);
2074 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2075 return buildLogicalAccessChainFromGEP(
I);
2080 Value *PtrOp =
I.getPointerOperand();
2081 Type *SrcElemTy =
I.getSourceElementType();
2082 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2085 if (ArrTy->getElementType() == SrcElemTy) {
2087 Type *FirstIdxType =
I.getOperand(1)->getType();
2088 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2089 for (
Value *Idx :
I.indices())
2093 SmallVector<Value *, 4>
Args;
2094 Args.push_back(
B.getInt1(
I.isInBounds()));
2095 Args.push_back(
I.getPointerOperand());
2098 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2100 replaceAllUsesWithAndErase(
B, &
I, NewI);
2107 SmallVector<Value *, 4>
Args;
2108 Args.push_back(
B.getInt1(
I.isInBounds()));
2111 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2112 replaceAllUsesWithAndErase(
B, &
I, NewI);
2116Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2118 B.SetInsertPoint(&
I);
2127 I.eraseFromParent();
2134 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2135 replaceAllUsesWithAndErase(
B, &
I, NewI);
2139void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2141 Type *VTy =
V->getType();
2146 if (ElemTy != AssignedType)
2159 if (CurrentType == AssignedType)
2166 " for value " +
V->getName(),
2175void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2176 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2181 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2182 if (PointerElemTy == ExpectedElementType ||
2187 Value *ExpectedElementVal =
2189 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2191 bool FirstPtrCastOrAssignPtrType =
true;
2197 for (
auto User :
Pointer->users()) {
2200 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2201 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2202 II->getOperand(0) != Pointer)
2207 FirstPtrCastOrAssignPtrType =
false;
2208 if (
II->getOperand(1) != VMD ||
2215 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2220 if (
II->getParent() !=
I->getParent())
2223 I->setOperand(OperandToReplace,
II);
2238 if (FirstPtrCastOrAssignPtrType) {
2243 }
else if (isTodoType(Pointer)) {
2244 eraseTodoType(Pointer);
2252 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2253 std::make_pair(
I, Pointer)};
2255 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2267 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2273void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2278 replacePointerOperandWithPtrCast(
2279 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2285 Type *OpTy =
Op->getType();
2288 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2291 if (OpTy ==
Op->getType())
2292 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2293 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2298 Type *OpTy = LI->getType();
2303 Type *NewOpTy = OpTy;
2304 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2305 if (OpTy == NewOpTy)
2306 insertTodoType(Pointer);
2309 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2314 Type *OpTy =
nullptr;
2326 OpTy = GEPI->getSourceElementType();
2328 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2330 insertTodoType(Pointer);
2342 std::string DemangledName =
2346 bool HaveTypes =
false;
2347 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2365 for (User *U : CalledArg->
users()) {
2367 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2373 HaveTypes |= ElemTy !=
nullptr;
2378 if (DemangledName.empty() && !HaveTypes)
2381 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2396 Type *ExpectedType =
2397 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2398 if (!ExpectedType && !DemangledName.empty())
2399 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2400 DemangledName, OpIdx,
I->getContext());
2401 if (!ExpectedType || ExpectedType->
isVoidTy())
2409 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2414SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2417 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2421 I.getOperand(1)->getType(),
2422 I.getOperand(2)->getType()};
2424 B.SetInsertPoint(&
I);
2426 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2428 replaceAllUsesWithAndErase(
B, &
I, NewI);
2433SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2436 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2440 B.SetInsertPoint(&
I);
2442 I.getIndexOperand()->getType()};
2443 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2444 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2446 replaceAllUsesWithAndErase(
B, &
I, NewI);
2450Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2452 B.SetInsertPoint(&
I);
2455 Value *AggregateOp =
I.getAggregateOperand();
2459 Args.push_back(AggregateOp);
2460 Args.push_back(
I.getInsertedValueOperand());
2461 for (
auto &
Op :
I.indices())
2462 Args.push_back(
B.getInt32(
Op));
2464 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2465 replaceMemInstrUses(&
I, NewI,
B);
2470SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2472 B.SetInsertPoint(&
I);
2473 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2482 for (
auto &
Op :
I.indices())
2483 Args.push_back(
B.getInt32(
Op));
2484 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2485 {
I.getType()}, {
Args});
2491 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2492 AggrConstTypes[NewI] =
I.getType();
2494 replaceMemInstrUses(&
I, NewI,
B);
2497 replaceAllUsesWithAndErase(
B, &
I, NewI);
2501 for (
const Use &U : NewI->
uses()) {
2502 User *Usr =
U.getUser();
2504 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2515 if (ArgNo < FT->getNumParams() &&
2516 !FT->getParamType(ArgNo)->isAggregateType()) {
2525Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2526 if (!
I.getType()->isAggregateType())
2529 B.SetInsertPoint(&
I);
2530 TrackConstants =
false;
2535 unsigned IntrinsicId;
2536 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2537 if (!
I.isAtomic()) {
2538 IntrinsicId = Intrinsic::spv_load;
2539 Args.push_back(
B.getInt32(
I.getAlign().value()));
2541 IntrinsicId = Intrinsic::spv_atomic_load;
2542 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2544 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2545 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2547 replaceMemInstrUses(&
I, NewI,
B);
2551Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2555 B.SetInsertPoint(&
I);
2556 TrackConstants =
false;
2560 auto *PtrOp =
I.getPointerOperand();
2562 if (
I.getValueOperand()->getType()->isAggregateType()) {
2570 "Unexpected argument of aggregate type, should be spv_extractv!");
2574 unsigned IntrinsicId;
2575 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2577 if (!
I.isAtomic()) {
2578 IntrinsicId = Intrinsic::spv_store;
2579 Args.push_back(
B.getInt32(
I.getAlign().value()));
2581 IntrinsicId = Intrinsic::spv_atomic_store;
2582 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2585 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2587 I.eraseFromParent();
2591Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2592 Value *ArraySize =
nullptr;
2593 if (
I.isArrayAllocation()) {
2596 SPIRV::Extension::SPV_INTEL_variable_length_array))
2598 "array allocation: this instruction requires the following "
2599 "SPIR-V extension: SPV_INTEL_variable_length_array",
2601 ArraySize =
I.getArraySize();
2604 B.SetInsertPoint(&
I);
2605 TrackConstants =
false;
2606 Type *PtrTy =
I.getType();
2609 ?
B.CreateIntrinsicWithoutFolding(
2610 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2611 {ArraySize,
B.getInt32(
I.getAlign().value())})
2612 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2613 {
B.getInt32(
I.getAlign().value())});
2614 replaceAllUsesWithAndErase(
B, &
I, NewI);
2619SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2620 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2622 B.SetInsertPoint(&
I);
2625 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2629 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2630 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2631 uint32_t ScSem =
static_cast<uint32_t
>(
2640 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2641 replaceMemInstrUses(&
I, NewI,
B);
2650 case Intrinsic::spv_abort:
2652 case Intrinsic::trap:
2653 case Intrinsic::ubsantrap:
2655 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2675 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2676 "abort-like call must be the last non-debug instruction before its "
2677 "block's terminator");
2681Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2682 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2686 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2693 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2707 while (!Stack.empty()) {
2708 const Value *V = Stack.pop_back_val();
2709 if (!Visited.
insert(V).second)
2717 Stack.append(
C->user_begin(),
C->user_end());
2733 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2734 if (UserFunctions.contains(
F))
2739 if (!UserFunctions.empty())
2744 const Module &M = *
F->getParent();
2745 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2746 return F == &FirstDefinition;
2749Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2751 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2752 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2754 AggrConstTypes[Leaf] = ElemTy;
2757 SmallVector<Value *, 4> Elems;
2759 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2762 DenseMap<Type *, Instruction *> LeafByType;
2763 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2765 auto &
Entry = LeafByType[ElemTy];
2767 Entry = MakeLeaf(ElemTy);
2771 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2772 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2774 AggrConstTypes[Composite] = AggrTy;
2783void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2788 for (BasicBlock &BB : Func) {
2792 Value *RetVal = RI->getReturnValue();
2799 B.SetInsertPoint(RI);
2802 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2803 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2805 RI->setOperand(0, Rebuilt);
2809void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2819 deduceElementTypeHelper(&GV,
false);
2824 Value *InitOp = Init;
2831 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2832 {
B.getInt32Ty()}, {});
2837 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2842 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2843 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2849 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2855bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2857 bool UnknownElemTypeI8) {
2863 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2870void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2873 static StringMap<unsigned> ResTypeWellKnown = {
2874 {
"async_work_group_copy", WellKnownTypes::Event},
2875 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2876 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2880 bool IsKnown =
false;
2885 std::string DemangledName =
2888 if (DemangledName.length() > 0)
2890 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2891 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2892 if (ResIt != ResTypeWellKnown.
end()) {
2895 switch (ResIt->second) {
2896 case WellKnownTypes::Event:
2899 CanUseAnyVectorRank);
2904 switch (DecorationId) {
2907 case FPDecorationId::SAT:
2910 case FPDecorationId::RTE:
2912 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2914 case FPDecorationId::RTZ:
2916 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2918 case FPDecorationId::RTP:
2920 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2922 case FPDecorationId::RTN:
2924 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2930 Type *Ty =
I->getType();
2933 Type *TypeToAssign = Ty;
2936 auto It = AggrConstTypes.
find(
II);
2937 if (It == AggrConstTypes.
end())
2939 TypeToAssign = It->second;
2940 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2941 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2942 TypeToAssign = It->second;
2944 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2945 TypeToAssign = It->second;
2949 for (
const auto &
Op :
I->operands()) {
2957 Type *OpTy =
Op->getType();
2959 CallInst *AssignCI =
2964 Type *OpTy =
Op->getType();
2980 Intrinsic::spv_assign_type, {OpTy},
2990bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
2991 Instruction *Inst) {
2993 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3003void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3005 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3007 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3012 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3013 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3014 if (shouldTryToAddMemAliasingDecoration(
I)) {
3015 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3016 ? SPIRV::Decoration::AliasScopeINTEL
3017 : SPIRV::Decoration::NoAliasINTEL;
3019 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3022 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3023 {
I->getType()}, {
Args});
3027 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3028 processMemAliasingDecoration(LLVMContext::MD_noalias);
3031 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3033 bool AllowFPMaxError =
3035 if (!AllowFPMaxError)
3039 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3043 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
3047 auto &Ctx =
B.getContext();
3049 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
3052 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3054 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3055 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3058 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
3060 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
3062 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3070 &FPFastMathDefaultInfoMap,
3072 auto it = FPFastMathDefaultInfoMap.
find(
F);
3073 if (it != FPFastMathDefaultInfoMap.
end())
3081 SPIRV::FPFastMathMode::None);
3083 SPIRV::FPFastMathMode::None);
3085 SPIRV::FPFastMathMode::None);
3086 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3092 size_t BitWidth = Ty->getScalarSizeInBits();
3096 assert(Index >= 0 && Index < 3 &&
3097 "Expected FPFastMathDefaultInfo for half, float, or double");
3098 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3099 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3100 return FPFastMathDefaultInfoVec[Index];
3103void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3105 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3114 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3116 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3124 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3127 [[maybe_unused]] GlobalVariable *GV =
3128 new GlobalVariable(M,
3129 Type::getInt32Ty(
M.getContext()),
3143 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3144 FPFastMathDefaultInfoMap;
3146 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3155 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3157 "Expected 4 operands for FPFastMathDefault");
3163 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3165 SPIRV::FPFastMathDefaultInfo &
Info =
3168 Info.FPFastMathDefault =
true;
3169 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3171 "Expected no operands for ContractionOff");
3175 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3177 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3178 Info.ContractionOff =
true;
3180 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3182 "Expected 1 operand for SignedZeroInfNanPreserve");
3183 unsigned TargetWidth =
3188 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3192 assert(Index >= 0 && Index < 3 &&
3193 "Expected FPFastMathDefaultInfo for half, float, or double");
3194 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3195 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3196 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3200 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3201 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3202 if (FPFastMathDefaultInfoVec.
empty())
3205 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3206 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3209 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3210 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3214 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3216 "and AllowContract");
3218 if (
Info.SignedZeroInfNanPreserve &&
3220 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3221 SPIRV::FPFastMathMode::NSZ))) {
3222 if (
Info.FPFastMathDefault)
3224 "SignedZeroInfNanPreserve but at least one of "
3225 "NotNaN/NotInf/NSZ is enabled.");
3228 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3229 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3230 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3232 "AllowTransform requires AllowReassoc and "
3233 "AllowContract to be set.");
3236 auto it = GlobalVars.
find(Flags);
3237 GlobalVariable *GV =
nullptr;
3238 if (it != GlobalVars.
end()) {
3244 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3247 GV =
new GlobalVariable(M,
3248 Type::getInt32Ty(
M.getContext()),
3253 GlobalVars[
Flags] = GV;
3259void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3262 bool IsConstComposite =
3263 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3264 if (IsConstComposite && TrackConstants) {
3266 auto t = AggrConsts.
find(
I);
3270 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3272 NewOp->setArgOperand(0,
I);
3275 for (
const auto &
Op :
I->operands()) {
3279 unsigned OpNo =
Op.getOperandNo();
3280 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3281 (!
II->isBundleOperand(OpNo) &&
3282 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3286 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3287 :
B.SetInsertPoint(
I);
3290 Type *OpTy =
Op->getType();
3298 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3300 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3301 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3303 SmallVector<Value *, 2>
Args = {
3307 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3313 I->setOperand(OpNo, NewOp);
3319Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3321 SmallPtrSet<Function *, 0> FVisited;
3322 return deduceFunParamElementType(
F, OpIdx, FVisited);
3325Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3326 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3328 if (!FVisited.
insert(
F).second)
3331 SmallPtrSet<Value *, 0> Visited;
3334 for (User *U :
F->users()) {
3336 if (!CI || OpIdx >= CI->
arg_size())
3346 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3349 for (User *OpU : OpArg->
users()) {
3351 if (!Inst || Inst == CI)
3354 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3361 if (FVisited.
find(OuterF) != FVisited.
end())
3363 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3364 if (OuterF->
getArg(i) == OpArg) {
3365 Lookup.push_back(std::make_pair(OuterF, i));
3372 for (
auto &Pair :
Lookup) {
3373 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3380void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3382 B.SetInsertPointPastAllocas(
F);
3383 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3389 for (User *U : Arg->
users()) {
3391 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3409 for (User *U :
F->users()) {
3411 if (!CI || OpIdx >= CI->
arg_size())
3425 for (User *U : Arg->
users()) {
3429 CI->
getParent()->getParent() == CurrF) {
3431 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3443 B.SetInsertPointPastAllocas(
F);
3444 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3449 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3451 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3455 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3467 bool IsNewFTy =
false;
3483bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3486 if (
F.isIntrinsic())
3488 if (
F.isDeclaration()) {
3489 for (User *U :
F.users()) {
3502 for (User *U :
F.users()) {
3504 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3506 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3507 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3515 if (Worklist.
empty())
3518 LLVMContext &Ctx =
M.getContext();
3525 for (
const auto &Arg :
F->args())
3528 IRB.CreateCall(
F, Args);
3530 IRB.CreateRetVoid();
3536void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3537 DenseMap<Function *, CallInst *> Ptrcasts;
3538 for (
auto It : FDeclPtrTys) {
3540 for (
auto *U :
F->users()) {
3545 for (
auto [Idx, ElemTy] : It.second) {
3553 B.SetInsertPointPastAllocas(Arg->
getParent());
3557 }
else if (isaGEP(Param)) {
3558 replaceUsesOfWithSpvPtrcast(
3559 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3568 .getFirstNonPHIOrDbgOrAlloca());
3588GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3589 GetElementPtrInst *
GEP) {
3596 Type *SrcTy =
GEP->getSourceElementType();
3597 SmallVector<Value *, 8> Indices(
GEP->indices());
3599 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3600 Indices.erase(Indices.begin());
3601 SrcTy = ArrTy->getElementType();
3603 GEP->getNoWrapFlags(),
"",
3604 GEP->getIterator());
3609void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3616 if (
ST->canUseExtension(
3617 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3618 for (BasicBlock &BB :
F) {
3620 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3624 SmallVector<unsigned, 1>
Ops =
3626 unsigned LC =
Ops[0];
3627 if (LC == SPIRV::LoopControl::None)
3631 B.SetInsertPoint(Term);
3632 SmallVector<Value *, 4> IntrArgs;
3633 for (
unsigned Op :
Ops)
3635 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3656 SmallVector<unsigned, 1> LoopControlOps =
3658 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3662 B.SetInsertPoint(Header->getTerminator());
3665 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3666 for (
unsigned Imm : LoopControlOps)
3667 Args.emplace_back(
B.getInt32(
Imm));
3668 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3672bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3673 if (
Func.isDeclaration())
3677 GR =
ST.getSPIRVGlobalRegistry();
3681 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3683 CanUseAnyVectorRank =
3684 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3688 AggrConstTypes.
clear();
3691 processParamTypesByFunHeader(CurrF,
B);
3695 SmallPtrSet<Instruction *, 4> DeadInsts;
3698 Type *ElTy =
SI->getValueOperand()->getType();
3707 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3711 GR->addDeducedElementType(
3713 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3717 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3719 GEP->replaceAllUsesWith(NewGEP);
3723 if (
Type *GepTy = getGEPType(
GEP))
3727 for (
auto *
I : DeadInsts) {
3728 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3729 I->eraseFromParent();
3732 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3733 for (
auto &GV :
Func.getParent()->globals())
3734 processGlobalValue(GV,
B);
3736 reconstructAggregateReturns(Func,
B);
3737 preprocessUndefsAndPoisons(
B);
3738 simplifyNullAddrSpaceCasts();
3739 preprocessCompositeConstants(
B);
3747 Type *I32Ty =
B.getInt32Ty();
3752 insertCompositeAggregateArms(&
I,
B);
3753 AggrConstTypes[&
I] =
I.getType();
3754 I.mutateType(I32Ty);
3757 preprocessBoolVectorBitcasts(Func);
3758 SmallVector<Instruction *> Worklist(
3761 applyDemangledPtrArgTypes(
B);
3764 for (
auto &
I : Worklist) {
3766 if (isConvergenceIntrinsic(
I))
3769 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3771 insertAssignTypeIntrs(
I,
B);
3772 insertPtrCastOrAssignTypeInstr(
I,
B);
3776 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3777 insertAssignPtrTypeIntrs(
I,
B,
true);
3780 useRoundingMode(FPI,
B);
3785 SmallPtrSet<Instruction *, 4> IncompleteRets;
3787 deduceOperandElementType(&
I, &IncompleteRets);
3791 for (BasicBlock &BB : Func)
3792 for (PHINode &Phi : BB.
phis())
3794 deduceOperandElementType(&Phi,
nullptr);
3796 for (
auto *
I : Worklist) {
3797 TrackConstants =
true;
3807 if (isConvergenceIntrinsic(
I))
3811 processInstrAfterVisit(
I,
B);
3814 emitUnstructuredLoopControls(Func,
B);
3820bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3821 if (!GR || TodoTypeSz == 0)
3824 unsigned SzTodo = TodoTypeSz;
3825 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3830 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3831 Type *KnownTy = GR->findDeducedElementType(
Op);
3832 if (!KnownTy || !AssignCI)
3838 SmallPtrSet<Value *, 0> Visited;
3839 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3840 if (ElemTy != KnownTy) {
3841 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3842 propagateElemType(CI, ElemTy, VisitedSubst);
3849 if (
Op->hasUseList()) {
3850 for (User *U :
Op->users()) {
3857 if (TodoTypeSz == 0)
3862 SmallPtrSet<Instruction *, 4> IncompleteRets;
3864 auto It = ToProcess.
find(&
I);
3865 if (It == ToProcess.
end())
3867 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3868 if (It->second.size() == 0)
3870 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3871 if (TodoTypeSz == 0)
3876 return SzTodo > TodoTypeSz;
3880void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
3882 if (!
F.isDeclaration() ||
F.isIntrinsic())
3886 if (DemangledName.empty())
3890 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3891 DemangledName,
ST.getPreferredInstructionSet());
3892 if (Opcode != SPIRV::OpGroupAsyncCopy)
3895 SmallVector<unsigned> Idxs;
3896 for (
unsigned OpIdx = 0; OpIdx <
F.arg_size(); ++OpIdx) {
3904 LLVMContext &Ctx =
F.getContext();
3906 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3907 if (!TypeStrs.
size())
3910 for (
unsigned Idx : Idxs) {
3911 if (Idx >= TypeStrs.
size())
3914 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3917 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3922bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3923 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3925 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3926 if (!
ST.canUseExtension(
3927 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3928 I.getContext().emitError(
3929 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3933 I.eraseFromParent();
3939 Value *Ptrs =
I.getArgOperand(0);
3941 Value *Passthru =
I.getArgOperand(2);
3944 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
3946 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3951 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3953 I.eraseFromParent();
3957 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3958 if (!
ST.canUseExtension(
3959 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3960 I.getContext().emitError(
3961 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3964 I.eraseFromParent();
3971 Value *Ptrs =
I.getArgOperand(1);
3976 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
3978 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
3982 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3983 I.eraseFromParent();
3994void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
3995 struct BoolVecBitcast {
3997 FixedVectorType *BoolVecTy;
4001 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4003 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4011 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4013 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4017 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4019 Value *Src = BC->getOperand(0);
4020 unsigned BoolVecN = BoolVecTy->getNumElements();
4022 Type *IntTy =
B.getIntNTy(BoolVecN);
4028 IntVal = ConstantInt::get(IntTy, 0);
4029 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4030 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
4031 Value *Ext =
B.CreateZExt(Elem, IntTy);
4033 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
4034 IntVal =
B.CreateOr(IntVal, Ext);
4040 if (!Src->getType()->isIntegerTy())
4041 IntVal =
B.CreateBitCast(Src, IntTy);
4046 if (!SrcIsBoolVec) {
4049 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4052 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
4053 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4059 if (!BC->getDestTy()->isIntegerTy())
4060 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4063 BC->replaceAllUsesWith(Result);
4064 BC->eraseFromParent();
4068bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4072 if (!
F.isIntrinsic())
4075 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4080 Changed |= processMaskedMemIntrinsic(*
II);
4084 F.eraseFromParent();
4090bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4093 Changed |= convertMaskedMemIntrinsics(M);
4095 parseFunDeclarations(M);
4096 insertConstantsForFPFastMathDefault(M);
4107 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4109 processParamTypes(&
F,
B);
4113 CanTodoType =
false;
4114 Changed |= postprocessTypes(M);
4117 Changed |= processFunctionPointers(M);
4124 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4130 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.
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)