28#include "llvm/IR/IntrinsicsSPIRV.h"
61#define DEBUG_TYPE "spirv-emit-intrinsics"
65 cl::desc(
"Emit OpName for all instructions"),
69#define GET_BuiltinGroup_DECL
70#include "SPIRVGenTables.inc"
75class GlobalVariableUsers {
76 template <
typename T1,
typename T2>
77 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
79 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
81 void collectGlobalUsers(
82 const GlobalVariable *GV,
83 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
84 &GlobalIsUsedByGlobal) {
86 while (!
Stack.empty()) {
90 GlobalIsUsedByFun[GV].insert(
I->getFunction());
95 GlobalIsUsedByGlobal[GV].insert(UserGV);
100 Stack.append(
C->user_begin(),
C->user_end());
104 bool propagateGlobalToGlobalUsers(
105 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
106 &GlobalIsUsedByGlobal) {
109 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
110 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
111 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
112 auto It = GlobalIsUsedByGlobal.find(UserGV);
113 if (It == GlobalIsUsedByGlobal.end())
121 void propagateGlobalToFunctionReferences(
122 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
123 &GlobalIsUsedByGlobal) {
124 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
125 auto &UserFunctions = GlobalIsUsedByFun[GV];
126 for (
const GlobalVariable *UserGV : UserGlobals) {
127 auto It = GlobalIsUsedByFun.find(UserGV);
128 if (It == GlobalIsUsedByFun.end())
139 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
140 GlobalIsUsedByGlobal;
141 GlobalIsUsedByFun.clear();
142 for (GlobalVariable &GV :
M.globals())
143 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
146 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
149 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
152 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
153 const FunctionSetType &
154 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
155 auto It = GlobalIsUsedByFun.find(&GV);
156 if (It != GlobalIsUsedByFun.end())
159 static const FunctionSetType
Empty{};
164static bool isaGEP(
const Value *V) {
170static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
176 return AT->getNumElements();
182class SPIRVEmitIntrinsicsImpl
183 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
184 const SPIRVTargetMachine &TM;
185 SPIRVGlobalRegistry *GR =
nullptr;
187 bool TrackConstants =
true;
188 bool HaveFunPtrs =
false;
189 DenseMap<Instruction *, Constant *> AggrConsts;
190 DenseMap<Instruction *, Type *> AggrConstTypes;
191 SmallPtrSet<Instruction *, 0> AggrStores;
192 GlobalVariableUsers GVUsers;
193 SmallPtrSet<Value *, 0> Named;
196 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
199 bool CanTodoType =
true;
200 unsigned TodoTypeSz = 0;
201 DenseMap<Value *, bool> TodoType;
202 void insertTodoType(
Value *
Op) {
204 if (CanTodoType && !isaGEP(
Op)) {
205 auto It = TodoType.try_emplace(
Op,
true);
210 void eraseTodoType(
Value *
Op) {
211 auto It = TodoType.find(
Op);
212 if (It != TodoType.end() && It->second) {
220 auto It = TodoType.find(
Op);
221 return It != TodoType.end() && It->second;
225 SmallPtrSet<Instruction *, 0> TypeValidated;
228 enum WellKnownTypes { Event };
231 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
232 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
233 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
234 bool UnknownElemTypeI8,
235 bool IgnoreKnownType =
false);
236 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
237 bool UnknownElemTypeI8);
238 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
239 SmallPtrSetImpl<Value *> &Visited,
240 bool UnknownElemTypeI8);
242 SmallPtrSetImpl<Value *> &Visited,
243 bool UnknownElemTypeI8);
245 bool UnknownElemTypeI8);
248 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
249 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
250 SmallPtrSetImpl<Value *> &Visited,
251 bool UnknownElemTypeI8);
255 deduceOperandElementType(Instruction *
I,
256 SmallPtrSetImpl<Instruction *> *IncompleteRets,
257 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
258 bool IsPostprocessing =
false);
263 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
264 void simplifyNullAddrSpaceCasts();
266 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
267 bool IsPostprocessing);
269 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
271 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
272 bool UnknownElemTypeI8);
274 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
276 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
277 Type *ExpectedElementType,
278 unsigned OperandToReplace,
280 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
281 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
283 void insertConstantsForFPFastMathDefault(
Module &M);
286 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
289 Type *deduceFunParamElementType(
Function *
F,
unsigned OpIdx);
291 SmallPtrSetImpl<Function *> &FVisited);
293 bool deduceOperandElementTypeCalledFunction(
295 Type *&KnownElemTy,
bool &Incomplete);
296 void deduceOperandElementTypeFunctionPointer(
298 Type *&KnownElemTy,
bool IsPostprocessing);
299 bool deduceOperandElementTypeFunctionRet(
300 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
301 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
305 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
306 DenseMap<Function *, CallInst *> Ptrcasts);
308 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
311 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
312 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
313 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
314 SmallPtrSetImpl<Value *> &Visited,
315 DenseMap<Function *, CallInst *> Ptrcasts);
318 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
319 Instruction *Dest,
bool DeleteOld =
true);
323 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
326 bool postprocessTypes(
Module &M);
327 bool processFunctionPointers(
Module &M);
328 void parseFunDeclarations(
Module &M);
329 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
330 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
331 bool convertMaskedMemIntrinsics(
Module &M);
332 void preprocessBoolVectorBitcasts(
Function &
F);
351 bool walkLogicalAccessChain(
352 GetElementPtrInst &
GEP,
353 const std::function<
void(
Type *PointedType, uint64_t Index)>
356 uint64_t Multiplier)> &OnDynamicIndexing);
358 bool walkLogicalAccessChainDynamic(
359 Type *CurType,
Value *Operand, uint64_t Multiplier,
360 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
361 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing);
363 bool walkLogicalAccessChainConstant(
365 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing);
371 Type *getGEPType(GetElementPtrInst *
GEP);
378 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
380 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
383 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
386 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
389 Instruction *visitInsertElementInst(InsertElementInst &
I);
390 Instruction *visitExtractElementInst(ExtractElementInst &
I);
392 Instruction *visitExtractValueInst(ExtractValueInst &
I);
396 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
400 bool runOnModule(
Module &M);
403class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
404 const SPIRVTargetMachine &TM;
408 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
409 : ModulePass(ID), TM(TM) {}
411 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
413 bool runOnModule(
Module &M)
override {
414 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
420 Intrinsic::experimental_convergence_loop,
421 Intrinsic::experimental_convergence_anchor>());
424bool expectIgnoredInIRTranslation(
const Instruction *
I) {
426 Intrinsic::spv_resource_handlefrombinding,
427 Intrinsic::spv_resource_getbasepointer,
428 Intrinsic::spv_resource_getpointer>());
435 return getPointerRoot(V);
441char SPIRVEmitIntrinsicsLegacy::ID = 0;
444 "SPIRV emit intrinsics",
false,
false)
458 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
471 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
477 B.SetCurrentDebugLocation(
I->getDebugLoc());
478 if (
I->getType()->isVoidTy())
479 B.SetInsertPoint(
I->getNextNode());
481 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
491 if (
I->getType()->isTokenTy())
493 "does not support token type",
498 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
499 expectIgnoredInIRTranslation(
I))
510 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
521 std::vector<Value *> Args = {
524 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
527void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
531 if (isTodoType(Src)) {
534 insertTodoType(Dest);
538void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
543 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
544 Src->eraseFromParent();
547 if (Named.
insert(Dest).second)
562 V = V->stripPointerCasts();
583Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
584 bool UnknownElemTypeI8,
585 bool IsPostprocessing) {
589 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
603 if (UnknownElemTypeI8) {
604 if (!IsPostprocessing)
620 B.SetInsertPointPastAllocas(OpA->getParent());
623 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
625 Type *OpTy =
Op->getType();
629 CallInst *PtrCasted =
630 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
635void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
637 DenseMap<Function *, CallInst *> Ptrcasts) {
639 CallInst *PtrCastedI =
nullptr;
640 auto It = Ptrcasts.
find(
F);
641 if (It == Ptrcasts.
end()) {
642 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
643 Ptrcasts[
F] = PtrCastedI;
645 PtrCastedI = It->second;
647 I->replaceUsesOfWith(
Op, PtrCastedI);
650void SPIRVEmitIntrinsicsImpl::propagateElemType(
652 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
653 DenseMap<Function *, CallInst *> Ptrcasts;
655 for (
auto *U :
Users) {
658 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
663 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
664 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
668void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
670 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
671 SmallPtrSet<Value *, 0> Visited;
672 DenseMap<Function *, CallInst *> Ptrcasts;
673 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
674 std::move(Ptrcasts));
677void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
679 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
680 SmallPtrSetImpl<Value *> &Visited,
681 DenseMap<Function *, CallInst *> Ptrcasts) {
685 for (
auto *U :
Users) {
688 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
693 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
694 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
701Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
702 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
703 SmallPtrSet<Value *, 0> Visited;
704 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
708Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
709 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
710 bool UnknownElemTypeI8) {
715 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
726Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
727 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
739 for (User *OpU :
Op->users()) {
741 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
753 Function *CalledF,
unsigned OpIdx) {
754 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
763Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
764 bool UnknownElemTypeI8) {
765 SmallPtrSet<Value *, 0> Visited;
766 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
769void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
771 bool UnknownElemTypeI8) {
773 if (!UnknownElemTypeI8)
782bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
783 Type *CurType,
Value *Operand, uint64_t Multiplier,
784 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
785 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
791 if (
ST->getNumElements() == 0)
793 CurType =
ST->getElementType(0);
794 OnLiteralIndexing(CurType, 0);
802 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
803 return AT ==
nullptr;
806bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
808 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
813 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
817 CurType = AT->getElementType();
818 OnLiteralIndexing(CurType, Index);
820 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
823 const auto &STL =
DL.getStructLayout(ST);
824 unsigned Element = STL->getElementContainingOffset(
Offset);
825 Offset -= STL->getElementOffset(Element);
826 CurType =
ST->getElementType(Element);
827 OnLiteralIndexing(CurType, Element);
829 Type *EltTy = VT->getElementType();
830 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
831 assert(EltSizeBits % 8 == 0 &&
832 "Element type size in bits must be a multiple of 8.");
833 uint32_t EltTypeSize = EltSizeBits / 8;
838 OnLiteralIndexing(CurType, Index);
848bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
849 GetElementPtrInst &
GEP,
850 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
851 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
854 std::optional<uint64_t> MultiplierOpt =
855 getByteAddressingMultiplier(
GEP.getSourceElementType());
856 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
857 uint64_t Multiplier = *MultiplierOpt;
860 Value *Src = getPointerRoot(
GEP.getPointerOperand());
861 Type *CurType = deduceElementType(Src,
true);
865 return walkLogicalAccessChainConstant(
866 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
868 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
869 OnLiteralIndexing, OnDynamicIndexing);
872Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
873 GetElementPtrInst &
GEP) {
876 B.SetInsertPoint(&
GEP);
878 std::vector<Value *> Indices;
879 Indices.push_back(ConstantInt::get(
880 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
881 walkLogicalAccessChain(
883 [&Indices, &
B](
Type *EltType, uint64_t Index) {
885 ConstantInt::get(
B.getInt64Ty(), Index,
false));
888 uint64_t Multiplier) {
890 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
892 if (Multiplier == EltTypeSize) {
894 }
else if (EltTypeSize % Multiplier == 0) {
897 EltTypeSize / Multiplier,
901 ConstantInt::get(
Offset->getType(), Multiplier,
904 Index =
B.CreateUDiv(Index,
905 ConstantInt::get(
Offset->getType(), EltTypeSize,
909 Indices.push_back(Index);
913 SmallVector<Value *, 4>
Args;
914 Args.push_back(
B.getInt1(
GEP.isInBounds()));
915 Args.push_back(
GEP.getOperand(0));
918 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
919 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
923Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
925 Type *CurType =
GEP->getResultElementType();
927 bool Interrupted = walkLogicalAccessChain(
928 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
929 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
931 return Interrupted ?
GEP->getResultElementType() : CurType;
934Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
935 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
937 return getGEPTypeLogical(
Ref);
944 Ty =
Ref->getSourceElementType();
948 Ty =
Ref->getResultElementType();
953Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
954 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
955 bool IgnoreKnownType) {
961 if (!IgnoreKnownType)
973 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
975 Ty = getGEPType(
Ref);
977 Ty = SGEP->getResultElementType();
982 KnownTy =
Op->getType();
984 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
987 Ty = SPIRV::getOriginalFunctionType(*Fn);
990 Ty = deduceElementTypeByValueDeep(
992 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
996 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
998 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1000 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1002 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1004 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1009 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1013 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1015 Type *BestTy =
nullptr;
1017 DenseMap<Type *, unsigned> PhiTys;
1018 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1019 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1026 if (It.first->second > MaxN) {
1027 MaxN = It.first->second;
1035 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1039 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1040 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1045 static StringMap<unsigned> ResTypeByArg = {
1049 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1050 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1051 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1052 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1053 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1054 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1058 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1059 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1061 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1062 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1063 for (User *U :
II->users()) {
1068 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1070 Ty = HandleType->getTypeParameter(0);
1071 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1085 }
else if (
II &&
II->getIntrinsicID() ==
1086 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1090 std::string DemangledName =
1092 if (DemangledName.length() > 0)
1093 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1094 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1095 if (AsArgIt != ResTypeByArg.
end())
1096 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1097 Visited, UnknownElemTypeI8);
1104 if (Ty && !IgnoreKnownType) {
1115Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1116 bool UnknownElemTypeI8) {
1117 SmallPtrSet<Value *, 0> Visited;
1118 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1121Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1122 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1123 bool UnknownElemTypeI8) {
1132 if (!Visited.
insert(U).second)
1137 bool Change =
false;
1138 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1140 assert(
Op &&
"Operands should not be null.");
1141 Type *OpTy =
Op->getType();
1144 if (
Type *NestedTy =
1145 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1152 Change |= Ty != OpTy;
1160 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1161 Type *OpTy = ArrTy->getElementType();
1164 if (
Type *NestedTy =
1165 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1172 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1178 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1179 Type *OpTy = VecTy->getElementType();
1182 if (
Type *NestedTy =
1183 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1190 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1200Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1201 bool UnknownElemTypeI8) {
1202 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1204 if (!UnknownElemTypeI8)
1207 return IntegerType::getInt8Ty(
I->getContext());
1211 Value *PointerOperand) {
1217 return I->getType();
1225bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1227 Type *&KnownElemTy,
bool &Incomplete) {
1231 std::string DemangledName =
1233 if (DemangledName.length() > 0 &&
1235 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1236 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1237 DemangledName,
ST.getPreferredInstructionSet());
1238 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1239 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1245 KnownElemTy = ElemTy;
1246 Ops.push_back(std::make_pair(
Op, i));
1248 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1255 case SPIRV::OpAtomicFAddEXT:
1256 case SPIRV::OpAtomicFMinEXT:
1257 case SPIRV::OpAtomicFMaxEXT:
1258 case SPIRV::OpAtomicLoad:
1259 case SPIRV::OpAtomicCompareExchangeWeak:
1260 case SPIRV::OpAtomicCompareExchange:
1261 case SPIRV::OpAtomicExchange:
1262 case SPIRV::OpAtomicIAdd:
1263 case SPIRV::OpAtomicISub:
1264 case SPIRV::OpAtomicOr:
1265 case SPIRV::OpAtomicXor:
1266 case SPIRV::OpAtomicAnd:
1267 case SPIRV::OpAtomicUMin:
1268 case SPIRV::OpAtomicUMax:
1269 case SPIRV::OpAtomicSMin:
1270 case SPIRV::OpAtomicSMax: {
1275 Incomplete = isTodoType(
Op);
1276 Ops.push_back(std::make_pair(
Op, 0));
1278 case SPIRV::OpAtomicStore: {
1287 Incomplete = isTodoType(
Op);
1288 Ops.push_back(std::make_pair(
Op, 0));
1297void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1299 Type *&KnownElemTy,
bool IsPostprocessing) {
1303 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1304 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1305 bool IsNewFTy =
false, IsIncomplete =
false;
1308 Type *ArgTy = Arg->getType();
1313 if (isTodoType(Arg))
1314 IsIncomplete =
true;
1316 IsIncomplete =
true;
1319 ArgTy = FTy->getFunctionParamType(ParmIdx);
1323 Type *RetTy = FTy->getReturnType();
1330 IsIncomplete =
true;
1332 IsIncomplete =
true;
1335 if (!IsPostprocessing && IsIncomplete)
1338 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1341bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1342 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1343 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1355 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1356 for (User *U :
F->users()) {
1364 propagateElemType(CI, PrevElemTy, VisitedSubst);
1374 for (Instruction *IncompleteRetI : *IncompleteRets)
1375 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1377 }
else if (IncompleteRets) {
1388void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1389 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1390 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1392 Type *KnownElemTy =
nullptr;
1393 bool Incomplete =
false;
1399 Incomplete = isTodoType(
I);
1400 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1403 Ops.push_back(std::make_pair(
Op, i));
1409 Incomplete = isTodoType(
I);
1410 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1417 Incomplete = isTodoType(
I);
1418 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1422 KnownElemTy =
Ref->getSourceElementType();
1423 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1428 KnownElemTy =
Ref->getBaseType();
1429 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1432 KnownElemTy =
I->getType();
1439 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1448 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1452 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1457 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1465 Incomplete = isTodoType(
Ref->getPointerOperand());
1466 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1474 Incomplete = isTodoType(
Ref->getPointerOperand());
1475 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1481 Incomplete = isTodoType(
I);
1482 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1485 Ops.push_back(std::make_pair(
Op, i));
1493 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1494 IsPostprocessing, KnownElemTy,
Op,
1497 Incomplete = isTodoType(CurrF);
1498 Ops.push_back(std::make_pair(
Op, 0));
1504 bool Incomplete0 = isTodoType(Op0);
1505 bool Incomplete1 = isTodoType(Op1);
1507 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1509 : GR->findDeducedElementType(Op0);
1511 KnownElemTy = ElemTy0;
1512 Incomplete = Incomplete0;
1513 Ops.push_back(std::make_pair(Op1, 1));
1514 }
else if (ElemTy1) {
1515 KnownElemTy = ElemTy1;
1516 Incomplete = Incomplete1;
1517 Ops.push_back(std::make_pair(Op0, 0));
1521 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1522 else if (HaveFunPtrs)
1523 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1528 if (!KnownElemTy ||
Ops.size() == 0)
1533 for (
auto &OpIt :
Ops) {
1537 Type *AskTy =
nullptr;
1538 CallInst *AskCI =
nullptr;
1539 if (IsPostprocessing && AskOps) {
1545 if (Ty == KnownElemTy)
1548 Type *OpTy =
Op->getType();
1554 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1561 else if (!IsPostprocessing)
1565 if (AssignCI ==
nullptr) {
1574 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1575 std::make_pair(
I,
Op)};
1576 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1580 CallInst *PtrCastI =
1581 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1582 if (OpIt.second == std::numeric_limits<unsigned>::max())
1585 I->setOperand(OpIt.second, PtrCastI);
1591void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1596 if (isAssignTypeInstr(U)) {
1597 B.SetInsertPoint(U);
1598 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1599 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1600 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1602 U->eraseFromParent();
1605 U->replaceUsesOfWith(Old, New);
1613 Type *NewArgTy =
New->getType();
1615 if (NewArgTy != ExpectedArgTy) {
1618 M, Intrinsic::spv_abort, {NewArgTy});
1628 "aggregate PHI/select/freeze should have been mutated to value-id "
1630 U->replaceUsesOfWith(Old, New);
1635 New->copyMetadata(*Old);
1641 bool HasPoisonExt) {
1648 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1649 "lowered as undef\n");
1651 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1652 Type *Ty = UV->getType();
1658 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1659 :
B.CreateIntrinsicWithoutFolding(IID, {});
1660 AggrConsts[
Call] = UV;
1661 AggrConstTypes[
Call] = Ty;
1666 return B.CreateIntrinsic(IID, {Ty}, {});
1673void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1678 SmallVector<Instruction *, 16> Insts;
1682 for (Instruction *
I : Insts) {
1683 bool BPrepared =
false;
1685 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1689 bool IsScalar = !
Op->getType()->isAggregateType();
1692 if (IsScalar && !AsPoison)
1696 if (IsScalar && Phi)
1697 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1698 else if (!BPrepared) {
1702 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1703 I->setOperand(Idx, Repl);
1712void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1716 ASC->replaceAllUsesWith(
1718 ASC->eraseFromParent();
1726 if (!V->getType()->isAggregateType())
1735 I.getType()->isAggregateType();
1741void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1744 for (Use &U :
I->operands()) {
1751 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1756 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1758 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1764void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1768 std::queue<Instruction *> Worklist;
1772 while (!Worklist.empty()) {
1773 auto *
I = Worklist.front();
1776 bool KeepInst =
false;
1777 for (
const auto &
Op :
I->operands()) {
1779 Type *ResTy =
nullptr;
1782 ResTy = COp->getType();
1794 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1797 auto PrepareInsert = [&]() {
1800 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1801 :
B.SetInsertPoint(
I);
1806 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1807 Args.push_back(COp->getElementAsConstant(i));
1813 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1822 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1828 auto *CI =
B.CreateIntrinsicWithoutFolding(
1829 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1833 AggrConsts[CI] = AggrConst;
1834 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1846 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1851 unsigned RoundingModeDeco,
1858 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1867 MDNode *SaturatedConversionNode =
1869 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1889 MDString *ConstraintString =
1894 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1898 B.SetInsertPoint(&
Call);
1899 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1904void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1907 if (!
RM.has_value())
1909 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1910 switch (
RM.value()) {
1914 case RoundingMode::NearestTiesToEven:
1915 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1917 case RoundingMode::TowardNegative:
1918 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1920 case RoundingMode::TowardPositive:
1921 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1923 case RoundingMode::TowardZero:
1924 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1926 case RoundingMode::Dynamic:
1927 case RoundingMode::NearestTiesToAway:
1931 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1937Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1941 B.SetInsertPoint(&
I);
1942 SmallVector<Value *, 4>
Args;
1944 Args.push_back(
I.getCondition());
1947 for (
auto &Case :
I.cases()) {
1948 Args.push_back(Case.getCaseValue());
1949 BBCases.
push_back(Case.getCaseSuccessor());
1952 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1953 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1957 I.eraseFromParent();
1960 B.SetInsertPoint(ParentBB);
1961 IndirectBrInst *BrI =
B.CreateIndirectBr(
1964 for (BasicBlock *BBCase : BBCases)
1973Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
1979 B.SetInsertPoint(&
I);
1981 SmallVector<Value *, 4>
Args;
1982 Args.push_back(
B.getInt1(
true));
1983 Args.push_back(
I.getOperand(0));
1984 Args.push_back(
B.getInt32(0));
1985 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1986 Args.push_back(SGEP->getIndexOperand(J));
1989 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1990 replaceAllUsesWithAndErase(
B, &
I, NewI);
1995SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
1997 B.SetInsertPoint(&
I);
2002 unsigned N = RetVTy->getNumElements();
2003 Value *PtrOp =
I.getPointerOperand();
2005 Type *ResultPtrTy = RetVTy->getElementType();
2008 Value *InBounds =
B.getInt1(
I.isInBounds());
2009 Type *LanePointeeTy = getGEPType(&
I);
2010 Type *SrcElemTy =
I.getSourceElementType();
2019 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2020 Value *LaneIdx =
B.getInt32(Lane);
2021 Value *ScalarPtr = PtrOp;
2025 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2029 SmallVector<Value *, 4>
Args;
2030 Args.push_back(InBounds);
2031 Args.push_back(ScalarPtr);
2032 for (
Value *Idx :
I.indices()) {
2034 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
2036 Args.push_back(Idx);
2038 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2040 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2044 replaceAllUsesWithAndErase(
B, &
I, NewI);
2062 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2063 return buildLogicalAccessChainFromGEP(
I);
2068 Value *PtrOp =
I.getPointerOperand();
2069 Type *SrcElemTy =
I.getSourceElementType();
2070 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2073 if (ArrTy->getElementType() == SrcElemTy) {
2075 Type *FirstIdxType =
I.getOperand(1)->getType();
2076 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2077 for (
Value *Idx :
I.indices())
2081 SmallVector<Value *, 4>
Args;
2082 Args.push_back(
B.getInt1(
I.isInBounds()));
2083 Args.push_back(
I.getPointerOperand());
2086 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2088 replaceAllUsesWithAndErase(
B, &
I, NewI);
2095 SmallVector<Value *, 4>
Args;
2096 Args.push_back(
B.getInt1(
I.isInBounds()));
2099 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2100 replaceAllUsesWithAndErase(
B, &
I, NewI);
2104Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2106 B.SetInsertPoint(&
I);
2115 I.eraseFromParent();
2122 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2123 replaceAllUsesWithAndErase(
B, &
I, NewI);
2127void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2129 Type *VTy =
V->getType();
2134 if (ElemTy != AssignedType)
2147 if (CurrentType == AssignedType)
2154 " for value " +
V->getName(),
2162void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2163 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2168 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2169 if (PointerElemTy == ExpectedElementType ||
2175 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2177 bool FirstPtrCastOrAssignPtrType =
true;
2183 for (
auto User :
Pointer->users()) {
2186 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2187 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2188 II->getOperand(0) != Pointer)
2193 FirstPtrCastOrAssignPtrType =
false;
2194 if (
II->getOperand(1) != VMD ||
2201 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2206 if (
II->getParent() !=
I->getParent())
2209 I->setOperand(OperandToReplace,
II);
2224 if (FirstPtrCastOrAssignPtrType) {
2229 }
else if (isTodoType(Pointer)) {
2230 eraseTodoType(Pointer);
2238 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2239 std::make_pair(
I, Pointer)};
2241 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2253 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2259void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2264 replacePointerOperandWithPtrCast(
2265 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2271 Type *OpTy =
Op->getType();
2274 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2277 if (OpTy ==
Op->getType())
2278 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2279 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2284 Type *OpTy = LI->getType();
2289 Type *NewOpTy = OpTy;
2290 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2291 if (OpTy == NewOpTy)
2292 insertTodoType(Pointer);
2295 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2300 Type *OpTy =
nullptr;
2312 OpTy = GEPI->getSourceElementType();
2314 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2316 insertTodoType(Pointer);
2328 std::string DemangledName =
2332 bool HaveTypes =
false;
2333 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2350 for (User *U : CalledArg->
users()) {
2352 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2358 HaveTypes |= ElemTy !=
nullptr;
2363 if (DemangledName.empty() && !HaveTypes)
2366 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2381 Type *ExpectedType =
2382 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2383 if (!ExpectedType && !DemangledName.empty())
2384 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2385 DemangledName, OpIdx,
I->getContext());
2386 if (!ExpectedType || ExpectedType->
isVoidTy())
2394 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2399SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2406 I.getOperand(1)->getType(),
2407 I.getOperand(2)->getType()};
2409 B.SetInsertPoint(&
I);
2411 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2413 replaceAllUsesWithAndErase(
B, &
I, NewI);
2418SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2425 B.SetInsertPoint(&
I);
2427 I.getIndexOperand()->getType()};
2428 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2429 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2431 replaceAllUsesWithAndErase(
B, &
I, NewI);
2435Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2437 B.SetInsertPoint(&
I);
2440 Value *AggregateOp =
I.getAggregateOperand();
2444 Args.push_back(AggregateOp);
2445 Args.push_back(
I.getInsertedValueOperand());
2446 for (
auto &
Op :
I.indices())
2447 Args.push_back(
B.getInt32(
Op));
2449 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2450 replaceMemInstrUses(&
I, NewI,
B);
2455SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2457 B.SetInsertPoint(&
I);
2458 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2467 for (
auto &
Op :
I.indices())
2468 Args.push_back(
B.getInt32(
Op));
2469 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2470 {
I.getType()}, {
Args});
2476 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2477 AggrConstTypes[NewI] =
I.getType();
2479 replaceMemInstrUses(&
I, NewI,
B);
2482 replaceAllUsesWithAndErase(
B, &
I, NewI);
2486 for (
const Use &U : NewI->
uses()) {
2487 User *Usr =
U.getUser();
2489 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2500 if (ArgNo < FT->getNumParams() &&
2501 !FT->getParamType(ArgNo)->isAggregateType()) {
2510Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2511 if (!
I.getType()->isAggregateType())
2514 B.SetInsertPoint(&
I);
2515 TrackConstants =
false;
2520 unsigned IntrinsicId;
2521 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2522 if (!
I.isAtomic()) {
2523 IntrinsicId = Intrinsic::spv_load;
2524 Args.push_back(
B.getInt32(
I.getAlign().value()));
2526 IntrinsicId = Intrinsic::spv_atomic_load;
2527 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2529 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2530 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2532 replaceMemInstrUses(&
I, NewI,
B);
2536Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2540 B.SetInsertPoint(&
I);
2541 TrackConstants =
false;
2545 auto *PtrOp =
I.getPointerOperand();
2547 if (
I.getValueOperand()->getType()->isAggregateType()) {
2555 "Unexpected argument of aggregate type, should be spv_extractv!");
2559 unsigned IntrinsicId;
2560 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2562 if (!
I.isAtomic()) {
2563 IntrinsicId = Intrinsic::spv_store;
2564 Args.push_back(
B.getInt32(
I.getAlign().value()));
2566 IntrinsicId = Intrinsic::spv_atomic_store;
2567 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2570 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2572 I.eraseFromParent();
2576Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2577 Value *ArraySize =
nullptr;
2578 if (
I.isArrayAllocation()) {
2581 SPIRV::Extension::SPV_INTEL_variable_length_array))
2583 "array allocation: this instruction requires the following "
2584 "SPIR-V extension: SPV_INTEL_variable_length_array",
2586 ArraySize =
I.getArraySize();
2589 B.SetInsertPoint(&
I);
2590 TrackConstants =
false;
2591 Type *PtrTy =
I.getType();
2594 ?
B.CreateIntrinsicWithoutFolding(
2595 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2596 {ArraySize,
B.getInt32(
I.getAlign().value())})
2597 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2598 {
B.getInt32(
I.getAlign().value())});
2599 replaceAllUsesWithAndErase(
B, &
I, NewI);
2604SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2605 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2607 B.SetInsertPoint(&
I);
2610 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2614 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2615 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2616 uint32_t ScSem =
static_cast<uint32_t
>(
2625 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2626 replaceMemInstrUses(&
I, NewI,
B);
2635 case Intrinsic::spv_abort:
2637 case Intrinsic::trap:
2638 case Intrinsic::ubsantrap:
2640 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2660 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2661 "abort-like call must be the last non-debug instruction before its "
2662 "block's terminator");
2666Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2667 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2671 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2678 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2692 while (!Stack.empty()) {
2693 const Value *V = Stack.pop_back_val();
2694 if (!Visited.
insert(V).second)
2702 Stack.append(
C->user_begin(),
C->user_end());
2718 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2719 if (UserFunctions.contains(
F))
2724 if (!UserFunctions.empty())
2729 const Module &M = *
F->getParent();
2730 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2731 return F == &FirstDefinition;
2734Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2736 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2737 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2739 AggrConstTypes[Leaf] = ElemTy;
2742 SmallVector<Value *, 4> Elems;
2744 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2747 DenseMap<Type *, Instruction *> LeafByType;
2748 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2750 auto &
Entry = LeafByType[ElemTy];
2752 Entry = MakeLeaf(ElemTy);
2756 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2757 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2759 AggrConstTypes[Composite] = AggrTy;
2768void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2773 for (BasicBlock &BB : Func) {
2777 Value *RetVal = RI->getReturnValue();
2784 B.SetInsertPoint(RI);
2786 for (uint64_t
I = 0;
I < NumElts; ++
I) {
2787 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2788 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2790 RI->setOperand(0, Rebuilt);
2794void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2804 deduceElementTypeHelper(&GV,
false);
2809 Value *InitOp = Init;
2816 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2817 {
B.getInt32Ty()}, {});
2822 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2827 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2828 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2834 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2840bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2842 bool UnknownElemTypeI8) {
2848 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2855void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2858 static StringMap<unsigned> ResTypeWellKnown = {
2859 {
"async_work_group_copy", WellKnownTypes::Event},
2860 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2861 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2865 bool IsKnown =
false;
2870 std::string DemangledName =
2873 if (DemangledName.length() > 0)
2875 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2876 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2877 if (ResIt != ResTypeWellKnown.
end()) {
2880 switch (ResIt->second) {
2881 case WellKnownTypes::Event:
2888 switch (DecorationId) {
2891 case FPDecorationId::SAT:
2894 case FPDecorationId::RTE:
2896 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2898 case FPDecorationId::RTZ:
2900 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2902 case FPDecorationId::RTP:
2904 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2906 case FPDecorationId::RTN:
2908 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2914 Type *Ty =
I->getType();
2917 Type *TypeToAssign = Ty;
2920 auto It = AggrConstTypes.
find(
II);
2921 if (It == AggrConstTypes.
end())
2923 TypeToAssign = It->second;
2924 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2925 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2926 TypeToAssign = It->second;
2928 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2929 TypeToAssign = It->second;
2933 for (
const auto &
Op :
I->operands()) {
2940 Type *OpTy =
Op->getType();
2942 CallInst *AssignCI =
2947 Type *OpTy =
Op->getType();
2962 CallInst *AssignCI =
2972bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
2973 Instruction *Inst) {
2975 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2985void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
2987 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2989 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2994 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2995 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2996 if (shouldTryToAddMemAliasingDecoration(
I)) {
2997 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2998 ? SPIRV::Decoration::AliasScopeINTEL
2999 : SPIRV::Decoration::NoAliasINTEL;
3001 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3004 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3005 {
I->getType()}, {
Args});
3009 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3010 processMemAliasingDecoration(LLVMContext::MD_noalias);
3013 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3015 bool AllowFPMaxError =
3017 if (!AllowFPMaxError)
3021 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3025 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
3029 auto &Ctx =
B.getContext();
3031 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
3034 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3036 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3037 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3040 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
3042 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
3044 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3052 &FPFastMathDefaultInfoMap,
3054 auto it = FPFastMathDefaultInfoMap.
find(
F);
3055 if (it != FPFastMathDefaultInfoMap.
end())
3063 SPIRV::FPFastMathMode::None);
3065 SPIRV::FPFastMathMode::None);
3067 SPIRV::FPFastMathMode::None);
3068 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3074 size_t BitWidth = Ty->getScalarSizeInBits();
3078 assert(Index >= 0 && Index < 3 &&
3079 "Expected FPFastMathDefaultInfo for half, float, or double");
3080 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3081 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3082 return FPFastMathDefaultInfoVec[Index];
3085void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3087 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3096 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3098 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3106 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3109 [[maybe_unused]] GlobalVariable *GV =
3110 new GlobalVariable(M,
3111 Type::getInt32Ty(
M.getContext()),
3125 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3126 FPFastMathDefaultInfoMap;
3128 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3137 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3139 "Expected 4 operands for FPFastMathDefault");
3145 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3147 SPIRV::FPFastMathDefaultInfo &
Info =
3150 Info.FPFastMathDefault =
true;
3151 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3153 "Expected no operands for ContractionOff");
3157 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3159 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3160 Info.ContractionOff =
true;
3162 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3164 "Expected 1 operand for SignedZeroInfNanPreserve");
3165 unsigned TargetWidth =
3170 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3174 assert(Index >= 0 && Index < 3 &&
3175 "Expected FPFastMathDefaultInfo for half, float, or double");
3176 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3177 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3178 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3182 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3183 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3184 if (FPFastMathDefaultInfoVec.
empty())
3187 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3188 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3191 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3192 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3196 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3198 "and AllowContract");
3200 if (
Info.SignedZeroInfNanPreserve &&
3202 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3203 SPIRV::FPFastMathMode::NSZ))) {
3204 if (
Info.FPFastMathDefault)
3206 "SignedZeroInfNanPreserve but at least one of "
3207 "NotNaN/NotInf/NSZ is enabled.");
3210 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3211 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3212 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3214 "AllowTransform requires AllowReassoc and "
3215 "AllowContract to be set.");
3218 auto it = GlobalVars.
find(Flags);
3219 GlobalVariable *GV =
nullptr;
3220 if (it != GlobalVars.
end()) {
3226 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3229 GV =
new GlobalVariable(M,
3230 Type::getInt32Ty(
M.getContext()),
3235 GlobalVars[
Flags] = GV;
3241void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3244 bool IsConstComposite =
3245 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3246 if (IsConstComposite && TrackConstants) {
3248 auto t = AggrConsts.
find(
I);
3252 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3254 NewOp->setArgOperand(0,
I);
3257 for (
const auto &
Op :
I->operands()) {
3261 unsigned OpNo =
Op.getOperandNo();
3262 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3263 (!
II->isBundleOperand(OpNo) &&
3264 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3268 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3269 :
B.SetInsertPoint(
I);
3272 Type *OpTy =
Op->getType();
3280 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3282 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3283 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3285 SmallVector<Value *, 2>
Args = {
3288 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3294 I->setOperand(OpNo, NewOp);
3300Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3302 SmallPtrSet<Function *, 0> FVisited;
3303 return deduceFunParamElementType(
F, OpIdx, FVisited);
3306Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3307 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3309 if (!FVisited.
insert(
F).second)
3312 SmallPtrSet<Value *, 0> Visited;
3315 for (User *U :
F->users()) {
3317 if (!CI || OpIdx >= CI->
arg_size())
3327 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3330 for (User *OpU : OpArg->
users()) {
3332 if (!Inst || Inst == CI)
3335 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3342 if (FVisited.
find(OuterF) != FVisited.
end())
3344 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3345 if (OuterF->
getArg(i) == OpArg) {
3346 Lookup.push_back(std::make_pair(OuterF, i));
3353 for (
auto &Pair :
Lookup) {
3354 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3361void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3363 B.SetInsertPointPastAllocas(
F);
3364 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3370 for (User *U : Arg->
users()) {
3372 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3390 for (User *U :
F->users()) {
3392 if (!CI || OpIdx >= CI->
arg_size())
3406 for (User *U : Arg->
users()) {
3410 CI->
getParent()->getParent() == CurrF) {
3412 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3424 B.SetInsertPointPastAllocas(
F);
3425 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3430 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3432 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3434 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3446 bool IsNewFTy =
false;
3462bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3465 if (
F.isIntrinsic())
3467 if (
F.isDeclaration()) {
3468 for (User *U :
F.users()) {
3481 for (User *U :
F.users()) {
3483 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3485 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3486 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3493 if (Worklist.
empty())
3496 LLVMContext &Ctx =
M.getContext();
3503 for (
const auto &Arg :
F->args())
3505 IRB.CreateCall(
F, Args);
3507 IRB.CreateRetVoid();
3513void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3514 DenseMap<Function *, CallInst *> Ptrcasts;
3515 for (
auto It : FDeclPtrTys) {
3517 for (
auto *U :
F->users()) {
3522 for (
auto [Idx, ElemTy] : It.second) {
3530 B.SetInsertPointPastAllocas(Arg->
getParent());
3534 }
else if (isaGEP(Param)) {
3535 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3544 .getFirstNonPHIOrDbgOrAlloca());
3564GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3565 GetElementPtrInst *
GEP) {
3572 Type *SrcTy =
GEP->getSourceElementType();
3573 SmallVector<Value *, 8> Indices(
GEP->indices());
3575 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3576 Indices.erase(Indices.begin());
3577 SrcTy = ArrTy->getElementType();
3579 GEP->getNoWrapFlags(),
"",
3580 GEP->getIterator());
3585void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3592 if (
ST->canUseExtension(
3593 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3594 for (BasicBlock &BB :
F) {
3596 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3600 SmallVector<unsigned, 1>
Ops =
3602 unsigned LC =
Ops[0];
3603 if (LC == SPIRV::LoopControl::None)
3607 B.SetInsertPoint(Term);
3608 SmallVector<Value *, 4> IntrArgs;
3609 for (
unsigned Op :
Ops)
3611 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3632 SmallVector<unsigned, 1> LoopControlOps =
3634 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3638 B.SetInsertPoint(Header->getTerminator());
3641 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3642 for (
unsigned Imm : LoopControlOps)
3643 Args.emplace_back(
B.getInt32(Imm));
3644 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3648bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3649 if (
Func.isDeclaration())
3653 GR =
ST.getSPIRVGlobalRegistry();
3657 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3662 AggrConstTypes.
clear();
3665 processParamTypesByFunHeader(CurrF,
B);
3669 SmallPtrSet<Instruction *, 4> DeadInsts;
3672 Type *ElTy =
SI->getValueOperand()->getType();
3681 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3685 GR->addDeducedElementType(SGEP,
3690 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3692 GEP->replaceAllUsesWith(NewGEP);
3696 if (
Type *GepTy = getGEPType(
GEP))
3700 for (
auto *
I : DeadInsts) {
3701 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3702 I->eraseFromParent();
3705 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3706 for (
auto &GV :
Func.getParent()->globals())
3707 processGlobalValue(GV,
B);
3709 reconstructAggregateReturns(Func,
B);
3710 preprocessUndefsAndPoisons(
B);
3711 simplifyNullAddrSpaceCasts();
3712 preprocessCompositeConstants(
B);
3720 Type *I32Ty =
B.getInt32Ty();
3725 insertCompositeAggregateArms(&
I,
B);
3726 AggrConstTypes[&
I] =
I.getType();
3727 I.mutateType(I32Ty);
3730 preprocessBoolVectorBitcasts(Func);
3731 SmallVector<Instruction *> Worklist(
3734 applyDemangledPtrArgTypes(
B);
3737 for (
auto &
I : Worklist) {
3739 if (isConvergenceIntrinsic(
I))
3742 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3744 insertAssignTypeIntrs(
I,
B);
3745 insertPtrCastOrAssignTypeInstr(
I,
B);
3749 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3750 insertAssignPtrTypeIntrs(
I,
B,
true);
3753 useRoundingMode(FPI,
B);
3758 SmallPtrSet<Instruction *, 4> IncompleteRets;
3760 deduceOperandElementType(&
I, &IncompleteRets);
3764 for (BasicBlock &BB : Func)
3765 for (PHINode &Phi : BB.
phis())
3767 deduceOperandElementType(&Phi,
nullptr);
3769 for (
auto *
I : Worklist) {
3770 TrackConstants =
true;
3780 if (isConvergenceIntrinsic(
I))
3784 processInstrAfterVisit(
I,
B);
3787 emitUnstructuredLoopControls(Func,
B);
3793bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3794 if (!GR || TodoTypeSz == 0)
3797 unsigned SzTodo = TodoTypeSz;
3798 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3803 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3804 Type *KnownTy = GR->findDeducedElementType(
Op);
3805 if (!KnownTy || !AssignCI)
3811 SmallPtrSet<Value *, 0> Visited;
3812 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3813 if (ElemTy != KnownTy) {
3814 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3815 propagateElemType(CI, ElemTy, VisitedSubst);
3822 if (
Op->hasUseList()) {
3823 for (User *U :
Op->users()) {
3830 if (TodoTypeSz == 0)
3835 SmallPtrSet<Instruction *, 4> IncompleteRets;
3837 auto It = ToProcess.
find(&
I);
3838 if (It == ToProcess.
end())
3840 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3841 if (It->second.size() == 0)
3843 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3844 if (TodoTypeSz == 0)
3849 return SzTodo > TodoTypeSz;
3853void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
3855 if (!
F.isDeclaration() ||
F.isIntrinsic())
3859 if (DemangledName.empty())
3863 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3864 DemangledName,
ST.getPreferredInstructionSet());
3865 if (Opcode != SPIRV::OpGroupAsyncCopy)
3868 SmallVector<unsigned> Idxs;
3869 for (
unsigned OpIdx = 0; OpIdx <
F.arg_size(); ++OpIdx) {
3877 LLVMContext &Ctx =
F.getContext();
3879 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3880 if (!TypeStrs.
size())
3883 for (
unsigned Idx : Idxs) {
3884 if (Idx >= TypeStrs.
size())
3887 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3890 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3895bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3896 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3898 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3899 if (!
ST.canUseExtension(
3900 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3901 I.getContext().emitError(
3902 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3906 I.eraseFromParent();
3912 Value *Ptrs =
I.getArgOperand(0);
3914 Value *Passthru =
I.getArgOperand(2);
3917 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3919 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3924 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3926 I.eraseFromParent();
3930 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3931 if (!
ST.canUseExtension(
3932 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3933 I.getContext().emitError(
3934 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3937 I.eraseFromParent();
3944 Value *Ptrs =
I.getArgOperand(1);
3949 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3951 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
3955 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3956 I.eraseFromParent();
3967void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
3968 struct BoolVecBitcast {
3970 FixedVectorType *BoolVecTy;
3974 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3976 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3984 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3986 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3990 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3992 Value *Src = BC->getOperand(0);
3993 unsigned BoolVecN = BoolVecTy->getNumElements();
3995 Type *IntTy =
B.getIntNTy(BoolVecN);
4001 IntVal = ConstantInt::get(IntTy, 0);
4002 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4003 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
4004 Value *Ext =
B.CreateZExt(Elem, IntTy);
4006 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
4007 IntVal =
B.CreateOr(IntVal, Ext);
4013 if (!Src->getType()->isIntegerTy())
4014 IntVal =
B.CreateBitCast(Src, IntTy);
4019 if (!SrcIsBoolVec) {
4022 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4025 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
4026 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4032 if (!BC->getDestTy()->isIntegerTy())
4033 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4036 BC->replaceAllUsesWith(Result);
4037 BC->eraseFromParent();
4041bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4045 if (!
F.isIntrinsic())
4048 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4053 Changed |= processMaskedMemIntrinsic(*
II);
4057 F.eraseFromParent();
4063bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4066 Changed |= convertMaskedMemIntrinsics(M);
4068 parseFunDeclarations(M);
4069 insertConstantsForFPFastMathDefault(M);
4080 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4082 processParamTypes(&
F,
B);
4086 CanTodoType =
false;
4087 Changed |= postprocessTypes(M);
4090 Changed |= processFunctionPointers(M);
4097 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4103 return new SPIRVEmitIntrinsicsLegacy(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void replaceAllUsesWith(Value *Old, Value *New, SmallPtrSet< BasicBlock *, 32 > &FreshBBs, bool IsHuge)
Replace all old uses with new ones, and push the updated BBs into FreshBBs.
static Type * getPointeeType(Value *Ptr, const DataLayout &DL)
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
static bool runOnFunction(Function &F, bool PostInlining)
iv Induction Variable Users
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Machine Check Debug Module
uint64_t IntrinsicInst * II
OptimizedStructLayoutField Field
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrConstForceInt32(const Value *V)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, DenseMap< Function *, SPIRV::FPFastMathDefaultInfoVector > &FPFastMathDefaultInfoMap, Function *F)
static Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static void emitAssignName(Instruction *I, IRBuilder<> &B)
static bool isArtificialGlobal(StringRef Name)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void createRoundingModeDecoration(Instruction *I, unsigned RoundingModeDeco, IRBuilder<> &B)
static void createDecorationIntrinsic(Instruction *I, MDNode *Node, IRBuilder<> &B)
static bool hasOnlyArtificialUses(const GlobalVariable &GV)
static bool isAggregateValueIdInstr(const Instruction &I)
static SPIRV::FPFastMathDefaultInfo & getFPFastMathDefaultInfo(SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty)
static bool isAbortCall(const Instruction &I, const SPIRVSubtarget &ST)
static cl::opt< bool > SpirvEmitOpNames("spirv-emit-op-names", cl::desc("Emit OpName for all instructions"), cl::init(false))
static bool tracesToPointerAlloca(Value *V)
static bool isUseListGlobal(StringRef Name)
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool isSpvAggrPlaceholder(const Value *V)
static bool precededByAbortIntrinsic(const UnreachableInst &I, const SPIRVSubtarget &ST)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static bool isMultiRegisterAggregate(Value *V)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
This file defines the SmallPtrSet class.
StringSet - A set-like wrapper for the StringMap.
static SymbolRef::Type getType(const Symbol *Sym)
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
This class represents an incoming formal argument to a Function.
const Function * getParent() const
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
static LLVM_ABI BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI std::optional< RoundingMode > getRoundingMode() const
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Type * getParamType(unsigned i) const
Parameter type accessors.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Type * getReturnType() const
Returns the type of the ret val.
Argument * getArg(unsigned i) const
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static LLVM_ABI Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static unsigned getPointerOperandIndex()
PointerType * getType() const
Global values are always pointers.
@ InternalLinkage
Rename collisions when linking (static functions).
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI void addDestination(BasicBlock *Dest)
Add a destination.
Base class for instruction visitors.
LLVM_ABI bool isDebugOrPseudoInst() const LLVM_READONLY
Return true if the instruction is a DbgInfoIntrinsic or PseudoProbeInst.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
static unsigned getPointerOperandIndex()
SmallVector< LoopT *, 4 > getLoopsInPreorder() const
Return all of the loops in the function in preorder across the loop nests, with siblings in forward p...
void analyze(ParentT F)
Create the loop forest for a function.
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Flags
Flags values. These may be or'd together.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg)
Type * findDeducedCompositeType(const Value *Val)
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld=true)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
iterator find(ConstPtrType Ptr) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator find(StringRef Key)
Represent a constant reference to a string, i.e.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
const Triple & getTargetTriple() const
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getArrayElementType() const
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
bool isStructTy() const
True if this is an instance of StructType.
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
This function has undefined behavior.
void setOperand(unsigned i, Value *Val)
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
iterator_range< use_iterator > uses()
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
const ParentTy * getParent() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ SPIR_KERNEL
Used for SPIR kernel functions.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
auto m_Value()
Match an arbitrary value and ignore it.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
unsigned getNumElements(Type *Ty)
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
ModulePass * createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
RelativeUniformCounterPtr Values
uint32_t getMemSemanticsWithStorageClass(const Triple &TT, uint32_t OrderSem, uint32_t StorageClassSem)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
bool isUntypedPointerVectorTy(const Type *T)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx, SyncScope::ID Id)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
bool isNestedPointer(const Type *Ty)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
auto reverse(ContainerTy &&C)
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
@ Ref
The access may reference the value stored in memory.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
bool hasInitializer(const GlobalVariable *GV)
Type * normalizeType(Type *Ty)
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 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)