29#include "llvm/IR/IntrinsicsSPIRV.h"
64#define DEBUG_TYPE "spirv-emit-intrinsics"
68 cl::desc(
"Emit OpName for all instructions"),
72#define GET_BuiltinGroup_DECL
73#include "SPIRVGenTables.inc"
78class GlobalVariableUsers {
79 template <
typename T1,
typename T2>
80 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
82 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
84 void collectGlobalUsers(
85 const GlobalVariable *GV,
86 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
87 &GlobalIsUsedByGlobal) {
89 while (!
Stack.empty()) {
93 GlobalIsUsedByFun[GV].insert(
I->getFunction());
98 GlobalIsUsedByGlobal[GV].insert(UserGV);
103 Stack.append(
C->user_begin(),
C->user_end());
107 bool propagateGlobalToGlobalUsers(
108 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
109 &GlobalIsUsedByGlobal) {
112 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
113 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
114 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
115 auto It = GlobalIsUsedByGlobal.find(UserGV);
116 if (It == GlobalIsUsedByGlobal.end())
124 void propagateGlobalToFunctionReferences(
125 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
126 &GlobalIsUsedByGlobal) {
127 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
128 auto &UserFunctions = GlobalIsUsedByFun[GV];
129 for (
const GlobalVariable *UserGV : UserGlobals) {
130 auto It = GlobalIsUsedByFun.find(UserGV);
131 if (It == GlobalIsUsedByFun.end())
142 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
143 GlobalIsUsedByGlobal;
144 GlobalIsUsedByFun.clear();
145 for (GlobalVariable &GV :
M.globals())
146 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
149 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
152 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
155 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
156 const FunctionSetType &
157 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
158 auto It = GlobalIsUsedByFun.find(&GV);
159 if (It != GlobalIsUsedByFun.end())
162 static const FunctionSetType
Empty{};
167static bool isaGEP(
const Value *V) {
173static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
179 return AT->getNumElements();
185class SPIRVEmitIntrinsicsImpl
186 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
187 const SPIRVTargetMachine &TM;
188 SPIRVGlobalRegistry *GR =
nullptr;
190 bool TrackConstants =
true;
191 bool HaveFunPtrs =
false;
192 bool CanUseAnyVectorRank =
false;
193 DenseMap<Instruction *, Constant *> AggrConsts;
194 DenseMap<Instruction *, Type *> AggrConstTypes;
195 SmallPtrSet<Instruction *, 0> AggrStores;
196 GlobalVariableUsers GVUsers;
197 SmallPtrSet<Value *, 0> Named;
200 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
203 bool CanTodoType =
true;
204 unsigned TodoTypeSz = 0;
205 DenseMap<Value *, bool> TodoType;
206 void insertTodoType(
Value *
Op) {
208 if (CanTodoType && !isaGEP(
Op)) {
209 auto It = TodoType.try_emplace(
Op,
true);
214 void eraseTodoType(
Value *
Op) {
215 auto It = TodoType.find(
Op);
216 if (It != TodoType.end() && It->second) {
224 auto It = TodoType.find(
Op);
225 return It != TodoType.end() && It->second;
229 SmallPtrSet<Instruction *, 0> TypeValidated;
232 enum WellKnownTypes { Event };
235 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
236 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
237 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
238 bool UnknownElemTypeI8,
239 bool IgnoreKnownType =
false);
240 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
241 bool UnknownElemTypeI8);
242 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
243 SmallPtrSetImpl<Value *> &Visited,
244 bool UnknownElemTypeI8,
245 std::optional<unsigned> AddrSpace = {});
247 SmallPtrSetImpl<Value *> &Visited,
248 bool UnknownElemTypeI8);
250 bool UnknownElemTypeI8);
253 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
254 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
255 SmallPtrSetImpl<Value *> &Visited,
256 bool UnknownElemTypeI8);
260 deduceOperandElementType(Instruction *
I,
261 SmallPtrSetImpl<Instruction *> *IncompleteRets,
262 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
263 bool IsPostprocessing =
false);
268 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
269 void simplifyNullAddrSpaceCasts();
271 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
272 bool IsPostprocessing);
274 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
276 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
277 bool UnknownElemTypeI8);
279 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
281 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
282 Type *ExpectedElementType,
283 unsigned OperandToReplace,
285 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
286 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
288 void insertConstantsForFPFastMathDefault(
Module &M);
291 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
294 Type *deduceFunParamElementType(
Function *
F,
unsigned OpIdx);
296 SmallPtrSetImpl<Function *> &FVisited);
298 bool deduceOperandElementTypeCalledFunction(
300 Type *&KnownElemTy,
bool &Incomplete);
301 void deduceOperandElementTypeFunctionPointer(
303 Type *&KnownElemTy,
bool IsPostprocessing);
304 bool deduceOperandElementTypeFunctionRet(
305 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
306 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
310 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
311 DenseMap<Function *, CallInst *> Ptrcasts);
313 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
316 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
317 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
318 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
319 SmallPtrSetImpl<Value *> &Visited,
320 DenseMap<Function *, CallInst *> Ptrcasts);
323 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
324 Instruction *Dest,
bool DeleteOld =
true);
328 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
331 bool postprocessTypes(
Module &M);
332 bool processFunctionPointers(
Module &M);
333 void parseFunDeclarations(
Module &M);
334 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
335 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
336 bool convertMaskedMemIntrinsics(
Module &M);
337 bool foldStaticArrayAllocas(
Module &M);
338 void preprocessBoolVectorBitcasts(
Function &
F);
357 bool walkLogicalAccessChain(
358 GetElementPtrInst &
GEP,
359 const std::function<
void(
Type *PointedType,
uint64_t Index)>
362 uint64_t Multiplier)> &OnDynamicIndexing);
364 bool walkLogicalAccessChainDynamic(
366 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
369 bool walkLogicalAccessChainConstant(
371 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing);
377 Type *getGEPType(GetElementPtrInst *
GEP);
384 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
386 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
389 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
392 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
395 Instruction *visitInsertElementInst(InsertElementInst &
I);
396 Instruction *visitExtractElementInst(ExtractElementInst &
I);
398 Instruction *visitExtractValueInst(ExtractValueInst &
I);
402 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
407 bool runOnModule(
Module &M);
410class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
411 const SPIRVTargetMachine &TM;
415 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
416 : ModulePass(ID), TM(TM) {}
418 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
420 bool runOnModule(
Module &M)
override {
421 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
427 Intrinsic::experimental_convergence_loop,
428 Intrinsic::experimental_convergence_anchor>());
431bool expectIgnoredInIRTranslation(
const Instruction *
I) {
433 Intrinsic::spv_resource_handlefrombinding,
434 Intrinsic::spv_resource_getbasepointer,
435 Intrinsic::spv_resource_getpointer>());
442 return getPointerRoot(V);
448char SPIRVEmitIntrinsicsLegacy::ID = 0;
451 "SPIRV emit intrinsics",
false,
false)
465 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
478 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrAlloca());
484 B.SetCurrentDebugLocation(
I->getDebugLoc());
485 if (
I->getType()->isVoidTy())
486 B.SetInsertPoint(
I->getNextNode());
488 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
498 if (
I->getType()->isTokenTy())
500 "does not support token type",
505 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
506 expectIgnoredInIRTranslation(
I))
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);
1627 CallInst *PtrCastI =
1628 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1629 if (OpIt.second == std::numeric_limits<unsigned>::max())
1632 I->setOperand(OpIt.second, PtrCastI);
1638void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1643 if (isAssignTypeInstr(U)) {
1644 B.SetInsertPoint(U);
1645 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1646 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1647 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1649 U->eraseFromParent();
1652 U->replaceUsesOfWith(Old, New);
1660 Type *NewArgTy =
New->getType();
1662 if (NewArgTy != ExpectedArgTy) {
1665 M, Intrinsic::spv_abort, {NewArgTy});
1675 "aggregate PHI/select/freeze should have been mutated to value-id "
1677 U->replaceUsesOfWith(Old, New);
1682 New->copyMetadata(*Old);
1688 bool HasPoisonExt) {
1695 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1696 "lowered as undef\n");
1698 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1699 Type *Ty = UV->getType();
1705 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1706 :
B.CreateIntrinsicWithoutFolding(IID, {});
1707 AggrConsts[
Call] = UV;
1708 AggrConstTypes[
Call] = Ty;
1713 return B.CreateIntrinsic(IID, {Ty}, {});
1720void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1725 SmallVector<Instruction *, 16> Insts;
1729 for (Instruction *
I : Insts) {
1730 bool BPrepared =
false;
1732 for (
unsigned Idx = 0;
Idx <
I->getNumOperands(); ++
Idx) {
1736 bool IsScalar = !
Op->getType()->isAggregateType();
1739 if (IsScalar && !AsPoison)
1743 if (IsScalar && Phi)
1744 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1745 else if (!BPrepared) {
1749 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1750 I->setOperand(Idx, Repl);
1759void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1763 ASC->replaceAllUsesWith(
1765 ASC->eraseFromParent();
1773 if (!V->getType()->isAggregateType())
1782 I.getType()->isAggregateType();
1788void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1791 for (Use &U :
I->operands()) {
1798 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1803 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1805 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1811void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1815 std::queue<Instruction *> Worklist;
1819 while (!Worklist.empty()) {
1820 auto *
I = Worklist.front();
1823 bool KeepInst =
false;
1824 for (
const auto &
Op :
I->operands()) {
1826 Type *ResTy =
nullptr;
1829 ResTy = COp->getType();
1841 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1844 auto PrepareInsert = [&]() {
1847 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1848 :
B.SetInsertPoint(
I);
1853 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1854 Args.push_back(COp->getElementAsConstant(i));
1860 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1869 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1875 auto *CI =
B.CreateIntrinsicWithoutFolding(
1876 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1880 AggrConsts[CI] = AggrConst;
1881 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1893 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1898 unsigned RoundingModeDeco,
1905 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1914 MDNode *SaturatedConversionNode =
1916 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1936 MDString *ConstraintString =
1941 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1945 B.SetInsertPoint(&
Call);
1946 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1951void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1954 if (!
RM.has_value())
1956 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1957 switch (
RM.value()) {
1961 case RoundingMode::NearestTiesToEven:
1962 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1964 case RoundingMode::TowardNegative:
1965 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1967 case RoundingMode::TowardPositive:
1968 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1970 case RoundingMode::TowardZero:
1971 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1973 case RoundingMode::Dynamic:
1974 case RoundingMode::NearestTiesToAway:
1978 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1984Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1988 B.SetInsertPoint(&
I);
1989 SmallVector<Value *, 4>
Args;
1991 Args.push_back(
I.getCondition());
1994 for (
auto &Case :
I.cases()) {
1995 Args.push_back(Case.getCaseValue());
1996 BBCases.
push_back(Case.getCaseSuccessor());
1999 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2000 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
2004 I.eraseFromParent();
2007 B.SetInsertPoint(ParentBB);
2008 IndirectBrInst *BrI =
B.CreateIndirectBr(
2011 for (BasicBlock *BBCase : BBCases)
2020Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
2026 B.SetInsertPoint(&
I);
2028 SmallVector<Value *, 4>
Args;
2029 Args.push_back(
B.getInt1(
true));
2030 Args.push_back(
I.getOperand(0));
2031 Args.push_back(
B.getInt32(0));
2032 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
2033 Args.push_back(SGEP->getIndexOperand(J));
2036 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
2037 replaceAllUsesWithAndErase(
B, &
I, NewI);
2042SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2044 B.SetInsertPoint(&
I);
2049 unsigned N = RetVTy->getNumElements();
2050 Value *PtrOp =
I.getPointerOperand();
2052 Type *ResultPtrTy = RetVTy->getElementType();
2055 Value *InBounds =
B.getInt1(
I.isInBounds());
2056 Type *LanePointeeTy = getGEPType(&
I);
2057 Type *SrcElemTy =
I.getSourceElementType();
2066 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2067 Value *LaneIdx =
B.getInt32(Lane);
2068 Value *ScalarPtr = PtrOp;
2072 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2076 SmallVector<Value *, 4>
Args;
2077 Args.push_back(InBounds);
2078 Args.push_back(ScalarPtr);
2079 for (
Value *Idx :
I.indices()) {
2087 Args.push_back(visitExtractElementInst(*EI));
2091 Args.push_back(Idx);
2094 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2096 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2100 replaceAllUsesWithAndErase(
B, &
I, NewI);
2118 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2119 return buildLogicalAccessChainFromGEP(
I);
2124 Value *PtrOp =
I.getPointerOperand();
2125 Type *SrcElemTy =
I.getSourceElementType();
2126 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2129 if (ArrTy->getElementType() == SrcElemTy) {
2131 Type *FirstIdxType =
I.getOperand(1)->getType();
2132 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2133 for (
Value *Idx :
I.indices())
2137 SmallVector<Value *, 4>
Args;
2138 Args.push_back(
B.getInt1(
I.isInBounds()));
2139 Args.push_back(
I.getPointerOperand());
2142 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2144 replaceAllUsesWithAndErase(
B, &
I, NewI);
2151 SmallVector<Value *, 4>
Args;
2152 Args.push_back(
B.getInt1(
I.isInBounds()));
2155 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2156 replaceAllUsesWithAndErase(
B, &
I, NewI);
2160Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2162 B.SetInsertPoint(&
I);
2171 I.eraseFromParent();
2178 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2179 replaceAllUsesWithAndErase(
B, &
I, NewI);
2183void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2185 Type *VTy =
V->getType();
2190 if (ElemTy != AssignedType)
2203 if (CurrentType == AssignedType)
2210 " for value " +
V->getName(),
2219void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2220 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2225 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2226 if (PointerElemTy == ExpectedElementType ||
2231 Value *ExpectedElementVal =
2233 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2235 bool FirstPtrCastOrAssignPtrType =
true;
2241 for (
auto User :
Pointer->users()) {
2244 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2245 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2246 II->getOperand(0) != Pointer)
2251 FirstPtrCastOrAssignPtrType =
false;
2252 if (
II->getOperand(1) != VMD ||
2259 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2264 if (
II->getParent() !=
I->getParent())
2267 I->setOperand(OperandToReplace,
II);
2282 if (FirstPtrCastOrAssignPtrType) {
2287 }
else if (isTodoType(Pointer)) {
2288 eraseTodoType(Pointer);
2296 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2297 std::make_pair(
I, Pointer)};
2299 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2312 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
2318void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2323 replacePointerOperandWithPtrCast(
2324 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2330 Type *OpTy =
Op->getType();
2333 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2336 if (OpTy ==
Op->getType())
2337 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2338 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2343 Type *OpTy = LI->getType();
2354 Type *NewOpTy = OpTy;
2355 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2356 if (OpTy == NewOpTy)
2357 insertTodoType(Pointer);
2360 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2365 Type *OpTy =
nullptr;
2377 OpTy = GEPI->getSourceElementType();
2379 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2381 insertTodoType(Pointer);
2387 Value *
Op = IVI->getInsertedValueOperand();
2389 replacePointerOperandWithPtrCast(
2403 std::string DemangledName =
2407 bool HaveTypes =
false;
2408 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2426 for (User *U : CalledArg->
users()) {
2428 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2434 HaveTypes |= ElemTy !=
nullptr;
2439 if (DemangledName.empty() && !HaveTypes)
2443 TM.
getSubtarget<SPIRVSubtarget>(*CalledF).getPreferredInstructionSet();
2445 bool ParseBuiltinTypes =
2446 !DemangledName.empty() &&
2447 (!CalledF->
isDeclaration() || SPIRV::isBuiltin(DemangledName, Set));
2448 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2463 Type *ExpectedType =
2464 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2465 if (!ExpectedType && ParseBuiltinTypes)
2466 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2467 DemangledName, OpIdx,
I->getContext());
2468 if (!ExpectedType || ExpectedType->
isVoidTy())
2476 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2481SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2484 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2488 I.getOperand(1)->getType(),
2489 I.getOperand(2)->getType()};
2491 B.SetInsertPoint(&
I);
2493 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2495 replaceAllUsesWithAndErase(
B, &
I, NewI);
2500SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2503 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2507 B.SetInsertPoint(&
I);
2509 I.getIndexOperand()->getType()};
2510 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2511 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2513 replaceAllUsesWithAndErase(
B, &
I, NewI);
2517Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2519 B.SetInsertPoint(&
I);
2522 Value *AggregateOp =
I.getAggregateOperand();
2526 Args.push_back(AggregateOp);
2527 Args.push_back(
I.getInsertedValueOperand());
2528 for (
auto &
Op :
I.indices())
2529 Args.push_back(
B.getInt32(
Op));
2531 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2532 replaceMemInstrUses(&
I, NewI,
B);
2537SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2539 B.SetInsertPoint(&
I);
2540 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2549 for (
auto &
Op :
I.indices())
2550 Args.push_back(
B.getInt32(
Op));
2551 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2552 {
I.getType()}, {
Args});
2558 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2559 AggrConstTypes[NewI] =
I.getType();
2561 replaceMemInstrUses(&
I, NewI,
B);
2564 replaceAllUsesWithAndErase(
B, &
I, NewI);
2568 for (
const Use &U : NewI->
uses()) {
2569 User *Usr =
U.getUser();
2571 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2582 if (ArgNo < FT->getNumParams() &&
2583 !FT->getParamType(ArgNo)->isAggregateType()) {
2592Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2593 if (!
I.getType()->isAggregateType())
2596 B.SetInsertPoint(&
I);
2597 TrackConstants =
false;
2602 unsigned IntrinsicId;
2603 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2604 if (!
I.isAtomic()) {
2605 IntrinsicId = Intrinsic::spv_load;
2606 Args.push_back(
B.getInt32(
I.getAlign().value()));
2608 IntrinsicId = Intrinsic::spv_atomic_load;
2609 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2611 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2612 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2614 replaceMemInstrUses(&
I, NewI,
B);
2618Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2622 B.SetInsertPoint(&
I);
2623 TrackConstants =
false;
2627 auto *PtrOp =
I.getPointerOperand();
2629 if (
I.getValueOperand()->getType()->isAggregateType()) {
2637 "Unexpected argument of aggregate type, should be spv_extractv!");
2641 unsigned IntrinsicId;
2642 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2644 if (!
I.isAtomic()) {
2645 IntrinsicId = Intrinsic::spv_store;
2646 Args.push_back(
B.getInt32(
I.getAlign().value()));
2648 IntrinsicId = Intrinsic::spv_atomic_store;
2649 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2652 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2654 I.eraseFromParent();
2658Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2659 Value *ArraySize =
nullptr;
2660 if (
I.isArrayAllocation()) {
2663 SPIRV::Extension::SPV_INTEL_variable_length_array))
2665 "array allocation: this instruction requires the following "
2666 "SPIR-V extension: SPV_INTEL_variable_length_array",
2668 ArraySize =
I.getArraySize();
2671 B.SetInsertPoint(&
I);
2672 TrackConstants =
false;
2673 Type *PtrTy =
I.getType();
2676 ?
B.CreateIntrinsicWithoutFolding(
2677 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2678 {ArraySize,
B.getInt32(
I.getAlign().value())})
2679 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2680 {
B.getInt32(
I.getAlign().value())});
2681 replaceAllUsesWithAndErase(
B, &
I, NewI);
2686SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2687 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2689 B.SetInsertPoint(&
I);
2692 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2696 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2697 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2698 uint32_t ScSem =
static_cast<uint32_t
>(
2707 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2708 replaceMemInstrUses(&
I, NewI,
B);
2712Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &
I) {
2713 auto Op =
I.getOperation();
2724 B.SetInsertPoint(&
I);
2726 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2727 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2729 uint32_t
Scope =
static_cast<uint32_t
>(
2730 getMemScope(
M->getTargetTriple(),
I.getContext(),
I.getSyncScopeID()));
2731 uint32_t ScSem =
static_cast<uint32_t
>(
2734 M->getTargetTriple(),
2738 ?
"__translate_spirv_atomic_uinc_wrap"
2739 :
"__translate_spirv_atomic_udec_wrap");
2741 Type *ValTy =
I.getValOperand()->getType();
2742 Type *PtrTy =
I.getPointerOperand()->getType();
2744 raw_svector_ostream OS(FuncName);
2745 OS <<
"_p" << AS <<
"_";
2747 OS <<
"v" << VecTy->getNumElements();
2750 Type *Int32Ty =
B.getInt32Ty();
2751 Type *BoolTy =
B.getInt1Ty();
2753 ValTy, BoolTy, BoolTy};
2754 FunctionType *FT = FunctionType::get(ValTy, ArgTys,
false);
2755 FunctionCallee
FC =
M->getOrInsertFunction(FuncName, FT);
2759 I.getPointerOperand(),
B.getInt32(Scope),
2760 B.getInt32(MemSem),
I.getValOperand(),
2761 B.getInt1(
I.isVolatile()),
B.getInt1(
I.isElementwise())};
2762 CallInst *CI =
B.CreateCall(FC, Args);
2768 replaceAllUsesWithAndErase(
B, &
I, CI);
2777 case Intrinsic::spv_abort:
2779 case Intrinsic::trap:
2780 case Intrinsic::ubsantrap:
2782 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2798 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2799 "abort-like call must be the last non-debug instruction before its "
2800 "block's terminator");
2804Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2805 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2809 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2816 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2830 while (!Stack.empty()) {
2831 const Value *V = Stack.pop_back_val();
2832 if (!Visited.
insert(V).second)
2840 Stack.append(
C->user_begin(),
C->user_end());
2856 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2857 if (UserFunctions.contains(
F))
2862 if (!UserFunctions.empty())
2867 const Module &M = *
F->getParent();
2868 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2869 return F == &FirstDefinition;
2872Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2874 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2875 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2877 AggrConstTypes[Leaf] = ElemTy;
2880 SmallVector<Value *, 4> Elems;
2882 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2885 DenseMap<Type *, Instruction *> LeafByType;
2886 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2888 auto &
Entry = LeafByType[ElemTy];
2890 Entry = MakeLeaf(ElemTy);
2894 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2895 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2897 AggrConstTypes[Composite] = AggrTy;
2906void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2911 for (BasicBlock &BB : Func) {
2915 Value *RetVal = RI->getReturnValue();
2922 B.SetInsertPoint(RI);
2925 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2926 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2928 RI->setOperand(0, Rebuilt);
2932void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2942 deduceElementTypeHelper(&GV,
false);
2947 Value *InitOp = Init;
2954 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2955 {
B.getInt32Ty()}, {});
2960 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2965 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2966 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2972 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2978bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2980 bool UnknownElemTypeI8) {
2986 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2993void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2996 static StringMap<unsigned> ResTypeWellKnown = {
2997 {
"async_work_group_copy", WellKnownTypes::Event},
2998 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2999 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
3003 bool IsKnown =
false;
3008 std::string DemangledName =
3011 if (DemangledName.length() > 0)
3013 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
3014 auto ResIt = ResTypeWellKnown.
find(DemangledName);
3015 if (ResIt != ResTypeWellKnown.
end()) {
3018 switch (ResIt->second) {
3019 case WellKnownTypes::Event:
3022 CanUseAnyVectorRank);
3027 switch (DecorationId) {
3030 case FPDecorationId::SAT:
3033 case FPDecorationId::RTE:
3035 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
3037 case FPDecorationId::RTZ:
3039 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
3041 case FPDecorationId::RTP:
3043 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
3045 case FPDecorationId::RTN:
3047 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
3053 Type *Ty =
I->getType();
3056 Type *TypeToAssign = Ty;
3059 auto It = AggrConstTypes.
find(
II);
3060 if (It == AggrConstTypes.
end())
3062 TypeToAssign = It->second;
3063 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
3064 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
3065 TypeToAssign = It->second;
3067 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
3068 TypeToAssign = It->second;
3072 for (
const auto &
Op :
I->operands()) {
3080 Type *OpTy =
Op->getType();
3082 CallInst *AssignCI =
3087 Type *OpTy =
Op->getType();
3103 Intrinsic::spv_assign_type, {OpTy},
3113bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
3114 Instruction *Inst) {
3116 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3126void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3128 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3130 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3135 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3136 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3137 if (shouldTryToAddMemAliasingDecoration(
I)) {
3138 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3139 ? SPIRV::Decoration::AliasScopeINTEL
3140 : SPIRV::Decoration::NoAliasINTEL;
3142 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3145 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3146 {
I->getType()}, {
Args});
3150 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3151 processMemAliasingDecoration(LLVMContext::MD_noalias);
3154 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3156 bool AllowFPMaxError =
3158 if (!AllowFPMaxError)
3162 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3168 LLVMContext &Ctx =
B.getContext();
3170 B.getInt32Ty(), SPIRV::Decoration::AuxDataInstructionMetadata));
3173 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3175 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3176 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3178 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.remote.memory")}));
3179 if (
I->hasMetadata(LLVMContext::MD_atomic_ignore_denormal_mode))
3181 Ctx, {AuxMD,
MDString::get(Ctx,
"atomic.ignore.denormal.mode")}));
3184 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3193 &FPFastMathDefaultInfoMap,
3195 auto it = FPFastMathDefaultInfoMap.
find(
F);
3196 if (it != FPFastMathDefaultInfoMap.
end())
3204 SPIRV::FPFastMathMode::None);
3206 SPIRV::FPFastMathMode::None);
3208 SPIRV::FPFastMathMode::None);
3209 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3215 size_t BitWidth = Ty->getScalarSizeInBits();
3219 assert(Index >= 0 && Index < 3 &&
3220 "Expected FPFastMathDefaultInfo for half, float, or double");
3221 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3222 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3223 return FPFastMathDefaultInfoVec[Index];
3226void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3228 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3237 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3239 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3247 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3250 [[maybe_unused]] GlobalVariable *GV =
3251 new GlobalVariable(M,
3252 Type::getInt32Ty(
M.getContext()),
3266 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3267 FPFastMathDefaultInfoMap;
3269 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3278 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3280 "Expected 4 operands for FPFastMathDefault");
3286 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3288 SPIRV::FPFastMathDefaultInfo &
Info =
3291 Info.FPFastMathDefault =
true;
3292 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3294 "Expected no operands for ContractionOff");
3298 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3300 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3301 Info.ContractionOff =
true;
3303 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3305 "Expected 1 operand for SignedZeroInfNanPreserve");
3306 unsigned TargetWidth =
3311 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3315 assert(Index >= 0 && Index < 3 &&
3316 "Expected FPFastMathDefaultInfo for half, float, or double");
3317 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3318 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3319 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3323 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3324 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3325 if (FPFastMathDefaultInfoVec.
empty())
3328 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3329 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3332 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3333 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3337 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3339 "and AllowContract");
3341 if (
Info.SignedZeroInfNanPreserve &&
3343 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3344 SPIRV::FPFastMathMode::NSZ))) {
3345 if (
Info.FPFastMathDefault)
3347 "SignedZeroInfNanPreserve but at least one of "
3348 "NotNaN/NotInf/NSZ is enabled.");
3351 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3352 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3353 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3355 "AllowTransform requires AllowReassoc and "
3356 "AllowContract to be set.");
3359 auto it = GlobalVars.
find(Flags);
3360 GlobalVariable *GV =
nullptr;
3361 if (it != GlobalVars.
end()) {
3367 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3370 GV =
new GlobalVariable(M,
3371 Type::getInt32Ty(
M.getContext()),
3376 GlobalVars[
Flags] = GV;
3382void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3385 bool IsConstComposite =
3386 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3387 if (IsConstComposite && TrackConstants) {
3389 auto t = AggrConsts.
find(
I);
3393 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3395 NewOp->setArgOperand(0,
I);
3398 for (
const auto &
Op :
I->operands()) {
3402 unsigned OpNo =
Op.getOperandNo();
3403 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3404 (!
II->isBundleOperand(OpNo) &&
3405 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3409 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3410 :
B.SetInsertPoint(
I);
3413 Type *OpTy =
Op->getType();
3421 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3423 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3424 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3426 SmallVector<Value *, 2>
Args = {
3430 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3436 I->setOperand(OpNo, NewOp);
3442Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3444 SmallPtrSet<Function *, 0> FVisited;
3445 return deduceFunParamElementType(
F, OpIdx, FVisited);
3448Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3449 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3451 if (!FVisited.
insert(
F).second)
3454 SmallPtrSet<Value *, 0> Visited;
3457 for (User *U :
F->users()) {
3459 if (!CI || OpIdx >= CI->
arg_size())
3469 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3472 for (User *OpU : OpArg->
users()) {
3474 if (!Inst || Inst == CI)
3477 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3484 if (FVisited.
find(OuterF) != FVisited.
end())
3486 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3487 if (OuterF->
getArg(i) == OpArg) {
3488 Lookup.push_back(std::make_pair(OuterF, i));
3495 for (
auto &Pair :
Lookup) {
3496 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3503void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3505 B.SetInsertPointPastAllocas(
F);
3506 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3512 for (User *U : Arg->
users()) {
3514 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3532 for (User *U :
F->users()) {
3534 if (!CI || OpIdx >= CI->
arg_size())
3548 for (User *U : Arg->
users()) {
3552 CI->
getParent()->getParent() == CurrF) {
3554 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3566 B.SetInsertPointPastAllocas(
F);
3567 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3572 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3574 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3578 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3590 bool IsNewFTy =
false;
3606bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3609 if (
F.isIntrinsic())
3611 if (
F.isDeclaration()) {
3612 for (User *U :
F.users()) {
3615 UF &&
UF->hasPersonalityFn() &&
UF->getPersonalityFn() == &
F)
3629 for (User *U :
F.users()) {
3631 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3633 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3634 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3642 if (Worklist.
empty())
3645 LLVMContext &Ctx =
M.getContext();
3652 for (
const auto &Arg :
F->args())
3655 IRB.CreateCall(
F, Args);
3657 IRB.CreateRetVoid();
3663void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3664 DenseMap<Function *, CallInst *> Ptrcasts;
3665 for (
auto It : FDeclPtrTys) {
3667 for (
auto *U :
F->users()) {
3672 for (
auto [Idx, ElemTy] : It.second) {
3680 B.SetInsertPointPastAllocas(Arg->
getParent());
3684 }
else if (isaGEP(Param)) {
3685 replaceUsesOfWithSpvPtrcast(
3686 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3695 .getFirstNonPHIOrAlloca());
3713 FDeclPtrTys.
clear();
3716GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3717 GetElementPtrInst *
GEP) {
3724 Type *SrcTy =
GEP->getSourceElementType();
3725 SmallVector<Value *, 8> Indices(
GEP->indices());
3727 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3728 Indices.erase(Indices.begin());
3729 SrcTy = ArrTy->getElementType();
3731 GEP->getNoWrapFlags(),
"",
3732 GEP->getIterator());
3737void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3744 if (
ST->canUseExtension(
3745 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3746 for (BasicBlock &BB :
F) {
3748 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3752 SmallVector<unsigned, 1>
Ops =
3754 unsigned LC =
Ops[0];
3755 if (LC == SPIRV::LoopControl::None)
3759 B.SetInsertPoint(Term);
3760 SmallVector<Value *, 4> IntrArgs;
3761 for (
unsigned Op :
Ops)
3763 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3775 SmallPtrSet<BasicBlock *, 8> UsedMergeBlocks;
3782 SmallVector<unsigned, 1> LoopControlOps =
3784 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3797 for (BasicBlock *BB : {Latch, Header}) {
3801 if (!
L->contains(Succ) && !UsedMergeBlocks.
contains(Succ))
3804 if (!MergeBlock || !UsedMergeBlocks.
insert(MergeBlock).second)
3807 B.SetInsertPoint(Header->getTerminator());
3810 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3811 for (
unsigned Imm : LoopControlOps)
3812 Args.emplace_back(
B.getInt32(
Imm));
3813 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3817bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3818 if (
Func.isDeclaration())
3827 GR =
ST.getSPIRVGlobalRegistry();
3831 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3833 CanUseAnyVectorRank =
3834 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3838 AggrConstTypes.
clear();
3841 processParamTypesByFunHeader(CurrF,
B);
3845 SmallPtrSet<Instruction *, 4> DeadInsts;
3848 Type *ElTy =
SI->getValueOperand()->getType();
3863 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3867 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3869 GEP->replaceAllUsesWith(NewGEP);
3873 if (
Type *GepTy = getGEPType(
GEP))
3877 for (
auto *
I : DeadInsts) {
3878 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3879 I->eraseFromParent();
3882 B.SetInsertPoint(
Func.getEntryBlock().begin());
3883 for (
auto &GV :
Func.getParent()->globals())
3884 processGlobalValue(GV,
B);
3886 reconstructAggregateReturns(Func,
B);
3887 preprocessUndefsAndPoisons(
B);
3888 simplifyNullAddrSpaceCasts();
3889 preprocessCompositeConstants(
B);
3897 Type *I32Ty =
B.getInt32Ty();
3902 insertCompositeAggregateArms(&
I,
B);
3903 AggrConstTypes[&
I] =
I.getType();
3904 I.mutateType(I32Ty);
3907 preprocessBoolVectorBitcasts(Func);
3908 SmallVector<Instruction *> Worklist(
3911 applyDemangledPtrArgTypes(
B);
3914 for (
auto &
I : Worklist) {
3916 if (isConvergenceIntrinsic(
I))
3919 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3921 insertAssignTypeIntrs(
I,
B);
3922 insertPtrCastOrAssignTypeInstr(
I,
B);
3927 insertAssignPtrTypeIntrs(
I,
B,
true);
3930 useRoundingMode(FPI,
B);
3935 SmallPtrSet<Instruction *, 4> IncompleteRets;
3937 deduceOperandElementType(&
I, &IncompleteRets);
3941 for (BasicBlock &BB : Func)
3942 for (PHINode &Phi : BB.
phis())
3944 deduceOperandElementType(&Phi,
nullptr);
3946 for (
auto *
I : Worklist) {
3947 TrackConstants =
true;
3957 if (isConvergenceIntrinsic(
I))
3961 processInstrAfterVisit(
I,
B);
3964 emitUnstructuredLoopControls(Func,
B);
3970bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3971 if (!GR || TodoTypeSz == 0)
3974 unsigned SzTodo = TodoTypeSz;
3975 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3982 if (!KnownTy || !AssignCI)
3988 SmallPtrSet<Value *, 0> Visited;
3989 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3990 if (ElemTy != KnownTy) {
3991 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3992 propagateElemType(CI, ElemTy, VisitedSubst);
3999 if (
Op->hasUseList()) {
4000 for (User *U :
Op->users()) {
4007 if (TodoTypeSz == 0)
4012 SmallPtrSet<Instruction *, 4> IncompleteRets;
4014 auto It = ToProcess.
find(&
I);
4015 if (It == ToProcess.
end())
4017 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
4018 if (It->second.size() == 0)
4020 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
4021 if (TodoTypeSz == 0)
4026 return SzTodo > TodoTypeSz;
4040 .Cases({
"char",
"signed char",
"unsigned char",
"short",
4041 "unsigned short",
"int",
"unsigned int",
"_Float16",
"float",
4049 unsigned NumElts = 0;
4050 if (
Count.getAsInteger(10, NumElts) || NumElts == 0)
4057 TypeStr.
split(Quals,
' ', -1,
false);
4060 if (Qual !=
"const" && Qual !=
"volatile" && Qual !=
"restrict" &&
4061 !(Qual.consume_front(
"AS") && !Qual.getAsInteger(10, AS)))
4068void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
4070 if (!
F.isDeclaration() ||
F.isIntrinsic())
4073 if (DemangledName.empty())
4076 auto Set =
ST.getPreferredInstructionSet();
4077 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(DemangledName, Set);
4079 const bool IsBuiltin = Grp >= 0 || SPIRV::isBuiltin(DemangledName, Set);
4080 if (IsBuiltin && Opcode != SPIRV::OpGroupAsyncCopy)
4082 SmallVector<unsigned> Idxs;
4083 for (Argument &Arg :
F.args())
4088 LLVMContext &Ctx =
F.getContext();
4090 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
4091 if (TypeStrs.
empty())
4094 if (!IsBuiltin && (!
F.getName().starts_with(
"_Z") ||
F.hasStructRetAttr() ||
4095 StringRef(DemangledName).
count(
'(') != 1 ||
4096 StringRef(DemangledName).
count(
')') != 1 ||
4097 StringRef(DemangledName).
contains(
'<') ||
4098 TypeStrs.
size() !=
F.arg_size()))
4100 bool AllowLongVectors =
4101 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
4102 for (
unsigned Idx : Idxs) {
4103 if (Idx >= TypeStrs.
size())
4105 StringRef TypeStr = TypeStrs[
Idx].trim();
4106 Type *ElemTy = IsBuiltin
4107 ? SPIRV::parseBuiltinCallArgumentType(TypeStr, Ctx)
4117 FDeclPtrTys[&
F].emplace_back(Idx, ElemTy);
4119 ST.getSPIRVGlobalRegistry()->addDeducedElementType(
F.getArg(Idx),
4125bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
4126 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
4128 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
4129 if (!
ST.canUseExtension(
4130 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4131 I.getContext().emitError(
4132 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
4136 I.eraseFromParent();
4142 Value *Ptrs =
I.getArgOperand(0);
4144 Value *Passthru =
I.getArgOperand(2);
4147 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
4149 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
4154 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
4156 I.eraseFromParent();
4160 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
4161 if (!
ST.canUseExtension(
4162 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4163 I.getContext().emitError(
4164 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
4167 I.eraseFromParent();
4174 Value *Ptrs =
I.getArgOperand(1);
4179 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
4181 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
4185 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
4186 I.eraseFromParent();
4197void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
4198 struct BoolVecBitcast {
4200 FixedVectorType *BoolVecTy;
4204 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4206 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4214 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4216 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4220 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4222 Value *Src = BC->getOperand(0);
4223 unsigned BoolVecN = BoolVecTy->getNumElements();
4226 Type *OtherTy = SrcIsBoolVec ? BC->getDestTy() : Src->getType();
4227 unsigned NumElts = 1;
4229 NumElts = VTy->getNumElements();
4235 if (!SrcIsBoolVec) {
4238 auto GetLane = [&](
unsigned I) {
4241 Elt =
B.CreateExtractElement(IntVal,
B.getInt32(
I / EltBits));
4245 return B.CreateICmpNE(
And, ConstantInt::get(EltTy, 0));
4253 if (!Idx ||
Idx->getValue().uge(BoolVecN))
4255 B.SetInsertPoint(EE);
4256 EE->replaceAllUsesWith(GetLane(
Idx->getZExtValue()));
4257 EE->eraseFromParent();
4259 if (BC->use_empty()) {
4260 BC->eraseFromParent();
4264 B.SetInsertPoint(BC);
4266 for (
unsigned I = 0;
I < BoolVecN; ++
I)
4267 Result =
B.CreateInsertElement(Result, GetLane(
I),
B.getInt32(
I));
4271 for (
unsigned J = 0; J < NumElts; ++J) {
4272 Value *Elt = ConstantInt::get(EltTy, 0);
4273 for (
unsigned Bit = 0;
Bit < EltBits; ++
Bit) {
4275 B.CreateExtractElement(Src,
B.getInt32(J * EltBits + Bit));
4276 Value *Ext =
B.CreateZExt(Lane, EltTy);
4278 Ext =
B.CreateShl(Ext, ConstantInt::get(EltTy, Bit));
4279 Elt =
B.CreateOr(Elt, Ext);
4281 IntVal = NumElts > 1 ?
B.CreateInsertElement(IntVal, Elt,
B.getInt32(J))
4284 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4287 BC->replaceAllUsesWith(Result);
4288 BC->eraseFromParent();
4292bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4296 if (!
F.isIntrinsic())
4299 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4304 Changed |= processMaskedMemIntrinsic(*
II);
4308 F.eraseFromParent();
4314bool SPIRVEmitIntrinsicsImpl::foldStaticArrayAllocas(
Module &M) {
4316 Type *I32Ty = Type::getInt32Ty(
M.getContext());
4318 if (
F.isDeclaration())
4323 for (Instruction &
I :
F.getEntryBlock()) {
4325 if (!AI || !AI->isStaticAlloca() || !AI->isArrayAllocation() ||
4326 AI->getAddressSpace() !=
4331 if (
Count->isZero() || !
Count->getValue().isIntN(32))
4333 AI->setAllocatedType(
4334 ArrayType::get(AI->getAllocatedType(),
Count->getZExtValue()));
4335 AI->setOperand(0, ConstantInt::get(I32Ty, 1));
4342bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4344 bool Changed = foldStaticArrayAllocas(M);
4345 Changed |= convertMaskedMemIntrinsics(M);
4347 parseFunDeclarations(M);
4348 insertConstantsForFPFastMathDefault(M);
4359 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4361 processParamTypes(&
F,
B);
4365 CanTodoType =
false;
4366 Changed |= postprocessTypes(M);
4369 Changed |= processFunctionPointers(M);
4376 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4382 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 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.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg, bool CanUseAnyVectorRank)
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg)
Type * findDeducedCompositeType(const Value *Val)
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld=true)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
iterator find(ConstPtrType Ptr) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator find(StringRef Key)
Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
Check if the string is empty.
constexpr size_t size() const
Get the string size.
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
A switch()-like statement whose cases are string literals.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
const Triple & getTargetTriple() const
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
VendorType getVendor() const
Get the parsed vendor type of this triple.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getArrayElementType() const
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
bool isStructTy() const
True if this is an instance of StructType.
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
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)
bool isLongVectorEXT(const Type *Ty)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
bool sortBlocks(Function &F)
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)
bool spirvPreserveAuxData(const Triple &TT)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
@ Ref
The access may reference the value stored in memory.
@ And
Bitwise or logical AND of integers.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Type * parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx)
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
bool hasInitializer(const GlobalVariable *GV)
bool isPointerTyOrWrapper(const Type *Ty)
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
PoisonValue * getNormalizedPoisonValue(Type *Ty, bool CanUseAnyVectorRank)
bool isUntypedPointerTy(const Type *T)
Type * reconstitutePeeledArrayType(Type *Ty)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)