30#include "llvm/IR/IntrinsicsSPIRV.h"
64#define DEBUG_TYPE "spirv-emit-intrinsics"
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 =
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 MapVector<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 SmallVector<Instruction *> RetypedToRevalidate;
228 bool RevalidatingRetyped =
false;
231 enum WellKnownTypes { Event };
234 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
235 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
236 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
237 bool UnknownElemTypeI8,
238 bool IgnoreKnownType =
false);
239 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
240 bool UnknownElemTypeI8);
241 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
242 SmallPtrSetImpl<Value *> &Visited,
243 bool UnknownElemTypeI8,
244 std::optional<unsigned> AddrSpace = {});
246 SmallPtrSetImpl<Value *> &Visited,
247 bool UnknownElemTypeI8);
249 bool UnknownElemTypeI8);
252 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
253 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
254 SmallPtrSetImpl<Value *> &Visited,
255 bool UnknownElemTypeI8);
259 deduceOperandElementType(Instruction *
I,
260 SmallPtrSetImpl<Instruction *> *IncompleteRets,
261 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
262 bool IsPostprocessing =
false);
267 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
268 void simplifyNullAddrSpaceCasts();
270 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
271 bool IsPostprocessing);
273 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
275 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
276 bool UnknownElemTypeI8);
278 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *
V,
280 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
281 Type *ExpectedElementType,
282 unsigned OperandToReplace,
284 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
285 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
287 void insertConstantsForFPFastMathDefault(
Module &M);
290 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
293 Type *deduceFunParamElementType(
Function *
F,
unsigned OpIdx);
295 SmallPtrSetImpl<Function *> &FVisited);
297 bool deduceOperandElementTypeCalledFunction(
299 Type *&KnownElemTy,
bool &Incomplete);
300 void deduceOperandElementTypeFunctionPointer(
302 Type *&KnownElemTy,
bool IsPostprocessing);
303 bool deduceOperandElementTypeFunctionRet(
304 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
305 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
309 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
310 DenseMap<Function *, CallInst *> Ptrcasts);
312 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
315 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
316 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
317 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
318 SmallPtrSetImpl<Value *> &Visited,
319 DenseMap<Function *, CallInst *> Ptrcasts);
322 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
323 Instruction *Dest,
bool DeleteOld =
true);
327 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
330 bool postprocessTypes(
Module &M);
331 bool processFunctionPointers(
Module &M);
332 void parseFunDeclarations(
Module &M);
333 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
334 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
335 bool convertMaskedMemIntrinsics(
Module &M);
336 bool foldStaticArrayAllocas(
Module &M);
337 void preprocessBoolVectorBitcasts(
Function &
F);
356 bool walkLogicalAccessChain(
357 GetElementPtrInst &
GEP,
358 const std::function<
void(
Type *PointedType,
uint64_t Index)>
361 uint64_t Multiplier)> &OnDynamicIndexing);
363 bool walkLogicalAccessChainDynamic(
365 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
368 bool walkLogicalAccessChainConstant(
370 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing);
376 Type *getGEPType(GetElementPtrInst *
GEP);
383 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
385 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
388 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
391 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
394 Instruction *visitInsertElementInst(InsertElementInst &
I);
395 Instruction *visitExtractElementInst(ExtractElementInst &
I);
397 Instruction *visitExtractValueInst(ExtractValueInst &
I);
401 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
406 bool runOnModule(
Module &M);
409class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
410 const SPIRVTargetMachine &TM;
414 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
415 : ModulePass(ID), TM(TM) {}
417 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
419 bool runOnModule(
Module &M)
override {
420 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
426 Intrinsic::experimental_convergence_loop,
427 Intrinsic::experimental_convergence_anchor>());
430bool expectIgnoredInIRTranslation(
const Instruction *
I) {
432 Intrinsic::spv_resource_handlefrombinding,
433 Intrinsic::spv_resource_getbasepointer,
434 Intrinsic::spv_resource_getpointer>());
441 return getPointerRoot(
V);
447char SPIRVEmitIntrinsicsLegacy::ID = 0;
450 "SPIRV emit intrinsics",
false,
false)
477 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrAlloca());
483 B.SetCurrentDebugLocation(
I->getDebugLoc());
484 if (
I->getType()->isVoidTy())
485 B.SetInsertPoint(
I->getNextNode());
487 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
497 if (
I->getType()->isTokenTy())
499 "does not support token type",
505 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
506 expectIgnoredInIRTranslation(
I))
511 bool KeepName = CLOpts.emit_op_names;
517 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
528 std::vector<Value *> Args = {
531 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
534void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
538 if (isTodoType(Src)) {
541 insertTodoType(Dest);
545void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
550 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
551 Src->eraseFromParent();
554 if (Named.
insert(Dest).second)
569 V =
V->stripPointerCasts();
599Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
600 bool UnknownElemTypeI8,
601 bool IsPostprocessing) {
605 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
619 if (UnknownElemTypeI8) {
620 if (!IsPostprocessing)
636 B.SetInsertPointPastAllocas(OpA->getParent());
639 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrAlloca());
641 Type *OpTy =
Op->getType();
643 SmallVector<Value *, 2>
Args = {
646 CallInst *PtrCasted =
647 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
652void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
654 DenseMap<Function *, CallInst *> Ptrcasts) {
656 CallInst *PtrCastedI =
nullptr;
657 auto It = Ptrcasts.
find(
F);
658 if (It == Ptrcasts.
end()) {
659 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
660 Ptrcasts[
F] = PtrCastedI;
662 PtrCastedI = It->second;
664 I->replaceUsesOfWith(
Op, PtrCastedI);
667void SPIRVEmitIntrinsicsImpl::propagateElemType(
669 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
670 DenseMap<Function *, CallInst *> Ptrcasts;
672 for (
auto *U :
Users) {
675 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
680 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
681 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
685void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
687 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
688 SmallPtrSet<Value *, 0> Visited;
689 DenseMap<Function *, CallInst *> Ptrcasts;
690 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
691 std::move(Ptrcasts));
694void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
696 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
697 SmallPtrSetImpl<Value *> &Visited,
698 DenseMap<Function *, CallInst *> Ptrcasts) {
702 for (
auto *U :
Users) {
705 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
710 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
711 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
718Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
719 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
720 SmallPtrSet<Value *, 0> Visited;
721 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
725Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
726 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
727 bool UnknownElemTypeI8, std::optional<unsigned> AddrSpace) {
732 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
734 NestedTy, AddrSpace.value_or(PtrTy->getAddressSpace()));
744Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
745 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
757 for (User *OpU :
Op->users()) {
759 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
771 Function *CalledF,
unsigned OpIdx) {
777 if (Name ==
"printf" || Name ==
"get_fence")
785Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
786 bool UnknownElemTypeI8) {
787 SmallPtrSet<Value *, 0> Visited;
788 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
791void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
793 bool UnknownElemTypeI8) {
795 if (!UnknownElemTypeI8)
804bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
806 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
813 if (
ST->getNumElements() == 0)
815 CurType =
ST->getElementType(0);
816 OnLiteralIndexing(CurType, 0);
824 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
825 return AT ==
nullptr;
828bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
830 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing) {
835 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
839 CurType = AT->getElementType();
840 OnLiteralIndexing(CurType, Index);
842 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
845 const auto &STL =
DL.getStructLayout(ST);
846 unsigned Element = STL->getElementContainingOffset(
Offset);
847 Offset -= STL->getElementOffset(Element);
848 CurType =
ST->getElementType(Element);
849 OnLiteralIndexing(CurType, Element);
851 Type *EltTy = VT->getElementType();
852 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
853 assert(EltSizeBits % 8 == 0 &&
854 "Element type size in bits must be a multiple of 8.");
855 uint32_t EltTypeSize = EltSizeBits / 8;
860 OnLiteralIndexing(CurType, Index);
870bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
871 GetElementPtrInst &
GEP,
872 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
876 std::optional<uint64_t> MultiplierOpt =
877 getByteAddressingMultiplier(
GEP.getSourceElementType());
878 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
879 uint64_t Multiplier = *MultiplierOpt;
882 Value *Src = getPointerRoot(
GEP.getPointerOperand());
883 Type *CurType = deduceElementType(Src,
true);
887 return walkLogicalAccessChainConstant(
888 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
890 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
891 OnLiteralIndexing, OnDynamicIndexing);
894Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
895 GetElementPtrInst &
GEP) {
898 B.SetInsertPoint(&
GEP);
900 std::vector<Value *> Indices;
901 Indices.push_back(ConstantInt::get(
902 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
903 walkLogicalAccessChain(
907 ConstantInt::get(
B.getInt64Ty(), Index,
false));
912 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
914 if (Multiplier == EltTypeSize) {
916 }
else if (EltTypeSize % Multiplier == 0) {
919 EltTypeSize / Multiplier,
923 ConstantInt::get(
Offset->getType(), Multiplier,
926 Index =
B.CreateUDiv(Index,
927 ConstantInt::get(
Offset->getType(), EltTypeSize,
931 Indices.push_back(Index);
935 SmallVector<Value *, 4>
Args;
936 Args.push_back(
B.getInt1(
GEP.isInBounds()));
937 Args.push_back(
GEP.getOperand(0));
940 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
941 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
945Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
947 Type *CurType =
GEP->getResultElementType();
949 bool Interrupted = walkLogicalAccessChain(
950 *
GEP, [&CurType](
Type *EltType,
uint64_t Index) { CurType = EltType; },
953 return Interrupted ?
GEP->getResultElementType() : CurType;
956Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
957 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
959 return getGEPTypeLogical(
Ref);
966 Ty =
Ref->getSourceElementType();
970 Ty =
Ref->getResultElementType();
975Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
976 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
977 bool IgnoreKnownType) {
983 if (!IgnoreKnownType)
995 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
997 Ty = getGEPType(
Ref);
999 Ty = SGEP->getResultElementType();
1004 KnownTy =
Op->getType();
1006 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
1009 Ty = SPIRV::getOriginalFunctionType(*Fn);
1016 std::optional<unsigned> ProgramAS;
1021 SPIRV::Extension::SPV_INTEL_function_pointers))
1025 Ty = deduceElementTypeByValueDeep(
Ref->getValueType(),
Op, Visited,
1026 UnknownElemTypeI8, ProgramAS);
1029 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
1031 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1033 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1035 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1037 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1043 reconstructType(
Ref->getAggregateOperand(),
false,
false),
1048 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1052 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1054 Type *BestTy =
nullptr;
1056 DenseMap<Type *, unsigned> PhiTys;
1057 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1058 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1065 if (It.first->second > MaxN) {
1066 MaxN = It.first->second;
1074 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1078 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1079 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1084 static StringMap<unsigned> ResTypeByArg = {
1090 {
"__to_private", 0},
1091 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1092 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1093 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1094 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1095 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1096 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1100 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1101 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1103 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1104 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1105 for (User *U :
II->users()) {
1110 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1112 Ty = HandleType->getTypeParameter(0);
1113 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1127 }
else if (
II &&
II->getIntrinsicID() ==
1128 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1132 std::string DemangledName =
1134 if (DemangledName.length() > 0)
1135 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1136 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1137 if (AsArgIt != ResTypeByArg.
end())
1138 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1139 Visited, UnknownElemTypeI8);
1146 if (Ty && !IgnoreKnownType) {
1157Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1158 bool UnknownElemTypeI8) {
1159 SmallPtrSet<Value *, 0> Visited;
1160 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1163Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1164 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1165 bool UnknownElemTypeI8) {
1175 if (!Visited.
insert(U).second)
1180 bool Change =
false;
1181 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1183 assert(
Op &&
"Operands should not be null.");
1184 Type *OpTy =
Op->getType();
1187 if (
Type *NestedTy =
1188 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1195 Change |= Ty != OpTy;
1199 Tys, OrigStructTy->isLiteral() ?
"" : OrigStructTy->getName(),
1200 OrigStructTy->isPacked());
1205 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1206 Type *OpTy = ArrTy->getElementType();
1209 if (
Type *NestedTy =
1210 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1217 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1223 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1224 Type *OpTy = VecTy->getElementType();
1227 if (
Type *NestedTy =
1228 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1235 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1246Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1247 bool UnknownElemTypeI8) {
1248 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1250 if (!UnknownElemTypeI8)
1253 return IntegerType::getInt8Ty(
I->getContext());
1257 Value *PointerOperand) {
1263 return I->getType();
1271bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1273 Type *&KnownElemTy,
bool &Incomplete) {
1277 std::string DemangledName =
1279 if (DemangledName.length() > 0 &&
1281 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1282 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1283 DemangledName,
ST.getPreferredInstructionSet());
1284 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1285 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1291 KnownElemTy = ElemTy;
1292 Ops.push_back(std::make_pair(
Op, i));
1294 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1301 case SPIRV::OpAtomicFAddEXT:
1302 case SPIRV::OpAtomicFMinEXT:
1303 case SPIRV::OpAtomicFMaxEXT:
1304 case SPIRV::OpAtomicLoad:
1305 case SPIRV::OpAtomicCompareExchangeWeak:
1306 case SPIRV::OpAtomicCompareExchange:
1307 case SPIRV::OpAtomicExchange:
1308 case SPIRV::OpAtomicIAdd:
1309 case SPIRV::OpAtomicISub:
1310 case SPIRV::OpAtomicOr:
1311 case SPIRV::OpAtomicXor:
1312 case SPIRV::OpAtomicAnd:
1313 case SPIRV::OpAtomicUMin:
1314 case SPIRV::OpAtomicUMax:
1315 case SPIRV::OpAtomicSMin:
1316 case SPIRV::OpAtomicSMax: {
1321 Incomplete = isTodoType(
Op);
1322 Ops.push_back(std::make_pair(
Op, 0));
1324 case SPIRV::OpAtomicStore: {
1333 Incomplete = isTodoType(
Op);
1334 Ops.push_back(std::make_pair(
Op, 0));
1343void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1345 Type *&KnownElemTy,
bool IsPostprocessing) {
1349 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1350 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1351 bool IsNewFTy =
false, IsIncomplete =
false;
1354 Type *ArgTy = Arg->getType();
1359 if (isTodoType(Arg))
1360 IsIncomplete =
true;
1362 IsIncomplete =
true;
1365 ArgTy = FTy->getFunctionParamType(ParmIdx);
1369 Type *RetTy = FTy->getReturnType();
1376 IsIncomplete =
true;
1378 IsIncomplete =
true;
1381 if (!IsPostprocessing && IsIncomplete)
1384 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1387bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1388 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1389 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1401 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1402 for (User *U :
F->users()) {
1411 propagateElemType(CI, PrevElemTy, VisitedSubst);
1421 for (Instruction *IncompleteRetI : *IncompleteRets)
1422 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1424 }
else if (IncompleteRets) {
1435void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1436 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1437 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1439 Type *KnownElemTy =
nullptr;
1440 bool Incomplete =
false;
1446 Incomplete = isTodoType(
I);
1447 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1450 Ops.push_back(std::make_pair(
Op, i));
1456 Incomplete = isTodoType(
I);
1457 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1464 Incomplete = isTodoType(
I);
1465 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1469 KnownElemTy =
Ref->getSourceElementType();
1470 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1475 KnownElemTy =
Ref->getBaseType();
1476 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1479 KnownElemTy =
I->getType();
1486 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1495 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1499 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1504 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1512 Incomplete = isTodoType(
Ref->getPointerOperand());
1513 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1521 Incomplete = isTodoType(
Ref->getPointerOperand());
1522 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1528 Incomplete = isTodoType(
I);
1529 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1532 Ops.push_back(std::make_pair(
Op, i));
1540 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1541 IsPostprocessing, KnownElemTy,
Op,
1544 Incomplete = isTodoType(CurrF);
1545 Ops.push_back(std::make_pair(
Op, 0));
1551 bool Incomplete0 = isTodoType(Op0);
1552 bool Incomplete1 = isTodoType(Op1);
1554 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1556 : GR->findDeducedElementType(Op0);
1558 KnownElemTy = ElemTy0;
1559 Incomplete = Incomplete0;
1560 Ops.push_back(std::make_pair(Op1, 1));
1561 }
else if (ElemTy1) {
1562 KnownElemTy = ElemTy1;
1563 Incomplete = Incomplete1;
1564 Ops.push_back(std::make_pair(Op0, 0));
1568 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1569 else if (HaveFunPtrs)
1570 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1575 if (!KnownElemTy ||
Ops.size() == 0)
1579 for (
auto &OpIt :
Ops) {
1583 Type *AskTy =
nullptr;
1584 CallInst *AskCI =
nullptr;
1585 if (IsPostprocessing && AskOps) {
1591 if (Ty == KnownElemTy)
1594 Type *OpTy =
Op->getType();
1600 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1608 else if (!IsPostprocessing)
1612 if (AssignCI ==
nullptr) {
1621 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1622 std::make_pair(
I,
Op)};
1623 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1634 CallInst *PtrCastI =
1635 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1636 if (OpIt.second == std::numeric_limits<unsigned>::max())
1639 I->setOperand(OpIt.second, PtrCastI);
1646 if (RevalidatingRetyped)
1648 RevalidatingRetyped =
true;
1649 while (!RetypedToRevalidate.
empty())
1650 deduceOperandElementType(RetypedToRevalidate.
pop_back_val(),
nullptr,
1651 nullptr, IsPostprocessing);
1652 RevalidatingRetyped =
false;
1655void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1660 if (isAssignTypeInstr(U)) {
1661 B.SetInsertPoint(U);
1662 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1663 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1664 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1666 U->eraseFromParent();
1669 U->replaceUsesOfWith(Old, New);
1677 Type *NewArgTy =
New->getType();
1679 if (NewArgTy != ExpectedArgTy) {
1682 M, Intrinsic::spv_abort, {NewArgTy});
1692 "aggregate PHI/select/freeze should have been mutated to value-id "
1694 U->replaceUsesOfWith(Old, New);
1699 New->copyMetadata(*Old);
1701 TypeValidated.
erase(Old);
1707 bool HasPoisonExt) {
1714 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1715 "lowered as undef\n");
1717 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1718 Type *Ty = UV->getType();
1724 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1725 :
B.CreateIntrinsicWithoutFolding(IID, {});
1726 AggrConsts[
Call] = UV;
1727 AggrConstTypes[
Call] = Ty;
1732 return B.CreateIntrinsic(IID, {Ty}, {});
1739void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1744 SmallVector<Instruction *, 16> Insts;
1748 for (Instruction *
I : Insts) {
1749 bool BPrepared =
false;
1751 for (
unsigned Idx = 0;
Idx <
I->getNumOperands(); ++
Idx) {
1755 bool IsScalar = !
Op->getType()->isAggregateType();
1758 if (IsScalar && !AsPoison)
1762 if (IsScalar && Phi)
1763 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1764 else if (!BPrepared) {
1768 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1769 I->setOperand(Idx, Repl);
1778void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1782 ASC->replaceAllUsesWith(
1784 ASC->eraseFromParent();
1792 if (!
V->getType()->isAggregateType())
1801 I.getType()->isAggregateType();
1807void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1810 for (Use &U :
I->operands()) {
1817 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1822 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1824 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1830void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1834 std::queue<Instruction *> Worklist;
1838 while (!Worklist.empty()) {
1839 auto *
I = Worklist.front();
1842 bool KeepInst =
false;
1843 for (
const auto &
Op :
I->operands()) {
1845 Type *ResTy =
nullptr;
1848 ResTy = COp->getType();
1860 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1863 auto PrepareInsert = [&]() {
1866 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1867 :
B.SetInsertPoint(
I);
1872 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1873 Args.push_back(COp->getElementAsConstant(i));
1879 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1888 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1894 auto *CI =
B.CreateIntrinsicWithoutFolding(
1895 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1899 AggrConsts[CI] = AggrConst;
1900 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1912 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1917 unsigned RoundingModeDeco,
1924 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1933 MDNode *SaturatedConversionNode =
1935 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1955 MDString *ConstraintString =
1960 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1964 B.SetInsertPoint(&
Call);
1965 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1970void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1973 if (!
RM.has_value())
1975 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1976 switch (
RM.value()) {
1980 case RoundingMode::NearestTiesToEven:
1981 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1983 case RoundingMode::TowardNegative:
1984 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1986 case RoundingMode::TowardPositive:
1987 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1989 case RoundingMode::TowardZero:
1990 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1992 case RoundingMode::Dynamic:
1993 case RoundingMode::NearestTiesToAway:
1997 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
2003Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
2007 B.SetInsertPoint(&
I);
2008 SmallVector<Value *, 4>
Args;
2010 Args.push_back(
I.getCondition());
2013 for (
auto &Case :
I.cases()) {
2014 Args.push_back(Case.getCaseValue());
2015 BBCases.
push_back(Case.getCaseSuccessor());
2018 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2019 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
2023 I.eraseFromParent();
2026 B.SetInsertPoint(ParentBB);
2027 IndirectBrInst *BrI =
B.CreateIndirectBr(
2030 for (BasicBlock *BBCase : BBCases)
2039Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
2045 B.SetInsertPoint(&
I);
2047 SmallVector<Value *, 4>
Args;
2048 Args.push_back(
B.getInt1(
true));
2049 Args.push_back(
I.getOperand(0));
2050 Args.push_back(
B.getInt32(0));
2051 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
2052 Args.push_back(SGEP->getIndexOperand(J));
2055 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
2056 replaceAllUsesWithAndErase(
B, &
I, NewI);
2061SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2063 B.SetInsertPoint(&
I);
2068 unsigned N = RetVTy->getNumElements();
2069 Value *PtrOp =
I.getPointerOperand();
2071 Type *ResultPtrTy = RetVTy->getElementType();
2074 Value *InBounds =
B.getInt1(
I.isInBounds());
2075 Type *LanePointeeTy = getGEPType(&
I);
2076 Type *SrcElemTy =
I.getSourceElementType();
2085 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2086 Value *LaneIdx =
B.getInt32(Lane);
2087 Value *ScalarPtr = PtrOp;
2091 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2095 SmallVector<Value *, 4>
Args;
2096 Args.push_back(InBounds);
2097 Args.push_back(ScalarPtr);
2098 for (
Value *Idx :
I.indices()) {
2106 Args.push_back(visitExtractElementInst(*EI));
2110 Args.push_back(Idx);
2113 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2115 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2119 replaceAllUsesWithAndErase(
B, &
I, NewI);
2137 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2138 return buildLogicalAccessChainFromGEP(
I);
2143 Value *PtrOp =
I.getPointerOperand();
2144 Type *SrcElemTy =
I.getSourceElementType();
2145 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2148 if (ArrTy->getElementType() == SrcElemTy) {
2150 Type *FirstIdxType =
I.getOperand(1)->getType();
2151 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2152 for (
Value *Idx :
I.indices())
2156 SmallVector<Value *, 4>
Args;
2157 Args.push_back(
B.getInt1(
I.isInBounds()));
2158 Args.push_back(
I.getPointerOperand());
2161 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2163 replaceAllUsesWithAndErase(
B, &
I, NewI);
2170 SmallVector<Value *, 4>
Args;
2171 Args.push_back(
B.getInt1(
I.isInBounds()));
2174 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2175 replaceAllUsesWithAndErase(
B, &
I, NewI);
2179Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2181 B.SetInsertPoint(&
I);
2190 I.eraseFromParent();
2197 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2198 replaceAllUsesWithAndErase(
B, &
I, NewI);
2202void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2209 if (ElemTy != AssignedType)
2222 if (CurrentType == AssignedType)
2229 " for value " +
V->getName(),
2238void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2239 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2244 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2245 if (PointerElemTy == ExpectedElementType ||
2250 Value *ExpectedElementVal =
2252 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2254 bool FirstPtrCastOrAssignPtrType =
true;
2260 for (
auto User :
Pointer->users()) {
2263 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2264 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2265 II->getOperand(0) != Pointer)
2270 FirstPtrCastOrAssignPtrType =
false;
2271 if (
II->getOperand(1) != VMD ||
2278 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2283 if (
II->getParent() !=
I->getParent())
2286 I->setOperand(OperandToReplace,
II);
2301 if (FirstPtrCastOrAssignPtrType) {
2306 }
else if (isTodoType(Pointer)) {
2307 eraseTodoType(Pointer);
2315 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2316 std::make_pair(
I, Pointer)};
2318 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2331 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
2337void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2342 replacePointerOperandWithPtrCast(
2343 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2349 Type *OpTy =
Op->getType();
2352 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2355 if (OpTy ==
Op->getType())
2356 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2357 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2362 Type *OpTy = LI->getType();
2373 Type *NewOpTy = OpTy;
2374 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2375 if (OpTy == NewOpTy)
2376 insertTodoType(Pointer);
2379 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2384 Type *OpTy =
nullptr;
2396 OpTy = GEPI->getSourceElementType();
2398 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2400 insertTodoType(Pointer);
2406 Value *
Op = IVI->getInsertedValueOperand();
2408 replacePointerOperandWithPtrCast(
2422 std::string DemangledName =
2426 bool HaveTypes =
false;
2427 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2445 for (User *U : CalledArg->
users()) {
2447 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2453 HaveTypes |= ElemTy !=
nullptr;
2458 if (DemangledName.empty() && !HaveTypes)
2462 TM.
getSubtarget<SPIRVSubtarget>(*CalledF).getPreferredInstructionSet();
2464 bool ParseBuiltinTypes =
2465 !DemangledName.empty() &&
2466 (!CalledF->
isDeclaration() || SPIRV::isBuiltin(DemangledName, Set));
2467 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2482 Type *ExpectedType =
2483 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2484 if (!ExpectedType && ParseBuiltinTypes)
2485 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2486 DemangledName, OpIdx,
I->getContext());
2487 if (!ExpectedType || ExpectedType->
isVoidTy())
2495 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2500SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2503 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2507 I.getOperand(1)->getType(),
2508 I.getOperand(2)->getType()};
2510 B.SetInsertPoint(&
I);
2512 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2514 replaceAllUsesWithAndErase(
B, &
I, NewI);
2519SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2522 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2526 B.SetInsertPoint(&
I);
2528 I.getIndexOperand()->getType()};
2529 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2530 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2532 replaceAllUsesWithAndErase(
B, &
I, NewI);
2536Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2538 B.SetInsertPoint(&
I);
2541 Value *AggregateOp =
I.getAggregateOperand();
2545 Args.push_back(AggregateOp);
2546 Args.push_back(
I.getInsertedValueOperand());
2547 for (
auto &
Op :
I.indices())
2548 Args.push_back(
B.getInt32(
Op));
2550 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2551 replaceMemInstrUses(&
I, NewI,
B);
2556SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2558 B.SetInsertPoint(&
I);
2559 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2568 for (
auto &
Op :
I.indices())
2569 Args.push_back(
B.getInt32(
Op));
2570 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2571 {
I.getType()}, {
Args});
2577 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2578 AggrConstTypes[NewI] =
I.getType();
2580 replaceMemInstrUses(&
I, NewI,
B);
2583 replaceAllUsesWithAndErase(
B, &
I, NewI);
2587 for (
const Use &U : NewI->
uses()) {
2588 User *Usr =
U.getUser();
2590 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2601 if (ArgNo < FT->getNumParams() &&
2602 !FT->getParamType(ArgNo)->isAggregateType()) {
2611Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2612 if (!
I.getType()->isAggregateType())
2615 B.SetInsertPoint(&
I);
2616 TrackConstants =
false;
2621 unsigned IntrinsicId;
2622 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2623 if (!
I.isAtomic()) {
2624 IntrinsicId = Intrinsic::spv_load;
2625 Args.push_back(
B.getInt32(
I.getAlign().value()));
2627 IntrinsicId = Intrinsic::spv_atomic_load;
2628 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2630 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2631 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2633 replaceMemInstrUses(&
I, NewI,
B);
2637Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2641 B.SetInsertPoint(&
I);
2642 TrackConstants =
false;
2646 auto *PtrOp =
I.getPointerOperand();
2648 if (
I.getValueOperand()->getType()->isAggregateType()) {
2656 "Unexpected argument of aggregate type, should be spv_extractv!");
2660 unsigned IntrinsicId;
2661 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2663 if (!
I.isAtomic()) {
2664 IntrinsicId = Intrinsic::spv_store;
2665 Args.push_back(
B.getInt32(
I.getAlign().value()));
2667 IntrinsicId = Intrinsic::spv_atomic_store;
2668 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2671 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2673 I.eraseFromParent();
2677Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2678 Value *ArraySize =
nullptr;
2679 if (
I.isArrayAllocation()) {
2682 SPIRV::Extension::SPV_INTEL_variable_length_array))
2684 "array allocation: this instruction requires the following "
2685 "SPIR-V extension: SPV_INTEL_variable_length_array",
2687 ArraySize =
I.getArraySize();
2690 B.SetInsertPoint(&
I);
2691 TrackConstants =
false;
2692 Type *PtrTy =
I.getType();
2695 ?
B.CreateIntrinsicWithoutFolding(
2696 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2697 {ArraySize,
B.getInt32(
I.getAlign().value())})
2698 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2699 {
B.getInt32(
I.getAlign().value())});
2700 replaceAllUsesWithAndErase(
B, &
I, NewI);
2705SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2706 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2708 B.SetInsertPoint(&
I);
2711 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2715 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2716 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2717 uint32_t ScSem =
static_cast<uint32_t
>(
2726 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2727 replaceMemInstrUses(&
I, NewI,
B);
2731Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &
I) {
2732 auto Op =
I.getOperation();
2743 B.SetInsertPoint(&
I);
2745 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2746 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2748 uint32_t
Scope =
static_cast<uint32_t
>(
2749 getMemScope(
M->getTargetTriple(),
I.getContext(),
I.getSyncScopeID()));
2750 uint32_t ScSem =
static_cast<uint32_t
>(
2753 M->getTargetTriple(),
2757 ?
"__translate_spirv_atomic_uinc_wrap"
2758 :
"__translate_spirv_atomic_udec_wrap");
2760 Type *ValTy =
I.getValOperand()->getType();
2761 Type *PtrTy =
I.getPointerOperand()->getType();
2763 raw_svector_ostream OS(FuncName);
2764 OS <<
"_p" << AS <<
"_";
2766 OS <<
"v" << VecTy->getNumElements();
2769 Type *Int32Ty =
B.getInt32Ty();
2770 Type *BoolTy =
B.getInt1Ty();
2772 ValTy, BoolTy, BoolTy};
2773 FunctionType *FT = FunctionType::get(ValTy, ArgTys,
false);
2774 FunctionCallee
FC =
M->getOrInsertFunction(FuncName, FT);
2778 I.getPointerOperand(),
B.getInt32(Scope),
2779 B.getInt32(MemSem),
I.getValOperand(),
2780 B.getInt1(
I.isVolatile()),
B.getInt1(
I.isElementwise())};
2781 CallInst *CI =
B.CreateCall(FC, Args);
2787 replaceAllUsesWithAndErase(
B, &
I, CI);
2796 case Intrinsic::spv_abort:
2798 case Intrinsic::trap:
2799 case Intrinsic::ubsantrap:
2801 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2817 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2818 "abort-like call must be the last non-debug instruction before its "
2819 "block's terminator");
2823Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2824 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2828 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2835 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2849 while (!Stack.empty()) {
2850 const Value *
V = Stack.pop_back_val();
2851 if (!Visited.
insert(
V).second)
2859 Stack.append(
C->user_begin(),
C->user_end());
2875 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2876 if (UserFunctions.contains(
F))
2881 if (!UserFunctions.empty())
2886 const Module &M = *
F->getParent();
2887 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2888 return F == &FirstDefinition;
2891Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2893 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2894 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2896 AggrConstTypes[Leaf] = ElemTy;
2899 SmallVector<Value *, 4> Elems;
2901 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2904 DenseMap<Type *, Instruction *> LeafByType;
2905 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2907 auto &
Entry = LeafByType[ElemTy];
2909 Entry = MakeLeaf(ElemTy);
2913 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2914 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2916 AggrConstTypes[Composite] = AggrTy;
2925void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2930 for (BasicBlock &BB : Func) {
2934 Value *RetVal = RI->getReturnValue();
2941 B.SetInsertPoint(RI);
2944 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2945 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2947 RI->setOperand(0, Rebuilt);
2951void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2961 deduceElementTypeHelper(&GV,
false);
2966 Value *InitOp = Init;
2973 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2974 {
B.getInt32Ty()}, {});
2979 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2984 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2985 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2991 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2997bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2999 bool UnknownElemTypeI8) {
3005 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
3012void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
3015 static StringMap<unsigned> ResTypeWellKnown = {
3016 {
"async_work_group_copy", WellKnownTypes::Event},
3017 {
"async_work_group_strided_copy", WellKnownTypes::Event},
3018 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
3022 bool IsKnown =
false;
3027 std::string DemangledName =
3030 if (DemangledName.length() > 0)
3032 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
3033 auto ResIt = ResTypeWellKnown.
find(DemangledName);
3034 if (ResIt != ResTypeWellKnown.
end()) {
3037 switch (ResIt->second) {
3038 case WellKnownTypes::Event:
3041 CanUseAnyVectorRank);
3046 switch (DecorationId) {
3049 case FPDecorationId::SAT:
3052 case FPDecorationId::RTE:
3054 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
3056 case FPDecorationId::RTZ:
3058 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
3060 case FPDecorationId::RTP:
3062 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
3064 case FPDecorationId::RTN:
3066 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
3072 Type *Ty =
I->getType();
3075 Type *TypeToAssign = Ty;
3078 auto It = AggrConstTypes.
find(
II);
3079 if (It == AggrConstTypes.
end())
3081 TypeToAssign = It->second;
3082 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
3083 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
3084 TypeToAssign = It->second;
3086 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
3087 TypeToAssign = It->second;
3091 for (
const auto &
Op :
I->operands()) {
3099 Type *OpTy =
Op->getType();
3101 CallInst *AssignCI =
3106 Type *OpTy =
Op->getType();
3122 Intrinsic::spv_assign_type, {OpTy},
3132bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
3133 Instruction *Inst) {
3135 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3145void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3147 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3149 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3154 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3155 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3156 if (shouldTryToAddMemAliasingDecoration(
I)) {
3157 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3158 ? SPIRV::Decoration::AliasScopeINTEL
3159 : SPIRV::Decoration::NoAliasINTEL;
3161 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3164 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3165 {
I->getType()}, {
Args});
3169 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3170 processMemAliasingDecoration(LLVMContext::MD_noalias);
3173 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3175 bool AllowFPMaxError =
3177 if (!AllowFPMaxError)
3181 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3187 LLVMContext &Ctx =
B.getContext();
3189 B.getInt32Ty(), SPIRV::Decoration::AuxDataInstructionMetadata));
3192 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3194 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3195 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3197 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.remote.memory")}));
3198 if (
I->hasMetadata(LLVMContext::MD_atomic_ignore_denormal_mode))
3200 Ctx, {AuxMD,
MDString::get(Ctx,
"atomic.ignore.denormal.mode")}));
3203 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3212 &FPFastMathDefaultInfoMap,
3214 auto it = FPFastMathDefaultInfoMap.
find(
F);
3215 if (it != FPFastMathDefaultInfoMap.
end())
3223 SPIRV::FPFastMathMode::None);
3225 SPIRV::FPFastMathMode::None);
3227 SPIRV::FPFastMathMode::None);
3228 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3234 size_t BitWidth = Ty->getScalarSizeInBits();
3238 assert(Index >= 0 && Index < 3 &&
3239 "Expected FPFastMathDefaultInfo for half, float, or double");
3240 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3241 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3242 return FPFastMathDefaultInfoVec[Index];
3245void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3247 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3256 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3258 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3266 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3269 [[maybe_unused]] GlobalVariable *GV =
3270 new GlobalVariable(M,
3271 Type::getInt32Ty(
M.getContext()),
3285 MapVector<Function *, SPIRV::FPFastMathDefaultInfoVector>
3286 FPFastMathDefaultInfoMap;
3288 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3297 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3299 "Expected 4 operands for FPFastMathDefault");
3305 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3307 SPIRV::FPFastMathDefaultInfo &
Info =
3310 Info.FPFastMathDefault =
true;
3311 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3313 "Expected no operands for ContractionOff");
3317 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3319 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3320 Info.ContractionOff =
true;
3322 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3324 "Expected 1 operand for SignedZeroInfNanPreserve");
3325 unsigned TargetWidth =
3330 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3334 assert(Index >= 0 && Index < 3 &&
3335 "Expected FPFastMathDefaultInfo for half, float, or double");
3336 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3337 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3338 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3342 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3343 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3344 if (FPFastMathDefaultInfoVec.
empty())
3347 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3348 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3351 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3352 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3356 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3358 "and AllowContract");
3360 if (
Info.SignedZeroInfNanPreserve &&
3362 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3363 SPIRV::FPFastMathMode::NSZ))) {
3364 if (
Info.FPFastMathDefault)
3366 "SignedZeroInfNanPreserve but at least one of "
3367 "NotNaN/NotInf/NSZ is enabled.");
3370 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3371 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3372 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3374 "AllowTransform requires AllowReassoc and "
3375 "AllowContract to be set.");
3378 auto it = GlobalVars.
find(Flags);
3379 GlobalVariable *GV =
nullptr;
3380 if (it != GlobalVars.
end()) {
3386 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3389 GV =
new GlobalVariable(M,
3390 Type::getInt32Ty(
M.getContext()),
3395 GlobalVars[
Flags] = GV;
3401void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3404 bool IsConstComposite =
3405 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3406 if (IsConstComposite && TrackConstants) {
3408 auto t = AggrConsts.
find(
I);
3412 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3414 NewOp->setArgOperand(0,
I);
3417 for (
const auto &
Op :
I->operands()) {
3421 unsigned OpNo =
Op.getOperandNo();
3422 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3423 (!
II->isBundleOperand(OpNo) &&
3424 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3428 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3429 :
B.SetInsertPoint(
I);
3432 Type *OpTy =
Op->getType();
3440 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3442 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3443 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3445 SmallVector<Value *, 2>
Args = {
3449 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3455 I->setOperand(OpNo, NewOp);
3461Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3463 SmallPtrSet<Function *, 0> FVisited;
3464 return deduceFunParamElementType(
F, OpIdx, FVisited);
3467Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3468 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3470 if (!FVisited.
insert(
F).second)
3473 SmallPtrSet<Value *, 0> Visited;
3476 for (User *U :
F->users()) {
3478 if (!CI || OpIdx >= CI->
arg_size())
3488 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3491 for (User *OpU : OpArg->
users()) {
3493 if (!Inst || Inst == CI)
3496 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3503 if (FVisited.
find(OuterF) != FVisited.
end())
3505 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3506 if (OuterF->
getArg(i) == OpArg) {
3507 Lookup.push_back(std::make_pair(OuterF, i));
3514 for (
auto &Pair :
Lookup) {
3515 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3522void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3524 B.SetInsertPointPastAllocas(
F);
3525 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3531 for (User *U : Arg->
users()) {
3533 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3551 for (User *U :
F->users()) {
3553 if (!CI || OpIdx >= CI->
arg_size())
3567 for (User *U : Arg->
users()) {
3571 CI->
getParent()->getParent() == CurrF) {
3573 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3585 B.SetInsertPointPastAllocas(
F);
3586 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3591 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3593 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3597 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3609 bool IsNewFTy =
false;
3625bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3628 if (
F.isIntrinsic())
3630 if (
F.isDeclaration()) {
3631 for (User *U :
F.users()) {
3634 UF &&
UF->hasPersonalityFn() &&
UF->getPersonalityFn() == &
F)
3648 for (User *U :
F.users()) {
3650 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3652 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3653 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3661 if (Worklist.
empty())
3664 LLVMContext &Ctx =
M.getContext();
3671 for (
const auto &Arg :
F->args())
3674 IRB.CreateCall(
F, Args);
3676 IRB.CreateRetVoid();
3682void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3683 DenseMap<Function *, CallInst *> Ptrcasts;
3684 for (
auto It : FDeclPtrTys) {
3686 for (
auto *U :
F->users()) {
3691 for (
auto [Idx, ElemTy] : It.second) {
3699 B.SetInsertPointPastAllocas(Arg->
getParent());
3706 replaceUsesOfWithSpvPtrcast(
3707 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3716 .getFirstNonPHIOrAlloca());
3734 FDeclPtrTys.
clear();
3737GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3738 GetElementPtrInst *
GEP) {
3745 Type *SrcTy =
GEP->getSourceElementType();
3746 SmallVector<Value *, 8> Indices(
GEP->indices());
3748 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3749 Indices.erase(Indices.begin());
3750 SrcTy = ArrTy->getElementType();
3752 GEP->getNoWrapFlags(),
"",
3753 GEP->getIterator());
3758void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3765 if (
ST->canUseExtension(
3766 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3767 for (BasicBlock &BB :
F) {
3769 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3773 SmallVector<unsigned, 1>
Ops =
3775 unsigned LC =
Ops[0];
3776 if (LC == SPIRV::LoopControl::None)
3780 B.SetInsertPoint(Term);
3781 SmallVector<Value *, 4> IntrArgs;
3782 for (
unsigned Op :
Ops)
3784 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3796 SmallPtrSet<BasicBlock *, 8> UsedMergeBlocks;
3803 SmallVector<unsigned, 1> LoopControlOps =
3805 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3818 for (BasicBlock *BB : {Latch, Header}) {
3822 if (!
L->contains(Succ) && !UsedMergeBlocks.
contains(Succ))
3825 if (!MergeBlock || !UsedMergeBlocks.
insert(MergeBlock).second)
3828 B.SetInsertPoint(Header->getTerminator());
3831 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3832 for (
unsigned Imm : LoopControlOps)
3833 Args.emplace_back(
B.getInt32(
Imm));
3834 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3838bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3839 if (
Func.isDeclaration())
3848 GR =
ST.getSPIRVGlobalRegistry();
3852 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3854 CanUseAnyVectorRank =
3855 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3859 AggrConstTypes.
clear();
3862 processParamTypesByFunHeader(CurrF,
B);
3866 SmallPtrSet<Instruction *, 4> DeadInsts;
3869 Type *ElTy =
SI->getValueOperand()->getType();
3884 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3888 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3890 GEP->replaceAllUsesWith(NewGEP);
3894 if (
Type *GepTy = getGEPType(
GEP))
3898 for (
auto *
I : DeadInsts) {
3899 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3900 I->eraseFromParent();
3903 B.SetInsertPoint(
Func.getEntryBlock().begin());
3904 for (
auto &GV :
Func.getParent()->globals())
3905 processGlobalValue(GV,
B);
3907 reconstructAggregateReturns(Func,
B);
3908 preprocessUndefsAndPoisons(
B);
3909 simplifyNullAddrSpaceCasts();
3910 preprocessCompositeConstants(
B);
3918 Type *I32Ty =
B.getInt32Ty();
3923 insertCompositeAggregateArms(&
I,
B);
3924 AggrConstTypes[&
I] =
I.getType();
3925 I.mutateType(I32Ty);
3928 preprocessBoolVectorBitcasts(Func);
3929 SmallVector<Instruction *> Worklist(
3932 applyDemangledPtrArgTypes(
B);
3935 for (
auto &
I : Worklist) {
3937 if (isConvergenceIntrinsic(
I))
3940 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3942 insertAssignTypeIntrs(
I,
B);
3943 insertPtrCastOrAssignTypeInstr(
I,
B);
3948 insertAssignPtrTypeIntrs(
I,
B,
true);
3951 useRoundingMode(FPI,
B);
3956 SmallPtrSet<Instruction *, 4> IncompleteRets;
3958 deduceOperandElementType(&
I, &IncompleteRets);
3962 for (BasicBlock &BB : Func)
3963 for (PHINode &Phi : BB.
phis())
3965 deduceOperandElementType(&Phi,
nullptr);
3967 for (
auto *
I : Worklist) {
3968 TrackConstants =
true;
3978 if (isConvergenceIntrinsic(
I))
3982 processInstrAfterVisit(
I,
B);
3985 emitUnstructuredLoopControls(Func,
B);
3991bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3992 if (!GR || TodoTypeSz == 0)
3995 unsigned SzTodo = TodoTypeSz;
3996 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
4003 if (!KnownTy || !AssignCI)
4009 SmallPtrSet<Value *, 0> Visited;
4010 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
4011 if (ElemTy != KnownTy) {
4012 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
4013 propagateElemType(CI, ElemTy, VisitedSubst);
4020 if (
Op->hasUseList()) {
4021 for (User *U :
Op->users()) {
4028 if (TodoTypeSz == 0)
4033 SmallPtrSet<Instruction *, 4> IncompleteRets;
4035 auto It = ToProcess.
find(&
I);
4036 if (It == ToProcess.
end())
4038 It->second.remove_if([
this](
Value *
V) {
return !isTodoType(
V); });
4039 if (It->second.size() == 0)
4041 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
4042 if (TodoTypeSz == 0)
4047 return SzTodo > TodoTypeSz;
4061 .Cases({
"char",
"signed char",
"unsigned char",
"short",
4062 "unsigned short",
"int",
"unsigned int",
"_Float16",
"float",
4070 unsigned NumElts = 0;
4071 if (
Count.getAsInteger(10, NumElts) || NumElts == 0)
4078 TypeStr.
split(Quals,
' ', -1,
false);
4081 if (Qual !=
"const" && Qual !=
"volatile" && Qual !=
"restrict" &&
4082 !(Qual.consume_front(
"AS") && !Qual.getAsInteger(10, AS)))
4089void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
4091 if (!
F.isDeclaration() ||
F.isIntrinsic())
4094 if (DemangledName.empty())
4097 auto Set =
ST.getPreferredInstructionSet();
4098 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(DemangledName, Set);
4100 const bool IsBuiltin = Grp >= 0 || SPIRV::isBuiltin(DemangledName, Set);
4101 if (IsBuiltin && Opcode != SPIRV::OpGroupAsyncCopy)
4103 SmallVector<unsigned> Idxs;
4104 for (Argument &Arg :
F.args())
4109 LLVMContext &Ctx =
F.getContext();
4111 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
4112 if (TypeStrs.
empty())
4115 if (!IsBuiltin && (!
F.getName().starts_with(
"_Z") ||
F.hasStructRetAttr() ||
4116 StringRef(DemangledName).
count(
'(') != 1 ||
4117 StringRef(DemangledName).
count(
')') != 1 ||
4118 StringRef(DemangledName).
contains(
'<') ||
4119 TypeStrs.
size() !=
F.arg_size()))
4121 bool AllowLongVectors =
4122 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
4123 for (
unsigned Idx : Idxs) {
4124 if (Idx >= TypeStrs.
size())
4126 StringRef TypeStr = TypeStrs[
Idx].trim();
4127 Type *ElemTy = IsBuiltin
4128 ? SPIRV::parseBuiltinCallArgumentType(TypeStr, Ctx)
4138 FDeclPtrTys[&
F].emplace_back(Idx, ElemTy);
4140 ST.getSPIRVGlobalRegistry()->addDeducedElementType(
F.getArg(Idx),
4146bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
4147 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
4149 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
4150 if (!
ST.canUseExtension(
4151 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4152 I.getContext().emitError(
4153 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
4157 I.eraseFromParent();
4163 Value *Ptrs =
I.getArgOperand(0);
4165 Value *Passthru =
I.getArgOperand(2);
4168 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
4170 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
4175 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
4177 I.eraseFromParent();
4181 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
4182 if (!
ST.canUseExtension(
4183 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4184 I.getContext().emitError(
4185 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
4188 I.eraseFromParent();
4195 Value *Ptrs =
I.getArgOperand(1);
4200 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
4202 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
4206 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
4207 I.eraseFromParent();
4218void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
4219 struct BoolVecBitcast {
4221 FixedVectorType *BoolVecTy;
4225 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4227 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4235 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4237 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4241 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4243 Value *Src = BC->getOperand(0);
4244 unsigned BoolVecN = BoolVecTy->getNumElements();
4247 Type *OtherTy = SrcIsBoolVec ? BC->getDestTy() : Src->getType();
4248 unsigned NumElts = 1;
4250 NumElts = VTy->getNumElements();
4256 if (!SrcIsBoolVec) {
4259 auto GetLane = [&](
unsigned I) {
4262 Elt =
B.CreateExtractElement(IntVal,
B.getInt32(
I / EltBits));
4266 return B.CreateICmpNE(
And, ConstantInt::get(EltTy, 0));
4274 if (!Idx ||
Idx->getValue().uge(BoolVecN))
4276 B.SetInsertPoint(EE);
4277 EE->replaceAllUsesWith(GetLane(
Idx->getZExtValue()));
4278 EE->eraseFromParent();
4280 if (BC->use_empty()) {
4281 BC->eraseFromParent();
4285 B.SetInsertPoint(BC);
4287 for (
unsigned I = 0;
I < BoolVecN; ++
I)
4288 Result =
B.CreateInsertElement(Result, GetLane(
I),
B.getInt32(
I));
4292 for (
unsigned J = 0; J < NumElts; ++J) {
4293 Value *Elt = ConstantInt::get(EltTy, 0);
4294 for (
unsigned Bit = 0;
Bit < EltBits; ++
Bit) {
4296 B.CreateExtractElement(Src,
B.getInt32(J * EltBits + Bit));
4297 Value *Ext =
B.CreateZExt(Lane, EltTy);
4299 Ext =
B.CreateShl(Ext, ConstantInt::get(EltTy, Bit));
4300 Elt =
B.CreateOr(Elt, Ext);
4302 IntVal = NumElts > 1 ?
B.CreateInsertElement(IntVal, Elt,
B.getInt32(J))
4305 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4308 BC->replaceAllUsesWith(Result);
4309 BC->eraseFromParent();
4313bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4317 if (!
F.isIntrinsic())
4320 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4325 Changed |= processMaskedMemIntrinsic(*
II);
4329 F.eraseFromParent();
4335bool SPIRVEmitIntrinsicsImpl::foldStaticArrayAllocas(
Module &M) {
4337 Type *I32Ty = Type::getInt32Ty(
M.getContext());
4339 if (
F.isDeclaration())
4344 for (Instruction &
I :
F.getEntryBlock()) {
4346 if (!AI || !AI->isStaticAlloca() || !AI->isArrayAllocation() ||
4347 AI->getAddressSpace() !=
4352 if (
Count->isZero() || !
Count->getValue().isIntN(32))
4354 AI->setAllocatedType(
4355 ArrayType::get(AI->getAllocatedType(),
Count->getZExtValue()));
4356 AI->setOperand(0, ConstantInt::get(I32Ty, 1));
4363bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4365 bool Changed = foldStaticArrayAllocas(M);
4366 Changed |= convertMaskedMemIntrinsics(M);
4368 parseFunDeclarations(M);
4369 insertConstantsForFPFastMathDefault(M);
4380 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4382 processParamTypes(&
F,
B);
4386 CanTodoType =
false;
4387 Changed |= postprocessTypes(M);
4390 Changed |= processFunctionPointers(M);
4397 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4403 return new SPIRVEmitIntrinsicsLegacy(TM);
const TargetLowering & TLI
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
This file implements a map that provides insertion order iteration.
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 Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, MapVector< Function *, SPIRV::FPFastMathDefaultInfoVector > &FPFastMathDefaultInfoMap, Function *F)
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 void emitAssignName(const SPIRVOptions &CLOpts, Instruction *I, 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 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 Type * getMemberPointeeType(Type *AggrTy, ArrayRef< unsigned > Indices)
static bool precededByAbortIntrinsic(const UnreachableInst &I, const SPIRVSubtarget &ST)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static bool isMultiRegisterAggregate(Value *V)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static Type * parseDeclPtrElemType(StringRef TypeStr, LLVMContext &Ctx)
static bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the SmallPtrSet class.
This file defines the SmallString class.
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
static SymbolRef::Type getType(const Symbol *Sym)
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
This class represents an incoming formal argument to a Function.
const Function * getParent() const
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
@ UIncWrap
Increment one up to a maximum value.
@ UDecWrap
Decrement one until a minimum value or zero.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
static LLVM_ABI BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
bool isInlineAsm() const
Check if this call is an inline asm statement.
void setCallingConv(CallingConv::ID CC)
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI std::optional< RoundingMode > getRoundingMode() const
uint64_t getNumOperands() const
unsigned getProgramAddressSpace() const
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Type * getParamType(unsigned i) const
Parameter type accessors.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Type * getReturnType() const
Returns the type of the ret val.
Argument * getArg(unsigned i) const
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static LLVM_ABI Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static unsigned getPointerOperandIndex()
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Module * getParent()
Get the module that this global value is contained inside of...
PointerType * getType() const
Global values are always pointers.
@ InternalLinkage
Rename collisions when linking (static functions).
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI void addDestination(BasicBlock *Dest)
Add a destination.
static unsigned getInsertedValueOperandIndex()
Base class for instruction visitors.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
static unsigned getPointerOperandIndex()
SmallVector< LoopT *, 4 > getLoopsInPreorder() const
Return all of the loops in the function in preorder across the loop nests, with siblings in forward p...
void analyze(ParentT F)
Create the loop forest for a function.
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Flags
Flags values. These may be or'd together.
This class implements a map that also provides access to all stored values in a deterministic order.
iterator find(const KeyT &Key)
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)
void removeAssignPtrTypeInstr(Value *OldVal)
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 SPIRVOptions & getCLOpts() const
const SPIRVSubtarget * getSubtargetImpl() const
bool erase(PtrType Ptr)
Remove pointer from the set.
iterator find(ConstPtrType Ptr) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator find(StringRef Key)
Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
Check if the string is empty.
constexpr size_t size() const
Get the string size.
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
A switch()-like statement whose cases are string literals.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
MachineMemOperand::Flags getLoadMemOperandFlags(const LoadInst &LI, const DataLayout &DL, AssumptionCache *AC=nullptr, const TargetLibraryInfo *LibInfo=nullptr, CodeGenOptLevel OptLevel=CodeGenOptLevel::Default) const
MachineMemOperand::Flags getStoreMemOperandFlags(const StoreInst &SI, const DataLayout &DL) const
const Triple & getTargetTriple() const
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
VendorType getVendor() const
Get the parsed vendor type of this triple.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getArrayElementType() const
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
bool isStructTy() const
True if this is an instance of StructType.
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
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.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
std::string lookupBuiltinNameHelper(StringRef DemangledCall, FPDecorationId *DecorationId)
Parses the name part of the demangled builtin call.
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
unsigned getNumElements(Type *Ty)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
ModulePass * createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
RelativeUniformCounterPtr Values
uint32_t getMemSemanticsWithStorageClass(const Triple &TT, uint32_t OrderSem, uint32_t StorageClassSem)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
bool isUntypedPointerVectorTy(const Type *T)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
bool sortBlocks(Function &F)
bool isa_and_nonnull(const Y &Val)
SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx, SyncScope::ID Id)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
bool isNestedPointer(const Type *Ty)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
Type * normalizeType(Type *Ty, bool CanUseAnyVectorRank)
auto reverse(ContainerTy &&C)
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
@ Ref
The access may reference the value stored in memory.
@ And
Bitwise or logical AND of integers.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
bool isLongVectorEXT(const Type *Ty, bool CanUseVector16=true)
Type * parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx)
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
bool hasInitializer(const GlobalVariable *GV)
bool isPointerTyOrWrapper(const Type *Ty)
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
PoisonValue * getNormalizedPoisonValue(Type *Ty, bool CanUseAnyVectorRank)
bool isUntypedPointerTy(const Type *T)
Type * reconstitutePeeledArrayType(Type *Ty)
bool spirvPreserveAuxData(const SPIRVOptions &CLOpts, const Triple &TT)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)