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 SPIRVEmitIntrinsics
185 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
186 const SPIRVTargetMachine &TM;
187 SPIRVGlobalRegistry *GR =
nullptr;
189 bool TrackConstants =
true;
190 bool HaveFunPtrs =
false;
191 DenseMap<Instruction *, Constant *> AggrConsts;
192 DenseMap<Instruction *, Type *> AggrConstTypes;
193 SmallPtrSet<Instruction *, 0> AggrStores;
194 GlobalVariableUsers GVUsers;
195 SmallPtrSet<Value *, 0> Named;
198 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
201 bool CanTodoType =
true;
202 unsigned TodoTypeSz = 0;
203 DenseMap<Value *, bool> TodoType;
204 void insertTodoType(
Value *
Op) {
206 if (CanTodoType && !isaGEP(
Op)) {
207 auto It = TodoType.try_emplace(
Op,
true);
212 void eraseTodoType(
Value *
Op) {
213 auto It = TodoType.find(
Op);
214 if (It != TodoType.end() && It->second) {
222 auto It = TodoType.find(
Op);
223 return It != TodoType.end() && It->second;
227 SmallPtrSet<Instruction *, 0> TypeValidated;
230 enum WellKnownTypes { Event };
233 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
234 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
235 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
236 bool UnknownElemTypeI8,
237 bool IgnoreKnownType =
false);
238 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
239 bool UnknownElemTypeI8);
240 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
241 SmallPtrSetImpl<Value *> &Visited,
242 bool UnknownElemTypeI8);
244 SmallPtrSetImpl<Value *> &Visited,
245 bool UnknownElemTypeI8);
247 bool UnknownElemTypeI8);
250 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
251 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
252 SmallPtrSetImpl<Value *> &Visited,
253 bool UnknownElemTypeI8);
257 deduceOperandElementType(Instruction *
I,
258 SmallPtrSetImpl<Instruction *> *IncompleteRets,
259 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
260 bool IsPostprocessing =
false);
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 processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
288 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
289 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
290 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,
304 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
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);
334 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
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);
384 SPIRVEmitIntrinsics(
const SPIRVTargetMachine &TM) : ModulePass(ID), 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 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
403 bool runOnModule(
Module &M)
override;
405 void getAnalysisUsage(AnalysisUsage &AU)
const override {
406 ModulePass::getAnalysisUsage(AU);
412 Intrinsic::experimental_convergence_loop,
413 Intrinsic::experimental_convergence_anchor>());
416bool expectIgnoredInIRTranslation(
const Instruction *
I) {
418 Intrinsic::spv_resource_handlefrombinding,
419 Intrinsic::spv_resource_getbasepointer,
420 Intrinsic::spv_resource_getpointer>());
427 return getPointerRoot(V);
433char SPIRVEmitIntrinsics::ID = 0;
436 "SPIRV emit intrinsics",
false,
false)
450 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
463 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
469 B.SetCurrentDebugLocation(
I->getDebugLoc());
470 if (
I->getType()->isVoidTy())
471 B.SetInsertPoint(
I->getNextNode());
473 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
483 if (
I->getType()->isTokenTy())
485 "does not support token type",
490 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
491 expectIgnoredInIRTranslation(
I))
502 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
513 std::vector<Value *> Args = {
516 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
519void SPIRVEmitIntrinsics::replaceAllUsesWith(
Value *Src,
Value *Dest,
523 if (isTodoType(Src)) {
526 insertTodoType(Dest);
530void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
535 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
536 Src->eraseFromParent();
539 if (Named.
insert(Dest).second)
554 V = V->stripPointerCasts();
575Type *SPIRVEmitIntrinsics::reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
576 bool IsPostprocessing) {
580 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
594 if (UnknownElemTypeI8) {
595 if (!IsPostprocessing)
603CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *
F,
Value *
Op,
611 B.SetInsertPointPastAllocas(OpA->getParent());
614 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
616 Type *OpTy =
Op->getType();
620 CallInst *PtrCasted =
621 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
626void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
628 DenseMap<Function *, CallInst *> Ptrcasts) {
630 CallInst *PtrCastedI =
nullptr;
631 auto It = Ptrcasts.
find(
F);
632 if (It == Ptrcasts.
end()) {
633 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
634 Ptrcasts[
F] = PtrCastedI;
636 PtrCastedI = It->second;
638 I->replaceUsesOfWith(
Op, PtrCastedI);
641void SPIRVEmitIntrinsics::propagateElemType(
643 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
644 DenseMap<Function *, CallInst *> Ptrcasts;
646 for (
auto *U :
Users) {
649 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
654 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
655 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
659void SPIRVEmitIntrinsics::propagateElemTypeRec(
661 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
662 SmallPtrSet<Value *, 0> Visited;
663 DenseMap<Function *, CallInst *> Ptrcasts;
664 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
665 std::move(Ptrcasts));
668void SPIRVEmitIntrinsics::propagateElemTypeRec(
670 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
671 SmallPtrSetImpl<Value *> &Visited,
672 DenseMap<Function *, CallInst *> Ptrcasts) {
676 for (
auto *U :
Users) {
679 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
684 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
685 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
693SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
694 bool UnknownElemTypeI8) {
695 SmallPtrSet<Value *, 0> Visited;
696 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
700Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
701 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
702 bool UnknownElemTypeI8) {
707 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
718Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
719 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
731 for (User *OpU :
Op->users()) {
733 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
746 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
755Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I,
756 bool UnknownElemTypeI8) {
757 SmallPtrSet<Value *, 0> Visited;
758 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
761void SPIRVEmitIntrinsics::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
Type *RefTy,
762 bool UnknownElemTypeI8) {
764 if (!UnknownElemTypeI8)
773bool SPIRVEmitIntrinsics::walkLogicalAccessChainDynamic(
774 Type *CurType,
Value *Operand, uint64_t Multiplier,
775 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
776 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
782 if (
ST->getNumElements() == 0)
784 CurType =
ST->getElementType(0);
785 OnLiteralIndexing(CurType, 0);
793 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
794 return AT ==
nullptr;
797bool SPIRVEmitIntrinsics::walkLogicalAccessChainConstant(
799 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
804 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
808 CurType = AT->getElementType();
809 OnLiteralIndexing(CurType, Index);
811 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
814 const auto &STL =
DL.getStructLayout(ST);
815 unsigned Element = STL->getElementContainingOffset(
Offset);
816 Offset -= STL->getElementOffset(Element);
817 CurType =
ST->getElementType(Element);
818 OnLiteralIndexing(CurType, Element);
820 Type *EltTy = VT->getElementType();
821 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
822 assert(EltSizeBits % 8 == 0 &&
823 "Element type size in bits must be a multiple of 8.");
824 uint32_t EltTypeSize = EltSizeBits / 8;
829 OnLiteralIndexing(CurType, Index);
839bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
840 GetElementPtrInst &
GEP,
841 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
842 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
845 std::optional<uint64_t> MultiplierOpt =
846 getByteAddressingMultiplier(
GEP.getSourceElementType());
847 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
848 uint64_t Multiplier = *MultiplierOpt;
851 Value *Src = getPointerRoot(
GEP.getPointerOperand());
852 Type *CurType = deduceElementType(Src,
true);
856 return walkLogicalAccessChainConstant(
857 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
859 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
860 OnLiteralIndexing, OnDynamicIndexing);
864SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP) {
867 B.SetInsertPoint(&
GEP);
869 std::vector<Value *> Indices;
870 Indices.push_back(ConstantInt::get(
871 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
872 walkLogicalAccessChain(
874 [&Indices, &
B](
Type *EltType, uint64_t Index) {
876 ConstantInt::get(
B.getInt64Ty(), Index,
false));
879 uint64_t Multiplier) {
881 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
883 if (Multiplier == EltTypeSize) {
885 }
else if (EltTypeSize % Multiplier == 0) {
888 EltTypeSize / Multiplier,
892 ConstantInt::get(
Offset->getType(), Multiplier,
895 Index =
B.CreateUDiv(Index,
896 ConstantInt::get(
Offset->getType(), EltTypeSize,
900 Indices.push_back(Index);
904 SmallVector<Value *, 4>
Args;
905 Args.push_back(
B.getInt1(
GEP.isInBounds()));
906 Args.push_back(
GEP.getOperand(0));
909 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
910 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
914Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *
GEP) {
916 Type *CurType =
GEP->getResultElementType();
918 bool Interrupted = walkLogicalAccessChain(
919 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
920 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
922 return Interrupted ?
GEP->getResultElementType() : CurType;
925Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *
Ref) {
926 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
928 return getGEPTypeLogical(
Ref);
935 Ty =
Ref->getSourceElementType();
939 Ty =
Ref->getResultElementType();
944Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
945 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
946 bool IgnoreKnownType) {
952 if (!IgnoreKnownType)
964 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
966 Ty = getGEPType(
Ref);
968 Ty = SGEP->getResultElementType();
973 KnownTy =
Op->getType();
975 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
978 Ty = SPIRV::getOriginalFunctionType(*Fn);
981 Ty = deduceElementTypeByValueDeep(
983 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
987 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
989 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
991 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
993 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
995 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1000 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1004 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1006 Type *BestTy =
nullptr;
1008 DenseMap<Type *, unsigned> PhiTys;
1009 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1010 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1017 if (It.first->second > MaxN) {
1018 MaxN = It.first->second;
1026 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1027 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1032 static StringMap<unsigned> ResTypeByArg = {
1036 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1037 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1038 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1039 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1040 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1041 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1045 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1046 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1048 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1049 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1050 for (User *U :
II->users()) {
1055 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1057 Ty = HandleType->getTypeParameter(0);
1058 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1072 }
else if (
II &&
II->getIntrinsicID() ==
1073 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1077 std::string DemangledName =
1079 if (DemangledName.length() > 0)
1080 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1081 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1082 if (AsArgIt != ResTypeByArg.
end())
1083 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1084 Visited, UnknownElemTypeI8);
1091 if (Ty && !IgnoreKnownType) {
1102Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1103 bool UnknownElemTypeI8) {
1104 SmallPtrSet<Value *, 0> Visited;
1105 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1109SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
Type *OrigTy,
1110 SmallPtrSetImpl<Value *> &Visited,
1111 bool UnknownElemTypeI8) {
1120 if (!Visited.
insert(U).second)
1125 bool Change =
false;
1126 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1128 assert(
Op &&
"Operands should not be null.");
1129 Type *OpTy =
Op->getType();
1132 if (
Type *NestedTy =
1133 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1140 Change |= Ty != OpTy;
1148 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1149 Type *OpTy = ArrTy->getElementType();
1152 if (
Type *NestedTy =
1153 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1160 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1166 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1167 Type *OpTy = VecTy->getElementType();
1170 if (
Type *NestedTy =
1171 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1178 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1188Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I,
bool UnknownElemTypeI8) {
1189 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1191 if (!UnknownElemTypeI8)
1194 return IntegerType::getInt8Ty(
I->getContext());
1198 Value *PointerOperand) {
1204 return I->getType();
1212bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1214 Type *&KnownElemTy,
bool &Incomplete) {
1218 std::string DemangledName =
1220 if (DemangledName.length() > 0 &&
1222 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1223 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1224 DemangledName,
ST.getPreferredInstructionSet());
1225 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1226 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1232 KnownElemTy = ElemTy;
1233 Ops.push_back(std::make_pair(
Op, i));
1235 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1242 case SPIRV::OpAtomicFAddEXT:
1243 case SPIRV::OpAtomicFMinEXT:
1244 case SPIRV::OpAtomicFMaxEXT:
1245 case SPIRV::OpAtomicLoad:
1246 case SPIRV::OpAtomicCompareExchangeWeak:
1247 case SPIRV::OpAtomicCompareExchange:
1248 case SPIRV::OpAtomicExchange:
1249 case SPIRV::OpAtomicIAdd:
1250 case SPIRV::OpAtomicISub:
1251 case SPIRV::OpAtomicOr:
1252 case SPIRV::OpAtomicXor:
1253 case SPIRV::OpAtomicAnd:
1254 case SPIRV::OpAtomicUMin:
1255 case SPIRV::OpAtomicUMax:
1256 case SPIRV::OpAtomicSMin:
1257 case SPIRV::OpAtomicSMax: {
1262 Incomplete = isTodoType(
Op);
1263 Ops.push_back(std::make_pair(
Op, 0));
1265 case SPIRV::OpAtomicStore: {
1274 Incomplete = isTodoType(
Op);
1275 Ops.push_back(std::make_pair(
Op, 0));
1284void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1286 Type *&KnownElemTy,
bool IsPostprocessing) {
1290 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1291 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1292 bool IsNewFTy =
false, IsIncomplete =
false;
1295 Type *ArgTy = Arg->getType();
1300 if (isTodoType(Arg))
1301 IsIncomplete =
true;
1303 IsIncomplete =
true;
1306 ArgTy = FTy->getFunctionParamType(ParmIdx);
1310 Type *RetTy = FTy->getReturnType();
1317 IsIncomplete =
true;
1319 IsIncomplete =
true;
1322 if (!IsPostprocessing && IsIncomplete)
1325 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1328bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1329 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1330 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1342 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1343 for (User *U :
F->users()) {
1351 propagateElemType(CI, PrevElemTy, VisitedSubst);
1361 for (Instruction *IncompleteRetI : *IncompleteRets)
1362 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1364 }
else if (IncompleteRets) {
1375void SPIRVEmitIntrinsics::deduceOperandElementType(
1376 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1377 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1379 Type *KnownElemTy =
nullptr;
1380 bool Incomplete =
false;
1386 Incomplete = isTodoType(
I);
1387 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1390 Ops.push_back(std::make_pair(
Op, i));
1396 Incomplete = isTodoType(
I);
1397 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1404 Incomplete = isTodoType(
I);
1405 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1409 KnownElemTy =
Ref->getSourceElementType();
1410 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1415 KnownElemTy =
Ref->getBaseType();
1416 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1419 KnownElemTy =
I->getType();
1426 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1435 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1439 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1444 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1452 Incomplete = isTodoType(
Ref->getPointerOperand());
1453 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1461 Incomplete = isTodoType(
Ref->getPointerOperand());
1462 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1468 Incomplete = isTodoType(
I);
1469 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1472 Ops.push_back(std::make_pair(
Op, i));
1480 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1481 IsPostprocessing, KnownElemTy,
Op,
1484 Incomplete = isTodoType(CurrF);
1485 Ops.push_back(std::make_pair(
Op, 0));
1491 bool Incomplete0 = isTodoType(Op0);
1492 bool Incomplete1 = isTodoType(Op1);
1494 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1496 : GR->findDeducedElementType(Op0);
1498 KnownElemTy = ElemTy0;
1499 Incomplete = Incomplete0;
1500 Ops.push_back(std::make_pair(Op1, 1));
1501 }
else if (ElemTy1) {
1502 KnownElemTy = ElemTy1;
1503 Incomplete = Incomplete1;
1504 Ops.push_back(std::make_pair(Op0, 0));
1508 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1509 else if (HaveFunPtrs)
1510 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1515 if (!KnownElemTy ||
Ops.size() == 0)
1520 for (
auto &OpIt :
Ops) {
1524 Type *AskTy =
nullptr;
1525 CallInst *AskCI =
nullptr;
1526 if (IsPostprocessing && AskOps) {
1532 if (Ty == KnownElemTy)
1535 Type *OpTy =
Op->getType();
1541 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1548 else if (!IsPostprocessing)
1552 if (AssignCI ==
nullptr) {
1561 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1562 std::make_pair(
I,
Op)};
1563 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1567 CallInst *PtrCastI =
1568 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1569 if (OpIt.second == std::numeric_limits<unsigned>::max())
1572 I->setOperand(OpIt.second, PtrCastI);
1578void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1583 if (isAssignTypeInstr(U)) {
1584 B.SetInsertPoint(U);
1585 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1586 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1587 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1589 U->eraseFromParent();
1592 U->replaceUsesOfWith(Old, New);
1600 Type *NewArgTy =
New->getType();
1602 if (NewArgTy != ExpectedArgTy) {
1605 M, Intrinsic::spv_abort, {NewArgTy});
1615 "aggregate PHI/select/freeze should have been mutated to value-id "
1617 U->replaceUsesOfWith(Old, New);
1622 New->copyMetadata(*Old);
1628 bool HasPoisonExt) {
1635 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1636 "lowered as undef\n");
1638 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1639 Type *Ty = UV->getType();
1645 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1646 :
B.CreateIntrinsicWithoutFolding(IID, {});
1647 AggrConsts[
Call] = UV;
1648 AggrConstTypes[
Call] = Ty;
1653 return B.CreateIntrinsic(IID, {Ty}, {});
1660void SPIRVEmitIntrinsics::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1665 SmallVector<Instruction *, 16> Insts;
1669 for (Instruction *
I : Insts) {
1670 bool BPrepared =
false;
1672 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1676 bool IsScalar = !
Op->getType()->isAggregateType();
1679 if (IsScalar && !AsPoison)
1683 if (IsScalar && Phi)
1684 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1685 else if (!BPrepared) {
1689 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1690 I->setOperand(Idx, Repl);
1699void SPIRVEmitIntrinsics::simplifyNullAddrSpaceCasts() {
1703 ASC->replaceAllUsesWith(
1705 ASC->eraseFromParent();
1709void SPIRVEmitIntrinsics::preprocessCompositeConstants(
IRBuilder<> &
B) {
1713 std::queue<Instruction *> Worklist;
1717 while (!Worklist.empty()) {
1718 auto *
I = Worklist.front();
1721 bool KeepInst =
false;
1722 for (
const auto &
Op :
I->operands()) {
1724 Type *ResTy =
nullptr;
1727 ResTy = COp->getType();
1739 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1742 auto PrepareInsert = [&]() {
1745 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1746 :
B.SetInsertPoint(
I);
1751 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1752 Args.push_back(COp->getElementAsConstant(i));
1758 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1767 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1773 auto *CI =
B.CreateIntrinsicWithoutFolding(
1774 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1778 AggrConsts[CI] = AggrConst;
1779 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1791 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1796 unsigned RoundingModeDeco,
1803 ConstantInt::get(
Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1812 MDNode *SaturatedConversionNode =
1814 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1834 MDString *ConstraintString =
1843 B.SetInsertPoint(&
Call);
1844 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1849void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1852 if (!
RM.has_value())
1854 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1855 switch (
RM.value()) {
1859 case RoundingMode::NearestTiesToEven:
1860 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1862 case RoundingMode::TowardNegative:
1863 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1865 case RoundingMode::TowardPositive:
1866 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1868 case RoundingMode::TowardZero:
1869 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1871 case RoundingMode::Dynamic:
1872 case RoundingMode::NearestTiesToAway:
1876 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1882Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &
I) {
1886 B.SetInsertPoint(&
I);
1887 SmallVector<Value *, 4>
Args;
1889 Args.push_back(
I.getCondition());
1892 for (
auto &Case :
I.cases()) {
1893 Args.push_back(Case.getCaseValue());
1894 BBCases.
push_back(Case.getCaseSuccessor());
1897 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1898 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1902 I.eraseFromParent();
1905 B.SetInsertPoint(ParentBB);
1906 IndirectBrInst *BrI =
B.CreateIndirectBr(
1909 for (BasicBlock *BBCase : BBCases)
1918Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &
I) {
1924 B.SetInsertPoint(&
I);
1926 SmallVector<Value *, 4>
Args;
1927 Args.push_back(
B.getInt1(
true));
1928 Args.push_back(
I.getOperand(0));
1929 Args.push_back(
B.getInt32(0));
1930 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1931 Args.push_back(SGEP->getIndexOperand(J));
1934 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1935 replaceAllUsesWithAndErase(
B, &
I, NewI);
1939Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &
I) {
1941 B.SetInsertPoint(&
I);
1946 unsigned N = RetVTy->getNumElements();
1947 Value *PtrOp =
I.getPointerOperand();
1949 Type *ResultPtrTy = RetVTy->getElementType();
1952 Value *InBounds =
B.getInt1(
I.isInBounds());
1953 Type *LanePointeeTy = getGEPType(&
I);
1954 Type *SrcElemTy =
I.getSourceElementType();
1963 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
1964 Value *LaneIdx =
B.getInt32(Lane);
1965 Value *ScalarPtr = PtrOp;
1969 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
1973 SmallVector<Value *, 4>
Args;
1974 Args.push_back(InBounds);
1975 Args.push_back(ScalarPtr);
1976 for (
Value *Idx :
I.indices()) {
1978 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
1980 Args.push_back(Idx);
1982 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
1984 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
1988 replaceAllUsesWithAndErase(
B, &
I, NewI);
2006 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2007 return buildLogicalAccessChainFromGEP(
I);
2012 Value *PtrOp =
I.getPointerOperand();
2013 Type *SrcElemTy =
I.getSourceElementType();
2014 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2017 if (ArrTy->getElementType() == SrcElemTy) {
2019 Type *FirstIdxType =
I.getOperand(1)->getType();
2020 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2021 for (
Value *Idx :
I.indices())
2025 SmallVector<Value *, 4>
Args;
2026 Args.push_back(
B.getInt1(
I.isInBounds()));
2027 Args.push_back(
I.getPointerOperand());
2030 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2032 replaceAllUsesWithAndErase(
B, &
I, NewI);
2039 SmallVector<Value *, 4>
Args;
2040 Args.push_back(
B.getInt1(
I.isInBounds()));
2043 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2044 replaceAllUsesWithAndErase(
B, &
I, NewI);
2048Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &
I) {
2050 B.SetInsertPoint(&
I);
2059 I.eraseFromParent();
2066 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2067 replaceAllUsesWithAndErase(
B, &
I, NewI);
2071void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
2073 Type *VTy =
V->getType();
2078 if (ElemTy != AssignedType)
2091 if (CurrentType == AssignedType)
2098 " for value " +
V->getName(),
2106void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
2107 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2112 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2113 if (PointerElemTy == ExpectedElementType ||
2119 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2121 bool FirstPtrCastOrAssignPtrType =
true;
2127 for (
auto User :
Pointer->users()) {
2130 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2131 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2132 II->getOperand(0) != Pointer)
2137 FirstPtrCastOrAssignPtrType =
false;
2138 if (
II->getOperand(1) != VMD ||
2145 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2150 if (
II->getParent() !=
I->getParent())
2153 I->setOperand(OperandToReplace,
II);
2168 if (FirstPtrCastOrAssignPtrType) {
2173 }
else if (isTodoType(Pointer)) {
2174 eraseTodoType(Pointer);
2182 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2183 std::make_pair(
I, Pointer)};
2185 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2197 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2203void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2208 replacePointerOperandWithPtrCast(
2209 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2215 Type *OpTy =
Op->getType();
2218 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2221 if (OpTy ==
Op->getType())
2222 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2223 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2228 Type *OpTy = LI->getType();
2233 Type *NewOpTy = OpTy;
2234 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2235 if (OpTy == NewOpTy)
2236 insertTodoType(Pointer);
2239 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2244 Type *OpTy =
nullptr;
2256 OpTy = GEPI->getSourceElementType();
2258 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2260 insertTodoType(Pointer);
2272 std::string DemangledName =
2276 bool HaveTypes =
false;
2294 for (User *U : CalledArg->
users()) {
2296 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2302 HaveTypes |= ElemTy !=
nullptr;
2307 if (DemangledName.empty() && !HaveTypes)
2325 Type *ExpectedType =
2327 if (!ExpectedType && !DemangledName.empty())
2328 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2329 DemangledName,
OpIdx,
I->getContext());
2330 if (!ExpectedType || ExpectedType->
isVoidTy())
2338 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2342Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &
I) {
2349 I.getOperand(1)->getType(),
2350 I.getOperand(2)->getType()};
2352 B.SetInsertPoint(&
I);
2354 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2356 replaceAllUsesWithAndErase(
B, &
I, NewI);
2361SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &
I) {
2368 B.SetInsertPoint(&
I);
2370 I.getIndexOperand()->getType()};
2371 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2372 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2374 replaceAllUsesWithAndErase(
B, &
I, NewI);
2378Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &
I) {
2380 B.SetInsertPoint(&
I);
2383 Value *AggregateOp =
I.getAggregateOperand();
2387 Args.push_back(AggregateOp);
2388 Args.push_back(
I.getInsertedValueOperand());
2389 for (
auto &
Op :
I.indices())
2390 Args.push_back(
B.getInt32(
Op));
2392 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2393 replaceMemInstrUses(&
I, NewI,
B);
2397Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &
I) {
2399 B.SetInsertPoint(&
I);
2400 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2409 for (
auto &
Op :
I.indices())
2410 Args.push_back(
B.getInt32(
Op));
2411 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2412 {
I.getType()}, {
Args});
2413 replaceAllUsesWithAndErase(
B, &
I, NewI);
2417 for (
const Use &U : NewI->
uses()) {
2423 if (ArgNo < FT->getNumParams() &&
2424 !FT->getParamType(ArgNo)->isAggregateType()) {
2433Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &
I) {
2434 if (!
I.getType()->isAggregateType())
2437 B.SetInsertPoint(&
I);
2438 TrackConstants =
false;
2443 unsigned IntrinsicId;
2444 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2445 if (!
I.isAtomic()) {
2446 IntrinsicId = Intrinsic::spv_load;
2447 Args.push_back(
B.getInt32(
I.getAlign().value()));
2449 IntrinsicId = Intrinsic::spv_atomic_load;
2450 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2452 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2453 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2455 replaceMemInstrUses(&
I, NewI,
B);
2459Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &
I) {
2463 B.SetInsertPoint(&
I);
2464 TrackConstants =
false;
2468 auto *PtrOp =
I.getPointerOperand();
2470 if (
I.getValueOperand()->getType()->isAggregateType()) {
2478 "Unexpected argument of aggregate type, should be spv_extractv!");
2482 unsigned IntrinsicId;
2483 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2485 if (!
I.isAtomic()) {
2486 IntrinsicId = Intrinsic::spv_store;
2487 Args.push_back(
B.getInt32(
I.getAlign().value()));
2489 IntrinsicId = Intrinsic::spv_atomic_store;
2490 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2493 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2495 I.eraseFromParent();
2499Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &
I) {
2500 Value *ArraySize =
nullptr;
2501 if (
I.isArrayAllocation()) {
2504 SPIRV::Extension::SPV_INTEL_variable_length_array))
2506 "array allocation: this instruction requires the following "
2507 "SPIR-V extension: SPV_INTEL_variable_length_array",
2509 ArraySize =
I.getArraySize();
2512 B.SetInsertPoint(&
I);
2513 TrackConstants =
false;
2514 Type *PtrTy =
I.getType();
2517 ?
B.CreateIntrinsicWithoutFolding(
2518 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2519 {ArraySize,
B.getInt32(
I.getAlign().value())})
2520 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2521 {
B.getInt32(
I.getAlign().value())});
2522 replaceAllUsesWithAndErase(
B, &
I, NewI);
2526Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2527 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2529 B.SetInsertPoint(&
I);
2531 Args.push_back(
B.getInt32(
2532 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2535 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2536 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2537 uint32_t ScSem =
static_cast<uint32_t
>(
2539 Args.push_back(
B.getInt32(
2541 Args.push_back(
B.getInt32(
2544 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2545 replaceMemInstrUses(&
I, NewI,
B);
2554 case Intrinsic::spv_abort:
2556 case Intrinsic::trap:
2557 case Intrinsic::ubsantrap:
2559 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2579 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2580 "abort-like call must be the last non-debug instruction before its "
2581 "block's terminator");
2585Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &
I) {
2586 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2590 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2597 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2611 while (!Stack.empty()) {
2612 const Value *V = Stack.pop_back_val();
2613 if (!Visited.
insert(V).second)
2621 Stack.append(
C->user_begin(),
C->user_end());
2637 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2638 if (UserFunctions.contains(
F))
2643 if (!UserFunctions.empty())
2648 const Module &M = *
F->getParent();
2649 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2650 return F == &FirstDefinition;
2653Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(
Type *AggrTy,
2655 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2656 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2658 AggrConstTypes[Leaf] = ElemTy;
2661 SmallVector<Value *, 4> Elems;
2663 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2666 DenseMap<Type *, Instruction *> LeafByType;
2667 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2669 auto &
Entry = LeafByType[ElemTy];
2671 Entry = MakeLeaf(ElemTy);
2675 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2676 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2678 AggrConstTypes[Composite] = AggrTy;
2682void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2692 deduceElementTypeHelper(&GV,
false);
2697 Value *InitOp = Init;
2704 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2705 {
B.getInt32Ty()}, {});
2710 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2715 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2716 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2722 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2728bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *
I,
2730 bool UnknownElemTypeI8) {
2736 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2743void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *
I,
2746 static StringMap<unsigned> ResTypeWellKnown = {
2747 {
"async_work_group_copy", WellKnownTypes::Event},
2748 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2749 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2753 bool IsKnown =
false;
2758 std::string DemangledName =
2761 if (DemangledName.length() > 0)
2763 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2764 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2765 if (ResIt != ResTypeWellKnown.
end()) {
2768 switch (ResIt->second) {
2769 case WellKnownTypes::Event:
2776 switch (DecorationId) {
2779 case FPDecorationId::SAT:
2782 case FPDecorationId::RTE:
2784 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2786 case FPDecorationId::RTZ:
2788 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2790 case FPDecorationId::RTP:
2792 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2794 case FPDecorationId::RTN:
2796 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2802 Type *Ty =
I->getType();
2805 Type *TypeToAssign = Ty;
2808 auto It = AggrConstTypes.
find(
II);
2809 if (It == AggrConstTypes.
end())
2811 TypeToAssign = It->second;
2812 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2813 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2814 TypeToAssign = It->second;
2816 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2817 TypeToAssign = It->second;
2821 for (
const auto &
Op :
I->operands()) {
2828 Type *OpTy =
Op->getType();
2830 CallInst *AssignCI =
2835 Type *OpTy =
Op->getType();
2850 CallInst *AssignCI =
2860bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2861 Instruction *Inst) {
2863 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2873void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *
I,
2875 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2877 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2882 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2883 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2884 if (shouldTryToAddMemAliasingDecoration(
I)) {
2885 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2886 ? SPIRV::Decoration::AliasScopeINTEL
2887 : SPIRV::Decoration::NoAliasINTEL;
2889 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2892 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2893 {
I->getType()}, {
Args});
2897 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2898 processMemAliasingDecoration(LLVMContext::MD_noalias);
2901 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2903 bool AllowFPMaxError =
2905 if (!AllowFPMaxError)
2909 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2913 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
2917 auto &Ctx =
B.getContext();
2919 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
2922 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
2924 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
2925 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
2928 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
2930 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
2932 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2940 &FPFastMathDefaultInfoMap,
2942 auto it = FPFastMathDefaultInfoMap.
find(
F);
2943 if (it != FPFastMathDefaultInfoMap.
end())
2951 SPIRV::FPFastMathMode::None);
2953 SPIRV::FPFastMathMode::None);
2955 SPIRV::FPFastMathMode::None);
2956 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
2962 size_t BitWidth = Ty->getScalarSizeInBits();
2966 assert(Index >= 0 && Index < 3 &&
2967 "Expected FPFastMathDefaultInfo for half, float, or double");
2968 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2969 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2970 return FPFastMathDefaultInfoVec[Index];
2973void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(
Module &M) {
2975 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2984 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
2986 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
2994 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
2997 [[maybe_unused]] GlobalVariable *GV =
2998 new GlobalVariable(M,
2999 Type::getInt32Ty(
M.getContext()),
3013 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3014 FPFastMathDefaultInfoMap;
3016 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3025 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3027 "Expected 4 operands for FPFastMathDefault");
3033 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3035 SPIRV::FPFastMathDefaultInfo &
Info =
3038 Info.FPFastMathDefault =
true;
3039 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3041 "Expected no operands for ContractionOff");
3045 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3047 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3048 Info.ContractionOff =
true;
3050 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3052 "Expected 1 operand for SignedZeroInfNanPreserve");
3053 unsigned TargetWidth =
3058 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3062 assert(Index >= 0 && Index < 3 &&
3063 "Expected FPFastMathDefaultInfo for half, float, or double");
3064 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3065 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3066 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3070 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3071 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3072 if (FPFastMathDefaultInfoVec.
empty())
3075 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3076 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3079 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3080 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3084 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3086 "and AllowContract");
3088 if (
Info.SignedZeroInfNanPreserve &&
3090 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3091 SPIRV::FPFastMathMode::NSZ))) {
3092 if (
Info.FPFastMathDefault)
3094 "SignedZeroInfNanPreserve but at least one of "
3095 "NotNaN/NotInf/NSZ is enabled.");
3098 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3099 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3100 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3102 "AllowTransform requires AllowReassoc and "
3103 "AllowContract to be set.");
3106 auto it = GlobalVars.
find(Flags);
3107 GlobalVariable *GV =
nullptr;
3108 if (it != GlobalVars.
end()) {
3114 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3117 GV =
new GlobalVariable(M,
3118 Type::getInt32Ty(
M.getContext()),
3123 GlobalVars[
Flags] = GV;
3129void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *
I,
3132 bool IsConstComposite =
3133 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3134 if (IsConstComposite && TrackConstants) {
3136 auto t = AggrConsts.
find(
I);
3140 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3142 NewOp->setArgOperand(0,
I);
3145 for (
const auto &
Op :
I->operands()) {
3149 unsigned OpNo =
Op.getOperandNo();
3150 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3151 (!
II->isBundleOperand(OpNo) &&
3152 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3156 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3157 :
B.SetInsertPoint(
I);
3160 Type *OpTy =
Op->getType();
3168 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3170 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3171 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3173 SmallVector<Value *, 2>
Args = {
3176 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3182 I->setOperand(OpNo, NewOp);
3188Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *
F,
3190 SmallPtrSet<Function *, 0> FVisited;
3191 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3194Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
3195 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3197 if (!FVisited.
insert(
F).second)
3200 SmallPtrSet<Value *, 0> Visited;
3203 for (User *U :
F->users()) {
3215 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3218 for (User *OpU : OpArg->
users()) {
3220 if (!Inst || Inst == CI)
3223 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3230 if (FVisited.
find(OuterF) != FVisited.
end())
3232 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3233 if (OuterF->
getArg(i) == OpArg) {
3234 Lookup.push_back(std::make_pair(OuterF, i));
3241 for (
auto &Pair :
Lookup) {
3242 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3249void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *
F,
3251 B.SetInsertPointPastAllocas(
F);
3258 for (User *U : Arg->
users()) {
3260 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3278 for (User *U :
F->users()) {
3294 for (User *U : Arg->
users()) {
3298 CI->
getParent()->getParent() == CurrF) {
3300 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3311void SPIRVEmitIntrinsics::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3312 B.SetInsertPointPastAllocas(
F);
3318 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3320 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3322 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3334 bool IsNewFTy =
false;
3350bool SPIRVEmitIntrinsics::processFunctionPointers(
Module &M) {
3353 if (
F.isIntrinsic())
3355 if (
F.isDeclaration()) {
3356 for (User *U :
F.users()) {
3369 for (User *U :
F.users()) {
3371 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3373 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3374 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3381 if (Worklist.
empty())
3384 LLVMContext &Ctx =
M.getContext();
3389 for (Function *
F : Worklist) {
3391 for (
const auto &Arg :
F->args())
3393 IRB.CreateCall(
F, Args);
3395 IRB.CreateRetVoid();
3401void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3402 DenseMap<Function *, CallInst *> Ptrcasts;
3403 for (
auto It : FDeclPtrTys) {
3405 for (
auto *U :
F->users()) {
3410 for (
auto [Idx, ElemTy] : It.second) {
3418 B.SetInsertPointPastAllocas(Arg->
getParent());
3422 }
else if (isaGEP(Param)) {
3423 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3432 .getFirstNonPHIOrDbgOrAlloca());
3453SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP) {
3460 Type *SrcTy =
GEP->getSourceElementType();
3461 SmallVector<Value *, 8> Indices(
GEP->indices());
3463 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3464 Indices.erase(Indices.begin());
3465 SrcTy = ArrTy->getElementType();
3467 GEP->getNoWrapFlags(),
"",
3468 GEP->getIterator());
3473void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &
F,
3480 if (
ST->canUseExtension(
3481 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3482 for (BasicBlock &BB :
F) {
3484 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3488 SmallVector<unsigned, 1>
Ops =
3490 unsigned LC =
Ops[0];
3491 if (LC == SPIRV::LoopControl::None)
3495 B.SetInsertPoint(Term);
3496 SmallVector<Value *, 4> IntrArgs;
3497 for (
unsigned Op :
Ops)
3499 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3506 DominatorTree DT(
F);
3511 for (Loop *L : LI.getLoopsInPreorder()) {
3520 SmallVector<unsigned, 1> LoopControlOps =
3522 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3526 B.SetInsertPoint(Header->getTerminator());
3529 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3530 for (
unsigned Imm : LoopControlOps)
3531 Args.emplace_back(
B.getInt32(Imm));
3532 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3536bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3537 if (
Func.isDeclaration())
3541 GR =
ST.getSPIRVGlobalRegistry();
3545 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3550 AggrConstTypes.
clear();
3553 processParamTypesByFunHeader(CurrF,
B);
3557 SmallPtrSet<Instruction *, 4> DeadInsts;
3562 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3566 GR->addDeducedElementType(SGEP,
3571 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3573 GEP->replaceAllUsesWith(NewGEP);
3577 if (
Type *GepTy = getGEPType(
GEP))
3581 for (
auto *
I : DeadInsts) {
3582 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3583 I->eraseFromParent();
3593 Type *ElTy =
SI->getValueOperand()->getType();
3598 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3599 for (
auto &GV :
Func.getParent()->globals())
3600 processGlobalValue(GV,
B);
3602 preprocessUndefsAndPoisons(
B);
3603 simplifyNullAddrSpaceCasts();
3604 preprocessCompositeConstants(
B);
3612 Type *I32Ty =
B.getInt32Ty();
3616 if (!
I.getType()->isAggregateType())
3618 AggrConstTypes[&
I] =
I.getType();
3619 I.mutateType(I32Ty);
3622 preprocessBoolVectorBitcasts(Func);
3626 applyDemangledPtrArgTypes(
B);
3629 for (
auto &
I : Worklist) {
3631 if (isConvergenceIntrinsic(
I))
3634 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3636 insertAssignTypeIntrs(
I,
B);
3637 insertPtrCastOrAssignTypeInstr(
I,
B);
3641 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3642 insertAssignPtrTypeIntrs(
I,
B,
true);
3645 useRoundingMode(FPI,
B);
3650 SmallPtrSet<Instruction *, 4> IncompleteRets;
3652 deduceOperandElementType(&
I, &IncompleteRets);
3656 for (BasicBlock &BB : Func)
3657 for (PHINode &Phi : BB.
phis())
3659 deduceOperandElementType(&Phi,
nullptr);
3661 for (
auto *
I : Worklist) {
3662 TrackConstants =
true;
3672 if (isConvergenceIntrinsic(
I))
3676 processInstrAfterVisit(
I,
B);
3679 emitUnstructuredLoopControls(Func,
B);
3685bool SPIRVEmitIntrinsics::postprocessTypes(
Module &M) {
3686 if (!GR || TodoTypeSz == 0)
3689 unsigned SzTodo = TodoTypeSz;
3690 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3695 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3696 Type *KnownTy = GR->findDeducedElementType(
Op);
3697 if (!KnownTy || !AssignCI)
3703 SmallPtrSet<Value *, 0> Visited;
3704 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3705 if (ElemTy != KnownTy) {
3706 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3707 propagateElemType(CI, ElemTy, VisitedSubst);
3714 if (
Op->hasUseList()) {
3715 for (User *U :
Op->users()) {
3722 if (TodoTypeSz == 0)
3727 SmallPtrSet<Instruction *, 4> IncompleteRets;
3729 auto It = ToProcess.
find(&
I);
3730 if (It == ToProcess.
end())
3732 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3733 if (It->second.size() == 0)
3735 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3736 if (TodoTypeSz == 0)
3741 return SzTodo > TodoTypeSz;
3745void SPIRVEmitIntrinsics::parseFunDeclarations(
Module &M) {
3747 if (!
F.isDeclaration() ||
F.isIntrinsic())
3751 if (DemangledName.empty())
3755 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3756 DemangledName,
ST.getPreferredInstructionSet());
3757 if (Opcode != SPIRV::OpGroupAsyncCopy)
3760 SmallVector<unsigned> Idxs;
3769 LLVMContext &Ctx =
F.getContext();
3771 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3772 if (!TypeStrs.
size())
3775 for (
unsigned Idx : Idxs) {
3776 if (Idx >= TypeStrs.
size())
3779 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3782 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3787bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3788 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3790 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3791 if (!
ST.canUseExtension(
3792 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3793 I.getContext().emitError(
3794 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3798 I.eraseFromParent();
3804 Value *Ptrs =
I.getArgOperand(0);
3806 Value *Passthru =
I.getArgOperand(2);
3809 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3811 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3816 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3818 I.eraseFromParent();
3822 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3823 if (!
ST.canUseExtension(
3824 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3825 I.getContext().emitError(
3826 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3829 I.eraseFromParent();
3835 Value *Values =
I.getArgOperand(0);
3836 Value *Ptrs =
I.getArgOperand(1);
3841 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3843 SmallVector<Value *, 4>
Args = {Values, Ptrs,
B.getInt32(Alignment),
Mask};
3847 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3848 I.eraseFromParent();
3859void SPIRVEmitIntrinsics::preprocessBoolVectorBitcasts(Function &
F) {
3860 struct BoolVecBitcast {
3862 FixedVectorType *BoolVecTy;
3866 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3868 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3876 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3878 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3882 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3884 Value *Src = BC->getOperand(0);
3885 unsigned BoolVecN = BoolVecTy->getNumElements();
3887 Type *IntTy =
B.getIntNTy(BoolVecN);
3893 IntVal = ConstantInt::get(IntTy, 0);
3894 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3895 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3896 Value *Ext =
B.CreateZExt(Elem, IntTy);
3898 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3899 IntVal =
B.CreateOr(IntVal, Ext);
3905 if (!Src->getType()->isIntegerTy())
3906 IntVal =
B.CreateBitCast(Src, IntTy);
3911 if (!SrcIsBoolVec) {
3914 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3917 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
3918 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
3924 if (!BC->getDestTy()->isIntegerTy())
3925 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
3928 BC->replaceAllUsesWith(Result);
3929 BC->eraseFromParent();
3933bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(
Module &M) {
3937 if (!
F.isIntrinsic())
3940 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
3945 Changed |= processMaskedMemIntrinsic(*
II);
3949 F.eraseFromParent();
3955bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
3958 Changed |= convertMaskedMemIntrinsics(M);
3960 parseFunDeclarations(M);
3961 insertConstantsForFPFastMathDefault(M);
3972 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
3974 processParamTypes(&
F,
B);
3978 CanTodoType =
false;
3979 Changed |= postprocessTypes(M);
3982 Changed |= processFunctionPointers(M);
3989 SPIRVEmitIntrinsics Legacy(TM);
3990 if (Legacy.runOnModule(M))
3996 return new SPIRVEmitIntrinsics(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
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
static Value * getOpcode(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Machine Check Debug Module
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static unsigned getNumElements(Type *Ty)
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 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 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)
IntrinsicID_match m_Intrinsic()
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_Value()
Match an arbitrary value and ignore it.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
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.
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.
FunctionAddr VTableAddr Value
ModulePass * createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
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.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
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)
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)