29#include "llvm/IR/IntrinsicsSPIRV.h"
62#define DEBUG_TYPE "spirv-emit-intrinsics"
66 cl::desc(
"Emit OpName for all instructions"),
70#define GET_BuiltinGroup_DECL
71#include "SPIRVGenTables.inc"
76class GlobalVariableUsers {
77 template <
typename T1,
typename T2>
78 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
80 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
82 void collectGlobalUsers(
83 const GlobalVariable *GV,
84 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
85 &GlobalIsUsedByGlobal) {
87 while (!
Stack.empty()) {
91 GlobalIsUsedByFun[GV].insert(
I->getFunction());
96 GlobalIsUsedByGlobal[GV].insert(UserGV);
101 Stack.append(
C->user_begin(),
C->user_end());
105 bool propagateGlobalToGlobalUsers(
106 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
107 &GlobalIsUsedByGlobal) {
110 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
111 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
112 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
113 auto It = GlobalIsUsedByGlobal.find(UserGV);
114 if (It == GlobalIsUsedByGlobal.end())
122 void propagateGlobalToFunctionReferences(
123 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
124 &GlobalIsUsedByGlobal) {
125 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
126 auto &UserFunctions = GlobalIsUsedByFun[GV];
127 for (
const GlobalVariable *UserGV : UserGlobals) {
128 auto It = GlobalIsUsedByFun.find(UserGV);
129 if (It == GlobalIsUsedByFun.end())
140 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
141 GlobalIsUsedByGlobal;
142 GlobalIsUsedByFun.clear();
143 for (GlobalVariable &GV :
M.globals())
144 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
147 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
150 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
153 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
154 const FunctionSetType &
155 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
156 auto It = GlobalIsUsedByFun.find(&GV);
157 if (It != GlobalIsUsedByFun.end())
160 static const FunctionSetType
Empty{};
165static bool isaGEP(
const Value *V) {
171static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
177 return AT->getNumElements();
183class SPIRVEmitIntrinsicsImpl
184 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
185 const SPIRVTargetMachine &TM;
186 SPIRVGlobalRegistry *GR =
nullptr;
188 bool TrackConstants =
true;
189 bool HaveFunPtrs =
false;
190 DenseMap<Instruction *, Constant *> AggrConsts;
191 DenseMap<Instruction *, Type *> AggrConstTypes;
192 SmallPtrSet<Instruction *, 0> AggrStores;
193 GlobalVariableUsers GVUsers;
194 SmallPtrSet<Value *, 0> Named;
197 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
200 bool CanTodoType =
true;
201 unsigned TodoTypeSz = 0;
202 DenseMap<Value *, bool> TodoType;
203 void insertTodoType(
Value *
Op) {
205 if (CanTodoType && !isaGEP(
Op)) {
206 auto It = TodoType.try_emplace(
Op,
true);
211 void eraseTodoType(
Value *
Op) {
212 auto It = TodoType.find(
Op);
213 if (It != TodoType.end() && It->second) {
221 auto It = TodoType.find(
Op);
222 return It != TodoType.end() && It->second;
226 SmallPtrSet<Instruction *, 0> TypeValidated;
229 enum WellKnownTypes { Event };
232 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
233 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
234 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
235 bool UnknownElemTypeI8,
236 bool IgnoreKnownType =
false);
237 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
238 bool UnknownElemTypeI8);
239 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
240 SmallPtrSetImpl<Value *> &Visited,
241 bool UnknownElemTypeI8);
243 SmallPtrSetImpl<Value *> &Visited,
244 bool UnknownElemTypeI8);
246 bool UnknownElemTypeI8);
249 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
250 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
251 SmallPtrSetImpl<Value *> &Visited,
252 bool UnknownElemTypeI8);
256 deduceOperandElementType(Instruction *
I,
257 SmallPtrSetImpl<Instruction *> *IncompleteRets,
258 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
259 bool IsPostprocessing =
false);
264 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
265 void simplifyNullAddrSpaceCasts();
267 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
268 bool IsPostprocessing);
270 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
272 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
273 bool UnknownElemTypeI8);
275 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
277 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
278 Type *ExpectedElementType,
279 unsigned OperandToReplace,
281 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
282 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
284 void insertConstantsForFPFastMathDefault(
Module &M);
286 void reconstructAggregateReturns(Function &Func,
IRBuilder<> &
B);
287 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
289 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
290 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
291 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx,
292 SmallPtrSetImpl<Function *> &FVisited);
294 bool deduceOperandElementTypeCalledFunction(
296 Type *&KnownElemTy,
bool &Incomplete);
297 void deduceOperandElementTypeFunctionPointer(
299 Type *&KnownElemTy,
bool IsPostprocessing);
300 bool deduceOperandElementTypeFunctionRet(
301 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
302 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
305 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
306 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
307 DenseMap<Function *, CallInst *> Ptrcasts);
309 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
312 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
313 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
314 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
315 SmallPtrSetImpl<Value *> &Visited,
316 DenseMap<Function *, CallInst *> Ptrcasts);
319 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
320 Instruction *Dest,
bool DeleteOld =
true);
324 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
327 bool postprocessTypes(
Module &M);
328 bool processFunctionPointers(
Module &M);
329 void parseFunDeclarations(
Module &M);
330 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
331 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
332 bool convertMaskedMemIntrinsics(
Module &M);
333 void preprocessBoolVectorBitcasts(Function &
F);
335 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
352 bool walkLogicalAccessChain(
353 GetElementPtrInst &
GEP,
354 const std::function<
void(
Type *PointedType, uint64_t Index)>
357 uint64_t Multiplier)> &OnDynamicIndexing);
359 bool walkLogicalAccessChainDynamic(
360 Type *CurType,
Value *Operand, uint64_t Multiplier,
361 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
362 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing);
364 bool walkLogicalAccessChainConstant(
366 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing);
372 Type *getGEPType(GetElementPtrInst *
GEP);
379 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
381 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
384 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
387 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
390 Instruction *visitInsertElementInst(InsertElementInst &
I);
391 Instruction *visitExtractElementInst(ExtractElementInst &
I);
393 Instruction *visitExtractValueInst(ExtractValueInst &
I);
397 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
401 bool runOnModule(
Module &M);
404class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
405 const SPIRVTargetMachine &TM;
409 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
410 : ModulePass(ID), TM(TM) {}
412 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
414 bool runOnModule(
Module &M)
override {
415 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
421 Intrinsic::experimental_convergence_loop,
422 Intrinsic::experimental_convergence_anchor>());
425bool expectIgnoredInIRTranslation(
const Instruction *
I) {
427 Intrinsic::spv_resource_handlefrombinding,
428 Intrinsic::spv_resource_getbasepointer,
429 Intrinsic::spv_resource_getpointer>());
436 return getPointerRoot(V);
442char SPIRVEmitIntrinsicsLegacy::ID = 0;
445 "SPIRV emit intrinsics",
false,
false)
459 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
472 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
478 B.SetCurrentDebugLocation(
I->getDebugLoc());
479 if (
I->getType()->isVoidTy())
480 B.SetInsertPoint(
I->getNextNode());
482 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
492 if (
I->getType()->isTokenTy())
494 "does not support token type",
499 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
500 expectIgnoredInIRTranslation(
I))
511 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
522 std::vector<Value *> Args = {
525 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
528void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
532 if (isTodoType(Src)) {
535 insertTodoType(Dest);
539void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
544 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
545 Src->eraseFromParent();
548 if (Named.
insert(Dest).second)
563 V = V->stripPointerCasts();
584Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
585 bool UnknownElemTypeI8,
586 bool IsPostprocessing) {
590 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
604 if (UnknownElemTypeI8) {
605 if (!IsPostprocessing)
613CallInst *SPIRVEmitIntrinsicsImpl::buildSpvPtrcast(Function *
F,
Value *
Op,
621 B.SetInsertPointPastAllocas(OpA->getParent());
624 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
626 Type *OpTy =
Op->getType();
630 CallInst *PtrCasted =
631 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
636void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
638 DenseMap<Function *, CallInst *> Ptrcasts) {
640 CallInst *PtrCastedI =
nullptr;
641 auto It = Ptrcasts.
find(
F);
642 if (It == Ptrcasts.
end()) {
643 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
644 Ptrcasts[
F] = PtrCastedI;
646 PtrCastedI = It->second;
648 I->replaceUsesOfWith(
Op, PtrCastedI);
651void SPIRVEmitIntrinsicsImpl::propagateElemType(
653 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
654 DenseMap<Function *, CallInst *> Ptrcasts;
656 for (
auto *U :
Users) {
659 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
664 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
665 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
669void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
671 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
672 SmallPtrSet<Value *, 0> Visited;
673 DenseMap<Function *, CallInst *> Ptrcasts;
674 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
675 std::move(Ptrcasts));
678void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
680 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
681 SmallPtrSetImpl<Value *> &Visited,
682 DenseMap<Function *, CallInst *> Ptrcasts) {
686 for (
auto *U :
Users) {
689 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
694 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
695 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
702Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
703 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
704 SmallPtrSet<Value *, 0> Visited;
705 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
709Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
710 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
711 bool UnknownElemTypeI8) {
716 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
727Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
728 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
740 for (User *OpU :
Op->users()) {
742 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
755 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
764Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
765 bool UnknownElemTypeI8) {
766 SmallPtrSet<Value *, 0> Visited;
767 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
770void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
772 bool UnknownElemTypeI8) {
774 if (!UnknownElemTypeI8)
783bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
784 Type *CurType,
Value *Operand, uint64_t Multiplier,
785 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
786 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
792 if (
ST->getNumElements() == 0)
794 CurType =
ST->getElementType(0);
795 OnLiteralIndexing(CurType, 0);
803 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
804 return AT ==
nullptr;
807bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
809 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
814 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
818 CurType = AT->getElementType();
819 OnLiteralIndexing(CurType, Index);
821 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
824 const auto &STL =
DL.getStructLayout(ST);
825 unsigned Element = STL->getElementContainingOffset(
Offset);
826 Offset -= STL->getElementOffset(Element);
827 CurType =
ST->getElementType(Element);
828 OnLiteralIndexing(CurType, Element);
830 Type *EltTy = VT->getElementType();
831 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
832 assert(EltSizeBits % 8 == 0 &&
833 "Element type size in bits must be a multiple of 8.");
834 uint32_t EltTypeSize = EltSizeBits / 8;
839 OnLiteralIndexing(CurType, Index);
849bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
850 GetElementPtrInst &
GEP,
851 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
852 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
855 std::optional<uint64_t> MultiplierOpt =
856 getByteAddressingMultiplier(
GEP.getSourceElementType());
857 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
858 uint64_t Multiplier = *MultiplierOpt;
861 Value *Src = getPointerRoot(
GEP.getPointerOperand());
862 Type *CurType = deduceElementType(Src,
true);
866 return walkLogicalAccessChainConstant(
867 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
869 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
870 OnLiteralIndexing, OnDynamicIndexing);
873Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
874 GetElementPtrInst &
GEP) {
877 B.SetInsertPoint(&
GEP);
879 std::vector<Value *> Indices;
880 Indices.push_back(ConstantInt::get(
881 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
882 walkLogicalAccessChain(
884 [&Indices, &
B](
Type *EltType, uint64_t Index) {
886 ConstantInt::get(
B.getInt64Ty(), Index,
false));
889 uint64_t Multiplier) {
891 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
893 if (Multiplier == EltTypeSize) {
895 }
else if (EltTypeSize % Multiplier == 0) {
898 EltTypeSize / Multiplier,
902 ConstantInt::get(
Offset->getType(), Multiplier,
905 Index =
B.CreateUDiv(Index,
906 ConstantInt::get(
Offset->getType(), EltTypeSize,
910 Indices.push_back(Index);
914 SmallVector<Value *, 4>
Args;
915 Args.push_back(
B.getInt1(
GEP.isInBounds()));
916 Args.push_back(
GEP.getOperand(0));
919 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
920 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
924Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
926 Type *CurType =
GEP->getResultElementType();
928 bool Interrupted = walkLogicalAccessChain(
929 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
930 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
932 return Interrupted ?
GEP->getResultElementType() : CurType;
935Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
936 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
938 return getGEPTypeLogical(
Ref);
945 Ty =
Ref->getSourceElementType();
949 Ty =
Ref->getResultElementType();
954Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
955 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
956 bool IgnoreKnownType) {
962 if (!IgnoreKnownType)
974 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
976 Ty = getGEPType(
Ref);
978 Ty = SGEP->getResultElementType();
983 KnownTy =
Op->getType();
985 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
988 Ty = SPIRV::getOriginalFunctionType(*Fn);
991 Ty = deduceElementTypeByValueDeep(
993 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
997 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
999 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1001 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1003 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1005 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1010 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1014 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1016 Type *BestTy =
nullptr;
1018 DenseMap<Type *, unsigned> PhiTys;
1019 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1020 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1027 if (It.first->second > MaxN) {
1028 MaxN = It.first->second;
1036 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1037 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1042 static StringMap<unsigned> ResTypeByArg = {
1046 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1047 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1048 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1049 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1050 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1051 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1055 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1056 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1058 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1059 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1060 for (User *U :
II->users()) {
1065 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1067 Ty = HandleType->getTypeParameter(0);
1068 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1082 }
else if (
II &&
II->getIntrinsicID() ==
1083 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1087 std::string DemangledName =
1089 if (DemangledName.length() > 0)
1090 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1091 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1092 if (AsArgIt != ResTypeByArg.
end())
1093 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1094 Visited, UnknownElemTypeI8);
1101 if (Ty && !IgnoreKnownType) {
1112Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1113 bool UnknownElemTypeI8) {
1114 SmallPtrSet<Value *, 0> Visited;
1115 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1118Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1119 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1120 bool UnknownElemTypeI8) {
1129 if (!Visited.
insert(U).second)
1134 bool Change =
false;
1135 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1137 assert(
Op &&
"Operands should not be null.");
1138 Type *OpTy =
Op->getType();
1141 if (
Type *NestedTy =
1142 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1149 Change |= Ty != OpTy;
1157 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1158 Type *OpTy = ArrTy->getElementType();
1161 if (
Type *NestedTy =
1162 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1169 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1175 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1176 Type *OpTy = VecTy->getElementType();
1179 if (
Type *NestedTy =
1180 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1187 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1197Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1198 bool UnknownElemTypeI8) {
1199 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1201 if (!UnknownElemTypeI8)
1204 return IntegerType::getInt8Ty(
I->getContext());
1208 Value *PointerOperand) {
1214 return I->getType();
1222bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1224 Type *&KnownElemTy,
bool &Incomplete) {
1228 std::string DemangledName =
1230 if (DemangledName.length() > 0 &&
1232 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1233 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1234 DemangledName,
ST.getPreferredInstructionSet());
1235 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1236 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1242 KnownElemTy = ElemTy;
1243 Ops.push_back(std::make_pair(
Op, i));
1245 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1252 case SPIRV::OpAtomicFAddEXT:
1253 case SPIRV::OpAtomicFMinEXT:
1254 case SPIRV::OpAtomicFMaxEXT:
1255 case SPIRV::OpAtomicLoad:
1256 case SPIRV::OpAtomicCompareExchangeWeak:
1257 case SPIRV::OpAtomicCompareExchange:
1258 case SPIRV::OpAtomicExchange:
1259 case SPIRV::OpAtomicIAdd:
1260 case SPIRV::OpAtomicISub:
1261 case SPIRV::OpAtomicOr:
1262 case SPIRV::OpAtomicXor:
1263 case SPIRV::OpAtomicAnd:
1264 case SPIRV::OpAtomicUMin:
1265 case SPIRV::OpAtomicUMax:
1266 case SPIRV::OpAtomicSMin:
1267 case SPIRV::OpAtomicSMax: {
1272 Incomplete = isTodoType(
Op);
1273 Ops.push_back(std::make_pair(
Op, 0));
1275 case SPIRV::OpAtomicStore: {
1284 Incomplete = isTodoType(
Op);
1285 Ops.push_back(std::make_pair(
Op, 0));
1294void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1296 Type *&KnownElemTy,
bool IsPostprocessing) {
1300 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1301 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1302 bool IsNewFTy =
false, IsIncomplete =
false;
1305 Type *ArgTy = Arg->getType();
1310 if (isTodoType(Arg))
1311 IsIncomplete =
true;
1313 IsIncomplete =
true;
1316 ArgTy = FTy->getFunctionParamType(ParmIdx);
1320 Type *RetTy = FTy->getReturnType();
1327 IsIncomplete =
true;
1329 IsIncomplete =
true;
1332 if (!IsPostprocessing && IsIncomplete)
1335 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1338bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1339 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1340 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1352 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1353 for (User *U :
F->users()) {
1361 propagateElemType(CI, PrevElemTy, VisitedSubst);
1371 for (Instruction *IncompleteRetI : *IncompleteRets)
1372 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1374 }
else if (IncompleteRets) {
1385void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1386 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1387 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1389 Type *KnownElemTy =
nullptr;
1390 bool Incomplete =
false;
1396 Incomplete = isTodoType(
I);
1397 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1400 Ops.push_back(std::make_pair(
Op, i));
1406 Incomplete = isTodoType(
I);
1407 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1414 Incomplete = isTodoType(
I);
1415 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1419 KnownElemTy =
Ref->getSourceElementType();
1420 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1425 KnownElemTy =
Ref->getBaseType();
1426 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1429 KnownElemTy =
I->getType();
1436 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1445 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1449 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1454 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1462 Incomplete = isTodoType(
Ref->getPointerOperand());
1463 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1471 Incomplete = isTodoType(
Ref->getPointerOperand());
1472 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1478 Incomplete = isTodoType(
I);
1479 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1482 Ops.push_back(std::make_pair(
Op, i));
1490 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1491 IsPostprocessing, KnownElemTy,
Op,
1494 Incomplete = isTodoType(CurrF);
1495 Ops.push_back(std::make_pair(
Op, 0));
1501 bool Incomplete0 = isTodoType(Op0);
1502 bool Incomplete1 = isTodoType(Op1);
1504 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1506 : GR->findDeducedElementType(Op0);
1508 KnownElemTy = ElemTy0;
1509 Incomplete = Incomplete0;
1510 Ops.push_back(std::make_pair(Op1, 1));
1511 }
else if (ElemTy1) {
1512 KnownElemTy = ElemTy1;
1513 Incomplete = Incomplete1;
1514 Ops.push_back(std::make_pair(Op0, 0));
1518 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1519 else if (HaveFunPtrs)
1520 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1525 if (!KnownElemTy ||
Ops.size() == 0)
1530 for (
auto &OpIt :
Ops) {
1534 Type *AskTy =
nullptr;
1535 CallInst *AskCI =
nullptr;
1536 if (IsPostprocessing && AskOps) {
1542 if (Ty == KnownElemTy)
1545 Type *OpTy =
Op->getType();
1551 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1558 else if (!IsPostprocessing)
1562 if (AssignCI ==
nullptr) {
1571 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1572 std::make_pair(
I,
Op)};
1573 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1577 CallInst *PtrCastI =
1578 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1579 if (OpIt.second == std::numeric_limits<unsigned>::max())
1582 I->setOperand(OpIt.second, PtrCastI);
1588void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1593 if (isAssignTypeInstr(U)) {
1594 B.SetInsertPoint(U);
1595 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1596 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1597 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1599 U->eraseFromParent();
1602 U->replaceUsesOfWith(Old, New);
1610 Type *NewArgTy =
New->getType();
1612 if (NewArgTy != ExpectedArgTy) {
1615 M, Intrinsic::spv_abort, {NewArgTy});
1625 "aggregate PHI/select/freeze should have been mutated to value-id "
1627 U->replaceUsesOfWith(Old, New);
1632 New->copyMetadata(*Old);
1638 bool HasPoisonExt) {
1645 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1646 "lowered as undef\n");
1648 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1649 Type *Ty = UV->getType();
1655 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1656 :
B.CreateIntrinsicWithoutFolding(IID, {});
1657 AggrConsts[
Call] = UV;
1658 AggrConstTypes[
Call] = Ty;
1663 return B.CreateIntrinsic(IID, {Ty}, {});
1670void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1675 SmallVector<Instruction *, 16> Insts;
1679 for (Instruction *
I : Insts) {
1680 bool BPrepared =
false;
1682 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1686 bool IsScalar = !
Op->getType()->isAggregateType();
1689 if (IsScalar && !AsPoison)
1693 if (IsScalar && Phi)
1694 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1695 else if (!BPrepared) {
1699 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1700 I->setOperand(Idx, Repl);
1709void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1713 ASC->replaceAllUsesWith(
1715 ASC->eraseFromParent();
1723 if (!V->getType()->isAggregateType())
1732 I.getType()->isAggregateType();
1738void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1741 for (Use &U :
I->operands()) {
1748 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1753 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1755 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1761void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1765 std::queue<Instruction *> Worklist;
1769 while (!Worklist.empty()) {
1770 auto *
I = Worklist.front();
1773 bool KeepInst =
false;
1774 for (
const auto &
Op :
I->operands()) {
1776 Type *ResTy =
nullptr;
1779 ResTy = COp->getType();
1791 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1794 auto PrepareInsert = [&]() {
1797 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1798 :
B.SetInsertPoint(
I);
1803 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1804 Args.push_back(COp->getElementAsConstant(i));
1810 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1819 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1825 auto *CI =
B.CreateIntrinsicWithoutFolding(
1826 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1830 AggrConsts[CI] = AggrConst;
1831 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1843 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1848 unsigned RoundingModeDeco,
1855 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1864 MDNode *SaturatedConversionNode =
1866 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1886 MDString *ConstraintString =
1895 B.SetInsertPoint(&
Call);
1896 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1901void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1904 if (!
RM.has_value())
1906 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1907 switch (
RM.value()) {
1911 case RoundingMode::NearestTiesToEven:
1912 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1914 case RoundingMode::TowardNegative:
1915 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1917 case RoundingMode::TowardPositive:
1918 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1920 case RoundingMode::TowardZero:
1921 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1923 case RoundingMode::Dynamic:
1924 case RoundingMode::NearestTiesToAway:
1928 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1934Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1938 B.SetInsertPoint(&
I);
1939 SmallVector<Value *, 4>
Args;
1941 Args.push_back(
I.getCondition());
1944 for (
auto &Case :
I.cases()) {
1945 Args.push_back(Case.getCaseValue());
1946 BBCases.
push_back(Case.getCaseSuccessor());
1949 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1950 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1954 I.eraseFromParent();
1957 B.SetInsertPoint(ParentBB);
1958 IndirectBrInst *BrI =
B.CreateIndirectBr(
1961 for (BasicBlock *BBCase : BBCases)
1970Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
1976 B.SetInsertPoint(&
I);
1978 SmallVector<Value *, 4>
Args;
1979 Args.push_back(
B.getInt1(
true));
1980 Args.push_back(
I.getOperand(0));
1981 Args.push_back(
B.getInt32(0));
1982 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1983 Args.push_back(SGEP->getIndexOperand(J));
1986 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1987 replaceAllUsesWithAndErase(
B, &
I, NewI);
1992SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
1994 B.SetInsertPoint(&
I);
1999 unsigned N = RetVTy->getNumElements();
2000 Value *PtrOp =
I.getPointerOperand();
2002 Type *ResultPtrTy = RetVTy->getElementType();
2005 Value *InBounds =
B.getInt1(
I.isInBounds());
2006 Type *LanePointeeTy = getGEPType(&
I);
2007 Type *SrcElemTy =
I.getSourceElementType();
2016 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2017 Value *LaneIdx =
B.getInt32(Lane);
2018 Value *ScalarPtr = PtrOp;
2022 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2026 SmallVector<Value *, 4>
Args;
2027 Args.push_back(InBounds);
2028 Args.push_back(ScalarPtr);
2029 for (
Value *Idx :
I.indices()) {
2031 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
2033 Args.push_back(Idx);
2035 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2037 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2041 replaceAllUsesWithAndErase(
B, &
I, NewI);
2059 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2060 return buildLogicalAccessChainFromGEP(
I);
2065 Value *PtrOp =
I.getPointerOperand();
2066 Type *SrcElemTy =
I.getSourceElementType();
2067 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2070 if (ArrTy->getElementType() == SrcElemTy) {
2072 Type *FirstIdxType =
I.getOperand(1)->getType();
2073 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2074 for (
Value *Idx :
I.indices())
2078 SmallVector<Value *, 4>
Args;
2079 Args.push_back(
B.getInt1(
I.isInBounds()));
2080 Args.push_back(
I.getPointerOperand());
2083 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2085 replaceAllUsesWithAndErase(
B, &
I, NewI);
2092 SmallVector<Value *, 4>
Args;
2093 Args.push_back(
B.getInt1(
I.isInBounds()));
2096 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2097 replaceAllUsesWithAndErase(
B, &
I, NewI);
2101Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2103 B.SetInsertPoint(&
I);
2112 I.eraseFromParent();
2119 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2120 replaceAllUsesWithAndErase(
B, &
I, NewI);
2124void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2126 Type *VTy =
V->getType();
2131 if (ElemTy != AssignedType)
2144 if (CurrentType == AssignedType)
2151 " for value " +
V->getName(),
2159void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2160 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2165 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2166 if (PointerElemTy == ExpectedElementType ||
2172 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2174 bool FirstPtrCastOrAssignPtrType =
true;
2180 for (
auto User :
Pointer->users()) {
2183 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2184 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2185 II->getOperand(0) != Pointer)
2190 FirstPtrCastOrAssignPtrType =
false;
2191 if (
II->getOperand(1) != VMD ||
2198 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2203 if (
II->getParent() !=
I->getParent())
2206 I->setOperand(OperandToReplace,
II);
2221 if (FirstPtrCastOrAssignPtrType) {
2226 }
else if (isTodoType(Pointer)) {
2227 eraseTodoType(Pointer);
2235 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2236 std::make_pair(
I, Pointer)};
2238 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2250 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2256void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2261 replacePointerOperandWithPtrCast(
2262 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2268 Type *OpTy =
Op->getType();
2271 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2274 if (OpTy ==
Op->getType())
2275 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2276 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2281 Type *OpTy = LI->getType();
2286 Type *NewOpTy = OpTy;
2287 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2288 if (OpTy == NewOpTy)
2289 insertTodoType(Pointer);
2292 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2297 Type *OpTy =
nullptr;
2309 OpTy = GEPI->getSourceElementType();
2311 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2313 insertTodoType(Pointer);
2325 std::string DemangledName =
2329 bool HaveTypes =
false;
2347 for (User *U : CalledArg->
users()) {
2349 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2355 HaveTypes |= ElemTy !=
nullptr;
2360 if (DemangledName.empty() && !HaveTypes)
2378 Type *ExpectedType =
2380 if (!ExpectedType && !DemangledName.empty())
2381 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2382 DemangledName,
OpIdx,
I->getContext());
2383 if (!ExpectedType || ExpectedType->
isVoidTy())
2391 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2396SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2403 I.getOperand(1)->getType(),
2404 I.getOperand(2)->getType()};
2406 B.SetInsertPoint(&
I);
2408 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2410 replaceAllUsesWithAndErase(
B, &
I, NewI);
2415SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2422 B.SetInsertPoint(&
I);
2424 I.getIndexOperand()->getType()};
2425 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2426 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2428 replaceAllUsesWithAndErase(
B, &
I, NewI);
2432Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2434 B.SetInsertPoint(&
I);
2437 Value *AggregateOp =
I.getAggregateOperand();
2441 Args.push_back(AggregateOp);
2442 Args.push_back(
I.getInsertedValueOperand());
2443 for (
auto &
Op :
I.indices())
2444 Args.push_back(
B.getInt32(
Op));
2446 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2447 replaceMemInstrUses(&
I, NewI,
B);
2452SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2454 B.SetInsertPoint(&
I);
2455 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2464 for (
auto &
Op :
I.indices())
2465 Args.push_back(
B.getInt32(
Op));
2466 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2467 {
I.getType()}, {
Args});
2468 replaceAllUsesWithAndErase(
B, &
I, NewI);
2472 for (
const Use &U : NewI->
uses()) {
2478 if (ArgNo < FT->getNumParams() &&
2479 !FT->getParamType(ArgNo)->isAggregateType()) {
2488Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2489 if (!
I.getType()->isAggregateType())
2492 B.SetInsertPoint(&
I);
2493 TrackConstants =
false;
2498 unsigned IntrinsicId;
2499 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2500 if (!
I.isAtomic()) {
2501 IntrinsicId = Intrinsic::spv_load;
2502 Args.push_back(
B.getInt32(
I.getAlign().value()));
2504 IntrinsicId = Intrinsic::spv_atomic_load;
2505 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2507 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2508 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2510 replaceMemInstrUses(&
I, NewI,
B);
2514Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2518 B.SetInsertPoint(&
I);
2519 TrackConstants =
false;
2523 auto *PtrOp =
I.getPointerOperand();
2525 if (
I.getValueOperand()->getType()->isAggregateType()) {
2533 "Unexpected argument of aggregate type, should be spv_extractv!");
2537 unsigned IntrinsicId;
2538 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2540 if (!
I.isAtomic()) {
2541 IntrinsicId = Intrinsic::spv_store;
2542 Args.push_back(
B.getInt32(
I.getAlign().value()));
2544 IntrinsicId = Intrinsic::spv_atomic_store;
2545 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2548 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2550 I.eraseFromParent();
2554Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2555 Value *ArraySize =
nullptr;
2556 if (
I.isArrayAllocation()) {
2559 SPIRV::Extension::SPV_INTEL_variable_length_array))
2561 "array allocation: this instruction requires the following "
2562 "SPIR-V extension: SPV_INTEL_variable_length_array",
2564 ArraySize =
I.getArraySize();
2567 B.SetInsertPoint(&
I);
2568 TrackConstants =
false;
2569 Type *PtrTy =
I.getType();
2572 ?
B.CreateIntrinsicWithoutFolding(
2573 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2574 {ArraySize,
B.getInt32(
I.getAlign().value())})
2575 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2576 {
B.getInt32(
I.getAlign().value())});
2577 replaceAllUsesWithAndErase(
B, &
I, NewI);
2582SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2583 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2585 B.SetInsertPoint(&
I);
2587 Args.push_back(
B.getInt32(
2588 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2591 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2592 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2593 uint32_t ScSem =
static_cast<uint32_t
>(
2595 Args.push_back(
B.getInt32(
2597 Args.push_back(
B.getInt32(
2600 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2601 replaceMemInstrUses(&
I, NewI,
B);
2610 case Intrinsic::spv_abort:
2612 case Intrinsic::trap:
2613 case Intrinsic::ubsantrap:
2615 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2635 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2636 "abort-like call must be the last non-debug instruction before its "
2637 "block's terminator");
2641Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2642 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2646 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2653 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2667 while (!Stack.empty()) {
2668 const Value *V = Stack.pop_back_val();
2669 if (!Visited.
insert(V).second)
2677 Stack.append(
C->user_begin(),
C->user_end());
2693 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2694 if (UserFunctions.contains(
F))
2699 if (!UserFunctions.empty())
2704 const Module &M = *
F->getParent();
2705 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2706 return F == &FirstDefinition;
2709Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2711 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2712 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2714 AggrConstTypes[Leaf] = ElemTy;
2717 SmallVector<Value *, 4> Elems;
2719 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2722 DenseMap<Type *, Instruction *> LeafByType;
2723 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2725 auto &
Entry = LeafByType[ElemTy];
2727 Entry = MakeLeaf(ElemTy);
2731 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2732 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2734 AggrConstTypes[Composite] = AggrTy;
2743void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(Function &Func,
2748 for (BasicBlock &BB : Func) {
2752 Value *RetVal = RI->getReturnValue();
2759 B.SetInsertPoint(RI);
2761 for (uint64_t
I = 0;
I < NumElts; ++
I) {
2762 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2763 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2765 RI->setOperand(0, Rebuilt);
2769void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2779 deduceElementTypeHelper(&GV,
false);
2784 Value *InitOp = Init;
2791 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2792 {
B.getInt32Ty()}, {});
2797 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2802 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2803 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2809 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2815bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2817 bool UnknownElemTypeI8) {
2823 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2830void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2833 static StringMap<unsigned> ResTypeWellKnown = {
2834 {
"async_work_group_copy", WellKnownTypes::Event},
2835 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2836 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2840 bool IsKnown =
false;
2845 std::string DemangledName =
2848 if (DemangledName.length() > 0)
2850 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2851 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2852 if (ResIt != ResTypeWellKnown.
end()) {
2855 switch (ResIt->second) {
2856 case WellKnownTypes::Event:
2863 switch (DecorationId) {
2866 case FPDecorationId::SAT:
2869 case FPDecorationId::RTE:
2871 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2873 case FPDecorationId::RTZ:
2875 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2877 case FPDecorationId::RTP:
2879 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2881 case FPDecorationId::RTN:
2883 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2889 Type *Ty =
I->getType();
2892 Type *TypeToAssign = Ty;
2895 auto It = AggrConstTypes.
find(
II);
2896 if (It == AggrConstTypes.
end())
2898 TypeToAssign = It->second;
2899 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2900 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2901 TypeToAssign = It->second;
2903 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2904 TypeToAssign = It->second;
2908 for (
const auto &
Op :
I->operands()) {
2915 Type *OpTy =
Op->getType();
2917 CallInst *AssignCI =
2922 Type *OpTy =
Op->getType();
2937 CallInst *AssignCI =
2947bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
2948 Instruction *Inst) {
2950 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2960void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
2962 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2964 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2969 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2970 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2971 if (shouldTryToAddMemAliasingDecoration(
I)) {
2972 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2973 ? SPIRV::Decoration::AliasScopeINTEL
2974 : SPIRV::Decoration::NoAliasINTEL;
2976 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2979 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2980 {
I->getType()}, {
Args});
2984 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2985 processMemAliasingDecoration(LLVMContext::MD_noalias);
2988 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2990 bool AllowFPMaxError =
2992 if (!AllowFPMaxError)
2996 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3000 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
3004 auto &Ctx =
B.getContext();
3006 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
3009 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3011 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3012 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3015 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
3017 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
3019 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3027 &FPFastMathDefaultInfoMap,
3029 auto it = FPFastMathDefaultInfoMap.
find(
F);
3030 if (it != FPFastMathDefaultInfoMap.
end())
3038 SPIRV::FPFastMathMode::None);
3040 SPIRV::FPFastMathMode::None);
3042 SPIRV::FPFastMathMode::None);
3043 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3049 size_t BitWidth = Ty->getScalarSizeInBits();
3053 assert(Index >= 0 && Index < 3 &&
3054 "Expected FPFastMathDefaultInfo for half, float, or double");
3055 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3056 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3057 return FPFastMathDefaultInfoVec[Index];
3060void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3062 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3071 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3073 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3081 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3084 [[maybe_unused]] GlobalVariable *GV =
3085 new GlobalVariable(M,
3086 Type::getInt32Ty(
M.getContext()),
3100 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3101 FPFastMathDefaultInfoMap;
3103 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3112 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3114 "Expected 4 operands for FPFastMathDefault");
3120 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3122 SPIRV::FPFastMathDefaultInfo &
Info =
3125 Info.FPFastMathDefault =
true;
3126 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3128 "Expected no operands for ContractionOff");
3132 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3134 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3135 Info.ContractionOff =
true;
3137 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3139 "Expected 1 operand for SignedZeroInfNanPreserve");
3140 unsigned TargetWidth =
3145 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3149 assert(Index >= 0 && Index < 3 &&
3150 "Expected FPFastMathDefaultInfo for half, float, or double");
3151 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3152 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3153 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3157 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3158 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3159 if (FPFastMathDefaultInfoVec.
empty())
3162 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3163 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3166 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3167 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3171 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3173 "and AllowContract");
3175 if (
Info.SignedZeroInfNanPreserve &&
3177 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3178 SPIRV::FPFastMathMode::NSZ))) {
3179 if (
Info.FPFastMathDefault)
3181 "SignedZeroInfNanPreserve but at least one of "
3182 "NotNaN/NotInf/NSZ is enabled.");
3185 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3186 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3187 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3189 "AllowTransform requires AllowReassoc and "
3190 "AllowContract to be set.");
3193 auto it = GlobalVars.
find(Flags);
3194 GlobalVariable *GV =
nullptr;
3195 if (it != GlobalVars.
end()) {
3201 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3204 GV =
new GlobalVariable(M,
3205 Type::getInt32Ty(
M.getContext()),
3210 GlobalVars[
Flags] = GV;
3216void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3219 bool IsConstComposite =
3220 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3221 if (IsConstComposite && TrackConstants) {
3223 auto t = AggrConsts.
find(
I);
3227 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3229 NewOp->setArgOperand(0,
I);
3232 for (
const auto &
Op :
I->operands()) {
3236 unsigned OpNo =
Op.getOperandNo();
3237 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3238 (!
II->isBundleOperand(OpNo) &&
3239 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3243 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3244 :
B.SetInsertPoint(
I);
3247 Type *OpTy =
Op->getType();
3255 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3257 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3258 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3260 SmallVector<Value *, 2>
Args = {
3263 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3269 I->setOperand(OpNo, NewOp);
3275Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(Function *
F,
3277 SmallPtrSet<Function *, 0> FVisited;
3278 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3281Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3282 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3284 if (!FVisited.
insert(
F).second)
3287 SmallPtrSet<Value *, 0> Visited;
3290 for (User *U :
F->users()) {
3302 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3305 for (User *OpU : OpArg->
users()) {
3307 if (!Inst || Inst == CI)
3310 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3317 if (FVisited.
find(OuterF) != FVisited.
end())
3319 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3320 if (OuterF->
getArg(i) == OpArg) {
3321 Lookup.push_back(std::make_pair(OuterF, i));
3328 for (
auto &Pair :
Lookup) {
3329 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3336void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(Function *
F,
3338 B.SetInsertPointPastAllocas(
F);
3345 for (User *U : Arg->
users()) {
3347 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3365 for (User *U :
F->users()) {
3381 for (User *U : Arg->
users()) {
3385 CI->
getParent()->getParent() == CurrF) {
3387 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3398void SPIRVEmitIntrinsicsImpl::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3399 B.SetInsertPointPastAllocas(
F);
3405 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3407 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3409 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3421 bool IsNewFTy =
false;
3437bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3440 if (
F.isIntrinsic())
3442 if (
F.isDeclaration()) {
3443 for (User *U :
F.users()) {
3456 for (User *U :
F.users()) {
3458 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3460 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3461 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3468 if (Worklist.
empty())
3471 LLVMContext &Ctx =
M.getContext();
3476 for (Function *
F : Worklist) {
3478 for (
const auto &Arg :
F->args())
3480 IRB.CreateCall(
F, Args);
3482 IRB.CreateRetVoid();
3488void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3489 DenseMap<Function *, CallInst *> Ptrcasts;
3490 for (
auto It : FDeclPtrTys) {
3492 for (
auto *U :
F->users()) {
3497 for (
auto [Idx, ElemTy] : It.second) {
3505 B.SetInsertPointPastAllocas(Arg->
getParent());
3509 }
else if (isaGEP(Param)) {
3510 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3519 .getFirstNonPHIOrDbgOrAlloca());
3539GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3540 GetElementPtrInst *
GEP) {
3547 Type *SrcTy =
GEP->getSourceElementType();
3548 SmallVector<Value *, 8> Indices(
GEP->indices());
3550 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3551 Indices.erase(Indices.begin());
3552 SrcTy = ArrTy->getElementType();
3554 GEP->getNoWrapFlags(),
"",
3555 GEP->getIterator());
3560void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(Function &
F,
3567 if (
ST->canUseExtension(
3568 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3569 for (BasicBlock &BB :
F) {
3571 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3575 SmallVector<unsigned, 1>
Ops =
3577 unsigned LC =
Ops[0];
3578 if (LC == SPIRV::LoopControl::None)
3582 B.SetInsertPoint(Term);
3583 SmallVector<Value *, 4> IntrArgs;
3584 for (
unsigned Op :
Ops)
3586 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3593 DominatorTree DT(
F);
3598 for (Loop *L : LI.getLoopsInPreorder()) {
3607 SmallVector<unsigned, 1> LoopControlOps =
3609 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3613 B.SetInsertPoint(Header->getTerminator());
3616 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3617 for (
unsigned Imm : LoopControlOps)
3618 Args.emplace_back(
B.getInt32(Imm));
3619 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3623bool SPIRVEmitIntrinsicsImpl::runOnFunction(Function &Func) {
3624 if (
Func.isDeclaration())
3628 GR =
ST.getSPIRVGlobalRegistry();
3632 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3637 AggrConstTypes.
clear();
3640 processParamTypesByFunHeader(CurrF,
B);
3644 SmallPtrSet<Instruction *, 4> DeadInsts;
3649 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3653 GR->addDeducedElementType(SGEP,
3658 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3660 GEP->replaceAllUsesWith(NewGEP);
3664 if (
Type *GepTy = getGEPType(
GEP))
3668 for (
auto *
I : DeadInsts) {
3669 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3670 I->eraseFromParent();
3680 Type *ElTy =
SI->getValueOperand()->getType();
3685 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3686 for (
auto &GV :
Func.getParent()->globals())
3687 processGlobalValue(GV,
B);
3689 reconstructAggregateReturns(Func,
B);
3690 preprocessUndefsAndPoisons(
B);
3691 simplifyNullAddrSpaceCasts();
3692 preprocessCompositeConstants(
B);
3700 Type *I32Ty =
B.getInt32Ty();
3705 insertCompositeAggregateArms(&
I,
B);
3706 AggrConstTypes[&
I] =
I.getType();
3707 I.mutateType(I32Ty);
3710 preprocessBoolVectorBitcasts(Func);
3711 SmallVector<Instruction *> Worklist(
3714 applyDemangledPtrArgTypes(
B);
3717 for (
auto &
I : Worklist) {
3719 if (isConvergenceIntrinsic(
I))
3722 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3724 insertAssignTypeIntrs(
I,
B);
3725 insertPtrCastOrAssignTypeInstr(
I,
B);
3729 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3730 insertAssignPtrTypeIntrs(
I,
B,
true);
3733 useRoundingMode(FPI,
B);
3738 SmallPtrSet<Instruction *, 4> IncompleteRets;
3740 deduceOperandElementType(&
I, &IncompleteRets);
3744 for (BasicBlock &BB : Func)
3745 for (PHINode &Phi : BB.
phis())
3747 deduceOperandElementType(&Phi,
nullptr);
3749 for (
auto *
I : Worklist) {
3750 TrackConstants =
true;
3760 if (isConvergenceIntrinsic(
I))
3764 processInstrAfterVisit(
I,
B);
3767 emitUnstructuredLoopControls(Func,
B);
3773bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3774 if (!GR || TodoTypeSz == 0)
3777 unsigned SzTodo = TodoTypeSz;
3778 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3783 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3784 Type *KnownTy = GR->findDeducedElementType(
Op);
3785 if (!KnownTy || !AssignCI)
3791 SmallPtrSet<Value *, 0> Visited;
3792 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3793 if (ElemTy != KnownTy) {
3794 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3795 propagateElemType(CI, ElemTy, VisitedSubst);
3802 if (
Op->hasUseList()) {
3803 for (User *U :
Op->users()) {
3810 if (TodoTypeSz == 0)
3815 SmallPtrSet<Instruction *, 4> IncompleteRets;
3817 auto It = ToProcess.
find(&
I);
3818 if (It == ToProcess.
end())
3820 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3821 if (It->second.size() == 0)
3823 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3824 if (TodoTypeSz == 0)
3829 return SzTodo > TodoTypeSz;
3833void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
3835 if (!
F.isDeclaration() ||
F.isIntrinsic())
3839 if (DemangledName.empty())
3843 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3844 DemangledName,
ST.getPreferredInstructionSet());
3845 if (Opcode != SPIRV::OpGroupAsyncCopy)
3848 SmallVector<unsigned> Idxs;
3857 LLVMContext &Ctx =
F.getContext();
3859 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3860 if (!TypeStrs.
size())
3863 for (
unsigned Idx : Idxs) {
3864 if (Idx >= TypeStrs.
size())
3867 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3870 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3875bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3876 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3878 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3879 if (!
ST.canUseExtension(
3880 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3881 I.getContext().emitError(
3882 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3886 I.eraseFromParent();
3892 Value *Ptrs =
I.getArgOperand(0);
3894 Value *Passthru =
I.getArgOperand(2);
3897 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3899 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3904 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3906 I.eraseFromParent();
3910 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3911 if (!
ST.canUseExtension(
3912 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3913 I.getContext().emitError(
3914 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3917 I.eraseFromParent();
3924 Value *Ptrs =
I.getArgOperand(1);
3929 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3931 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
3935 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3936 I.eraseFromParent();
3947void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(Function &
F) {
3948 struct BoolVecBitcast {
3950 FixedVectorType *BoolVecTy;
3954 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3956 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3964 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3966 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3970 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3972 Value *Src = BC->getOperand(0);
3973 unsigned BoolVecN = BoolVecTy->getNumElements();
3975 Type *IntTy =
B.getIntNTy(BoolVecN);
3981 IntVal = ConstantInt::get(IntTy, 0);
3982 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3983 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3984 Value *Ext =
B.CreateZExt(Elem, IntTy);
3986 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3987 IntVal =
B.CreateOr(IntVal, Ext);
3993 if (!Src->getType()->isIntegerTy())
3994 IntVal =
B.CreateBitCast(Src, IntTy);
3999 if (!SrcIsBoolVec) {
4002 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4005 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
4006 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4012 if (!BC->getDestTy()->isIntegerTy())
4013 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4016 BC->replaceAllUsesWith(Result);
4017 BC->eraseFromParent();
4021bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4025 if (!
F.isIntrinsic())
4028 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4033 Changed |= processMaskedMemIntrinsic(*
II);
4037 F.eraseFromParent();
4043bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4046 Changed |= convertMaskedMemIntrinsics(M);
4048 parseFunDeclarations(M);
4049 insertConstantsForFPFastMathDefault(M);
4060 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4062 processParamTypes(&
F,
B);
4066 CanTodoType =
false;
4067 Changed |= postprocessTypes(M);
4070 Changed |= processFunctionPointers(M);
4077 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4083 return new SPIRVEmitIntrinsicsLegacy(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
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
MachineInstr unsigned OpIdx
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()
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 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.
@ C
The default llvm calling convention, compatible with C.
@ 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
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::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)
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)
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
@ Ref
The access may reference the value stored in memory.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ 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)