27#include "llvm/IR/IntrinsicsSPIRV.h"
38#include <unordered_set>
61#define DEBUG_TYPE "spirv-emit-intrinsics"
65 cl::desc(
"Emit OpName for all instructions"),
69#define GET_BuiltinGroup_DECL
70#include "SPIRVGenTables.inc"
75class GlobalVariableUsers {
76 template <
typename T1,
typename T2>
77 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
79 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
81 void collectGlobalUsers(
82 const GlobalVariable *GV,
83 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
84 &GlobalIsUsedByGlobal) {
86 while (!
Stack.empty()) {
90 GlobalIsUsedByFun[GV].insert(
I->getFunction());
95 GlobalIsUsedByGlobal[GV].insert(UserGV);
100 Stack.append(
C->user_begin(),
C->user_end());
104 bool propagateGlobalToGlobalUsers(
105 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
106 &GlobalIsUsedByGlobal) {
109 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
110 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
111 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
112 auto It = GlobalIsUsedByGlobal.find(UserGV);
113 if (It == GlobalIsUsedByGlobal.end())
121 void propagateGlobalToFunctionReferences(
122 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
123 &GlobalIsUsedByGlobal) {
124 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
125 auto &UserFunctions = GlobalIsUsedByFun[GV];
126 for (
const GlobalVariable *UserGV : UserGlobals) {
127 auto It = GlobalIsUsedByFun.find(UserGV);
128 if (It == GlobalIsUsedByFun.end())
139 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
140 GlobalIsUsedByGlobal;
141 GlobalIsUsedByFun.clear();
142 for (GlobalVariable &GV :
M.globals())
143 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
146 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
149 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
152 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
153 const FunctionSetType &
154 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
155 auto It = GlobalIsUsedByFun.find(&GV);
156 if (It != GlobalIsUsedByFun.end())
159 static const FunctionSetType
Empty{};
164static bool isaGEP(
const Value *V) {
170static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
176 return AT->getNumElements();
182class SPIRVEmitIntrinsics
184 public InstVisitor<SPIRVEmitIntrinsics, 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 DenseSet<Instruction *> AggrStores;
193 GlobalVariableUsers GVUsers;
194 std::unordered_set<Value *> 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 std::unordered_set<Instruction *> TypeValidated;
229 enum WellKnownTypes { Event };
232 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
233 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
234 Type *deduceElementTypeHelper(
Value *
I, std::unordered_set<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 std::unordered_set<Value *> &Visited,
241 bool UnknownElemTypeI8);
243 std::unordered_set<Value *> &Visited,
244 bool UnknownElemTypeI8);
246 bool UnknownElemTypeI8);
249 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
250 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
251 std::unordered_set<Value *> &Visited,
252 bool UnknownElemTypeI8);
255 void deduceOperandElementType(Instruction *
I,
256 SmallPtrSet<Instruction *, 4> *IncompleteRets,
257 const SmallPtrSet<Value *, 4> *AskOps =
nullptr,
258 bool IsPostprocessing =
false);
263 void simplifyNullAddrSpaceCasts();
265 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
266 bool IsPostprocessing);
268 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
270 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
271 bool UnknownElemTypeI8);
273 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
275 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
276 Type *ExpectedElementType,
277 unsigned OperandToReplace,
279 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
280 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
282 void insertConstantsForFPFastMathDefault(
Module &M);
284 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
286 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
287 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
288 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx,
289 std::unordered_set<Function *> &FVisited);
291 bool deduceOperandElementTypeCalledFunction(
293 Type *&KnownElemTy,
bool &Incomplete);
294 void deduceOperandElementTypeFunctionPointer(
296 Type *&KnownElemTy,
bool IsPostprocessing);
297 bool deduceOperandElementTypeFunctionRet(
298 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
299 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
302 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
303 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
304 DenseMap<Function *, CallInst *> Ptrcasts);
306 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
309 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
310 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
311 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
312 std::unordered_set<Value *> &Visited,
313 DenseMap<Function *, CallInst *> Ptrcasts);
316 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
317 Instruction *Dest,
bool DeleteOld =
true);
321 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
324 bool postprocessTypes(
Module &M);
325 bool processFunctionPointers(
Module &M);
326 void parseFunDeclarations(
Module &M);
327 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
328 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
329 bool convertMaskedMemIntrinsics(
Module &M);
330 void preprocessBoolVectorBitcasts(Function &
F);
332 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
349 bool walkLogicalAccessChain(
350 GetElementPtrInst &
GEP,
351 const std::function<
void(
Type *PointedType, uint64_t Index)>
354 uint64_t Multiplier)> &OnDynamicIndexing);
356 bool walkLogicalAccessChainDynamic(
357 Type *CurType,
Value *Operand, uint64_t Multiplier,
358 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
359 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing);
361 bool walkLogicalAccessChainConstant(
363 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing);
369 Type *getGEPType(GetElementPtrInst *
GEP);
376 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
378 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
382 SPIRVEmitIntrinsics(
const SPIRVTargetMachine &TM) : ModulePass(ID), TM(TM) {}
385 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
388 Instruction *visitInsertElementInst(InsertElementInst &
I);
389 Instruction *visitExtractElementInst(ExtractElementInst &
I);
391 Instruction *visitExtractValueInst(ExtractValueInst &
I);
395 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
399 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
401 bool runOnModule(
Module &M)
override;
403 void getAnalysisUsage(AnalysisUsage &AU)
const override {
404 ModulePass::getAnalysisUsage(AU);
410 Intrinsic::experimental_convergence_loop,
411 Intrinsic::experimental_convergence_anchor>());
414bool expectIgnoredInIRTranslation(
const Instruction *
I) {
416 Intrinsic::spv_resource_handlefrombinding,
417 Intrinsic::spv_resource_getbasepointer,
418 Intrinsic::spv_resource_getpointer>());
425 return getPointerRoot(V);
431char SPIRVEmitIntrinsics::ID = 0;
434 "SPIRV emit intrinsics",
false,
false)
448 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
461 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
467 B.SetCurrentDebugLocation(
I->getDebugLoc());
468 if (
I->getType()->isVoidTy())
469 B.SetInsertPoint(
I->getNextNode());
471 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
481 if (
I->getType()->isTokenTy())
483 "does not support token type",
488 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
489 expectIgnoredInIRTranslation(
I))
500 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
511 std::vector<Value *> Args = {
514 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
517void SPIRVEmitIntrinsics::replaceAllUsesWith(
Value *Src,
Value *Dest,
521 if (isTodoType(Src)) {
524 insertTodoType(Dest);
528void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
533 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
534 Src->eraseFromParent();
537 if (Named.insert(Dest).second)
562Type *SPIRVEmitIntrinsics::reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
563 bool IsPostprocessing) {
567 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
581 if (UnknownElemTypeI8) {
582 if (!IsPostprocessing)
590CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *
F,
Value *
Op,
598 B.SetInsertPointPastAllocas(OpA->getParent());
601 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
603 Type *OpTy =
Op->getType();
607 CallInst *PtrCasted =
608 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
613void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
615 DenseMap<Function *, CallInst *> Ptrcasts) {
617 CallInst *PtrCastedI =
nullptr;
618 auto It = Ptrcasts.
find(
F);
619 if (It == Ptrcasts.
end()) {
620 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
621 Ptrcasts[
F] = PtrCastedI;
623 PtrCastedI = It->second;
625 I->replaceUsesOfWith(
Op, PtrCastedI);
628void SPIRVEmitIntrinsics::propagateElemType(
630 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
631 DenseMap<Function *, CallInst *> Ptrcasts;
633 for (
auto *U :
Users) {
636 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
641 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
642 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
646void SPIRVEmitIntrinsics::propagateElemTypeRec(
648 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
649 std::unordered_set<Value *> Visited;
650 DenseMap<Function *, CallInst *> Ptrcasts;
651 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
652 std::move(Ptrcasts));
655void SPIRVEmitIntrinsics::propagateElemTypeRec(
657 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
658 std::unordered_set<Value *> &Visited,
659 DenseMap<Function *, CallInst *> Ptrcasts) {
660 if (!Visited.insert(
Op).second)
663 for (
auto *U :
Users) {
666 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
671 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
672 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
680SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
681 bool UnknownElemTypeI8) {
682 std::unordered_set<Value *> Visited;
683 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
687Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
688 Type *ValueTy,
Value *Operand, std::unordered_set<Value *> &Visited,
689 bool UnknownElemTypeI8) {
694 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
705Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
706 Value *
Op, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8) {
718 for (User *OpU :
Op->users()) {
720 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
733 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
742Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I,
743 bool UnknownElemTypeI8) {
744 std::unordered_set<Value *> Visited;
745 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
748void SPIRVEmitIntrinsics::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
Type *RefTy,
749 bool UnknownElemTypeI8) {
751 if (!UnknownElemTypeI8)
760bool SPIRVEmitIntrinsics::walkLogicalAccessChainDynamic(
761 Type *CurType,
Value *Operand, uint64_t Multiplier,
762 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
763 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
769 if (
ST->getNumElements() == 0)
771 CurType =
ST->getElementType(0);
772 OnLiteralIndexing(CurType, 0);
780 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
781 return AT ==
nullptr;
784bool SPIRVEmitIntrinsics::walkLogicalAccessChainConstant(
786 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
791 uint32_t EltTypeSize =
DL.getTypeSizeInBits(AT->getElementType()) / 8;
795 CurType = AT->getElementType();
796 OnLiteralIndexing(CurType, Index);
798 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
801 const auto &STL =
DL.getStructLayout(ST);
802 unsigned Element = STL->getElementContainingOffset(
Offset);
803 Offset -= STL->getElementOffset(Element);
804 CurType =
ST->getElementType(Element);
805 OnLiteralIndexing(CurType, Element);
807 Type *EltTy = VT->getElementType();
808 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
809 assert(EltSizeBits % 8 == 0 &&
810 "Element type size in bits must be a multiple of 8.");
811 uint32_t EltTypeSize = EltSizeBits / 8;
816 OnLiteralIndexing(CurType, Index);
826bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
827 GetElementPtrInst &
GEP,
828 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
829 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
832 std::optional<uint64_t> MultiplierOpt =
833 getByteAddressingMultiplier(
GEP.getSourceElementType());
834 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
835 uint64_t Multiplier = *MultiplierOpt;
838 Value *Src = getPointerRoot(
GEP.getPointerOperand());
839 Type *CurType = deduceElementType(Src,
true);
843 return walkLogicalAccessChainConstant(
844 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
846 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
847 OnLiteralIndexing, OnDynamicIndexing);
851SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP) {
854 B.SetInsertPoint(&
GEP);
856 std::vector<Value *> Indices;
857 Indices.push_back(ConstantInt::get(
858 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
859 walkLogicalAccessChain(
861 [&Indices, &
B](
Type *EltType, uint64_t Index) {
863 ConstantInt::get(
B.getInt64Ty(), Index,
false));
866 uint64_t Multiplier) {
868 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
870 if (Multiplier == EltTypeSize) {
872 }
else if (EltTypeSize % Multiplier == 0) {
875 EltTypeSize / Multiplier,
879 ConstantInt::get(
Offset->getType(), Multiplier,
882 Index =
B.CreateUDiv(Index,
883 ConstantInt::get(
Offset->getType(), EltTypeSize,
887 Indices.push_back(Index);
891 SmallVector<Value *, 4>
Args;
892 Args.push_back(
B.getInt1(
GEP.isInBounds()));
893 Args.push_back(
GEP.getOperand(0));
895 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
896 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
900Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *
GEP) {
902 Type *CurType =
GEP->getResultElementType();
904 bool Interrupted = walkLogicalAccessChain(
905 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
906 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
908 return Interrupted ?
GEP->getResultElementType() : CurType;
911Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *
Ref) {
912 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
914 return getGEPTypeLogical(
Ref);
921 Ty =
Ref->getSourceElementType();
925 Ty =
Ref->getResultElementType();
930Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
931 Value *
I, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8,
932 bool IgnoreKnownType) {
938 if (!IgnoreKnownType)
943 if (!Visited.insert(
I).second)
950 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
952 Ty = getGEPType(
Ref);
954 Ty = SGEP->getResultElementType();
959 KnownTy =
Op->getType();
961 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
964 Ty = SPIRV::getOriginalFunctionType(*Fn);
967 Ty = deduceElementTypeByValueDeep(
969 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
973 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
975 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
977 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
979 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
981 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
986 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
990 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
992 Type *BestTy =
nullptr;
994 DenseMap<Type *, unsigned> PhiTys;
995 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
996 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1003 if (It.first->second > MaxN) {
1004 MaxN = It.first->second;
1012 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1013 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1018 static StringMap<unsigned> ResTypeByArg = {
1022 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1023 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1024 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1025 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1026 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1027 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1031 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1032 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1034 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1035 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1036 for (User *U :
II->users()) {
1041 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1043 Ty = HandleType->getTypeParameter(0);
1044 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1058 }
else if (
II &&
II->getIntrinsicID() ==
1059 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1063 std::string DemangledName =
1065 if (DemangledName.length() > 0)
1066 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1067 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1068 if (AsArgIt != ResTypeByArg.
end())
1069 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1070 Visited, UnknownElemTypeI8);
1077 if (Ty && !IgnoreKnownType) {
1088Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1089 bool UnknownElemTypeI8) {
1090 std::unordered_set<Value *> Visited;
1091 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1094Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
1095 User *U,
Type *OrigTy, std::unordered_set<Value *> &Visited,
1096 bool UnknownElemTypeI8) {
1105 if (!Visited.insert(U).second)
1110 bool Change =
false;
1111 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1113 assert(
Op &&
"Operands should not be null.");
1114 Type *OpTy =
Op->getType();
1117 if (
Type *NestedTy =
1118 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1125 Change |= Ty != OpTy;
1133 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1134 Type *OpTy = ArrTy->getElementType();
1137 if (
Type *NestedTy =
1138 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1145 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1151 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1152 Type *OpTy = VecTy->getElementType();
1155 if (
Type *NestedTy =
1156 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1163 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1173Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I,
bool UnknownElemTypeI8) {
1174 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1176 if (!UnknownElemTypeI8)
1179 return IntegerType::getInt8Ty(
I->getContext());
1183 Value *PointerOperand) {
1189 return I->getType();
1197bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1199 Type *&KnownElemTy,
bool &Incomplete) {
1203 std::string DemangledName =
1205 if (DemangledName.length() > 0 &&
1207 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1208 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1209 DemangledName,
ST.getPreferredInstructionSet());
1210 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1211 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1217 KnownElemTy = ElemTy;
1218 Ops.push_back(std::make_pair(
Op, i));
1220 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1227 case SPIRV::OpAtomicFAddEXT:
1228 case SPIRV::OpAtomicFMinEXT:
1229 case SPIRV::OpAtomicFMaxEXT:
1230 case SPIRV::OpAtomicLoad:
1231 case SPIRV::OpAtomicCompareExchangeWeak:
1232 case SPIRV::OpAtomicCompareExchange:
1233 case SPIRV::OpAtomicExchange:
1234 case SPIRV::OpAtomicIAdd:
1235 case SPIRV::OpAtomicISub:
1236 case SPIRV::OpAtomicOr:
1237 case SPIRV::OpAtomicXor:
1238 case SPIRV::OpAtomicAnd:
1239 case SPIRV::OpAtomicUMin:
1240 case SPIRV::OpAtomicUMax:
1241 case SPIRV::OpAtomicSMin:
1242 case SPIRV::OpAtomicSMax: {
1247 Incomplete = isTodoType(
Op);
1248 Ops.push_back(std::make_pair(
Op, 0));
1250 case SPIRV::OpAtomicStore: {
1259 Incomplete = isTodoType(
Op);
1260 Ops.push_back(std::make_pair(
Op, 0));
1269void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1271 Type *&KnownElemTy,
bool IsPostprocessing) {
1275 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1276 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1277 bool IsNewFTy =
false, IsIncomplete =
false;
1280 Type *ArgTy = Arg->getType();
1285 if (isTodoType(Arg))
1286 IsIncomplete =
true;
1288 IsIncomplete =
true;
1291 ArgTy = FTy->getFunctionParamType(ParmIdx);
1295 Type *RetTy = FTy->getReturnType();
1302 IsIncomplete =
true;
1304 IsIncomplete =
true;
1307 if (!IsPostprocessing && IsIncomplete)
1310 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1313bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1314 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1315 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
1327 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1328 for (User *U :
F->users()) {
1336 propagateElemType(CI, PrevElemTy, VisitedSubst);
1346 for (Instruction *IncompleteRetI : *IncompleteRets)
1347 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1349 }
else if (IncompleteRets) {
1352 TypeValidated.insert(
I);
1360void SPIRVEmitIntrinsics::deduceOperandElementType(
1361 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1362 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing) {
1364 Type *KnownElemTy =
nullptr;
1365 bool Incomplete =
false;
1371 Incomplete = isTodoType(
I);
1372 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1375 Ops.push_back(std::make_pair(
Op, i));
1381 Incomplete = isTodoType(
I);
1382 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1389 Incomplete = isTodoType(
I);
1390 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1394 KnownElemTy =
Ref->getSourceElementType();
1395 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1400 KnownElemTy =
Ref->getBaseType();
1401 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1404 KnownElemTy =
I->getType();
1410 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1414 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1419 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1427 Incomplete = isTodoType(
Ref->getPointerOperand());
1428 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1436 Incomplete = isTodoType(
Ref->getPointerOperand());
1437 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1443 Incomplete = isTodoType(
I);
1444 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1447 Ops.push_back(std::make_pair(
Op, i));
1455 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1456 IsPostprocessing, KnownElemTy,
Op,
1459 Incomplete = isTodoType(CurrF);
1460 Ops.push_back(std::make_pair(
Op, 0));
1466 bool Incomplete0 = isTodoType(Op0);
1467 bool Incomplete1 = isTodoType(Op1);
1469 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1471 : GR->findDeducedElementType(Op0);
1473 KnownElemTy = ElemTy0;
1474 Incomplete = Incomplete0;
1475 Ops.push_back(std::make_pair(Op1, 1));
1476 }
else if (ElemTy1) {
1477 KnownElemTy = ElemTy1;
1478 Incomplete = Incomplete1;
1479 Ops.push_back(std::make_pair(Op0, 0));
1483 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1484 else if (HaveFunPtrs)
1485 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1490 if (!KnownElemTy ||
Ops.size() == 0)
1495 for (
auto &OpIt :
Ops) {
1499 Type *AskTy =
nullptr;
1500 CallInst *AskCI =
nullptr;
1501 if (IsPostprocessing && AskOps) {
1507 if (Ty == KnownElemTy)
1510 Type *OpTy =
Op->getType();
1511 if (
Op->hasUseList() &&
1518 else if (!IsPostprocessing)
1522 if (AssignCI ==
nullptr) {
1531 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1532 std::make_pair(
I,
Op)};
1533 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1537 CallInst *PtrCastI =
1538 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1539 if (OpIt.second == std::numeric_limits<unsigned>::max())
1542 I->setOperand(OpIt.second, PtrCastI);
1545 TypeValidated.insert(
I);
1548void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1553 if (isAssignTypeInstr(U)) {
1554 B.SetInsertPoint(U);
1555 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1556 CallInst *AssignCI =
1557 B.CreateIntrinsic(Intrinsic::spv_assign_type, {
New->getType()},
Args);
1559 U->eraseFromParent();
1562 U->replaceUsesOfWith(Old, New);
1570 Type *NewArgTy =
New->getType();
1572 if (NewArgTy != ExpectedArgTy) {
1575 M, Intrinsic::spv_abort, {NewArgTy});
1585 "aggregate PHI/select/freeze should have been mutated to value-id "
1587 U->replaceUsesOfWith(Old, New);
1592 New->copyMetadata(*Old);
1596void SPIRVEmitIntrinsics::preprocessUndefs(
IRBuilder<> &
B) {
1600 SmallVector<Instruction *, 16> Insts;
1604 for (Instruction *
I : Insts) {
1605 bool BPrepared =
false;
1606 for (
auto &
Op :
I->operands()) {
1608 if (!AggrUndef || !
Op->getType()->isAggregateType())
1613 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1614 "lowered as undef\n");
1620 auto *IntrUndef =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
1621 I->replaceUsesOfWith(
Op, IntrUndef);
1622 AggrConsts[IntrUndef] = AggrUndef;
1623 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1628void SPIRVEmitIntrinsics::preprocessPoisons(
IRBuilder<> &
B) {
1634 bool BPrepared =
false;
1637 for (
unsigned Idx = 0; Idx <
I.getNumOperands(); ++Idx) {
1640 if (!
Poison ||
Op->getType()->isMetadataTy())
1643 Type *OpTy =
Op->getType();
1644 Value *Replacement =
nullptr;
1651 B.CreateIntrinsic(Intrinsic::spv_poison, {
B.getInt32Ty()}, {});
1653 AggrConstTypes[
Call] = OpTy;
1657 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1658 else if (!BPrepared) {
1662 Replacement =
B.CreateIntrinsic(Intrinsic::spv_poison, {OpTy}, {});
1664 I.setOperand(Idx, Replacement);
1673void SPIRVEmitIntrinsics::simplifyNullAddrSpaceCasts() {
1677 ASC->replaceAllUsesWith(
1679 ASC->eraseFromParent();
1683void SPIRVEmitIntrinsics::preprocessCompositeConstants(
IRBuilder<> &
B) {
1687 std::queue<Instruction *> Worklist;
1691 while (!Worklist.empty()) {
1692 auto *
I = Worklist.front();
1695 bool KeepInst =
false;
1696 for (
const auto &
Op :
I->operands()) {
1698 Type *ResTy =
nullptr;
1701 ResTy = COp->getType();
1713 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1716 auto PrepareInsert = [&]() {
1719 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1720 :
B.SetInsertPoint(
I);
1725 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1726 Args.push_back(COp->getElementAsConstant(i));
1732 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1737 Type *PoisonTy =
Op->getType();
1739 auto *
Call =
B.CreateIntrinsic(Intrinsic::spv_poison,
1740 {
B.getInt32Ty()}, {});
1742 AggrConstTypes[
Call] = PoisonTy;
1745 Op =
B.CreateIntrinsic(Intrinsic::spv_poison, {PoisonTy}, {});
1752 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {
Args});
1756 AggrConsts[CI] = AggrConst;
1757 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1769 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1774 unsigned RoundingModeDeco,
1781 ConstantInt::get(
Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1790 MDNode *SaturatedConversionNode =
1792 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1812 MDString *ConstraintString =
1821 B.SetInsertPoint(&
Call);
1822 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1827void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1830 if (!
RM.has_value())
1832 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1833 switch (
RM.value()) {
1837 case RoundingMode::NearestTiesToEven:
1838 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1840 case RoundingMode::TowardNegative:
1841 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1843 case RoundingMode::TowardPositive:
1844 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1846 case RoundingMode::TowardZero:
1847 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1849 case RoundingMode::Dynamic:
1850 case RoundingMode::NearestTiesToAway:
1854 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1860Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &
I) {
1864 B.SetInsertPoint(&
I);
1865 SmallVector<Value *, 4>
Args;
1867 Args.push_back(
I.getCondition());
1870 for (
auto &Case :
I.cases()) {
1871 Args.push_back(Case.getCaseValue());
1872 BBCases.
push_back(Case.getCaseSuccessor());
1875 CallInst *NewI =
B.CreateIntrinsic(Intrinsic::spv_switch,
1876 {
I.getOperand(0)->getType()}, {
Args});
1880 I.eraseFromParent();
1883 B.SetInsertPoint(ParentBB);
1884 IndirectBrInst *BrI =
B.CreateIndirectBr(
1887 for (BasicBlock *BBCase : BBCases)
1896Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &
I) {
1902 B.SetInsertPoint(&
I);
1904 SmallVector<Value *, 4>
Args;
1905 Args.push_back(
B.getInt1(
true));
1906 Args.push_back(
I.getOperand(0));
1907 Args.push_back(
B.getInt32(0));
1908 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1909 Args.push_back(SGEP->getIndexOperand(J));
1911 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, Types, Args);
1912 replaceAllUsesWithAndErase(
B, &
I, NewI);
1916Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &
I) {
1918 B.SetInsertPoint(&
I);
1923 unsigned N = RetVTy->getNumElements();
1924 Value *PtrOp =
I.getPointerOperand();
1926 Type *ResultPtrTy = RetVTy->getElementType();
1929 Value *InBounds =
B.getInt1(
I.isInBounds());
1930 Type *LanePointeeTy = getGEPType(&
I);
1931 Type *SrcElemTy =
I.getSourceElementType();
1940 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
1941 Value *LaneIdx =
B.getInt32(Lane);
1942 Value *ScalarPtr = PtrOp;
1946 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
1950 SmallVector<Value *, 4>
Args;
1951 Args.push_back(InBounds);
1952 Args.push_back(ScalarPtr);
1953 for (
Value *Idx :
I.indices()) {
1955 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
1957 Args.push_back(Idx);
1959 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
1961 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
1965 replaceAllUsesWithAndErase(
B, &
I, NewI);
1983 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
1984 return buildLogicalAccessChainFromGEP(
I);
1989 Value *PtrOp =
I.getPointerOperand();
1990 Type *SrcElemTy =
I.getSourceElementType();
1991 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
1994 if (ArrTy->getElementType() == SrcElemTy) {
1996 Type *FirstIdxType =
I.getOperand(1)->getType();
1997 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
1998 for (
Value *Idx :
I.indices())
2002 SmallVector<Value *, 4>
Args;
2003 Args.push_back(
B.getInt1(
I.isInBounds()));
2004 Args.push_back(
I.getPointerOperand());
2007 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
2008 replaceAllUsesWithAndErase(
B, &
I, NewI);
2015 SmallVector<Value *, 4>
Args;
2016 Args.push_back(
B.getInt1(
I.isInBounds()));
2018 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
2019 replaceAllUsesWithAndErase(
B, &
I, NewI);
2023Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &
I) {
2025 B.SetInsertPoint(&
I);
2034 I.eraseFromParent();
2040 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_bitcast, {
Types}, {
Args});
2041 replaceAllUsesWithAndErase(
B, &
I, NewI);
2045void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
2047 Type *VTy =
V->getType();
2052 if (ElemTy != AssignedType)
2065 if (CurrentType == AssignedType)
2072 " for value " +
V->getName(),
2080void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
2081 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2083 TypeValidated.insert(
I);
2086 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2087 if (PointerElemTy == ExpectedElementType ||
2093 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2095 bool FirstPtrCastOrAssignPtrType =
true;
2101 for (
auto User :
Pointer->users()) {
2104 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2105 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2106 II->getOperand(0) != Pointer)
2111 FirstPtrCastOrAssignPtrType =
false;
2112 if (
II->getOperand(1) != VMD ||
2119 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2124 if (
II->getParent() !=
I->getParent())
2127 I->setOperand(OperandToReplace,
II);
2133 if (FirstPtrCastOrAssignPtrType) {
2138 }
else if (isTodoType(Pointer)) {
2139 eraseTodoType(Pointer);
2147 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2148 std::make_pair(
I, Pointer)};
2150 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2162 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2168void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2173 replacePointerOperandWithPtrCast(
2174 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2180 Type *OpTy =
Op->getType();
2183 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2186 if (OpTy ==
Op->getType())
2187 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2188 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2193 Type *OpTy = LI->getType();
2198 Type *NewOpTy = OpTy;
2199 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2200 if (OpTy == NewOpTy)
2201 insertTodoType(Pointer);
2204 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2209 Type *OpTy =
nullptr;
2221 OpTy = GEPI->getSourceElementType();
2223 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2225 insertTodoType(Pointer);
2237 std::string DemangledName =
2241 bool HaveTypes =
false;
2259 for (User *U : CalledArg->
users()) {
2261 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2267 HaveTypes |= ElemTy !=
nullptr;
2272 if (DemangledName.empty() && !HaveTypes)
2290 Type *ExpectedType =
2292 if (!ExpectedType && !DemangledName.empty())
2293 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2294 DemangledName,
OpIdx,
I->getContext());
2295 if (!ExpectedType || ExpectedType->
isVoidTy())
2303 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2307Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &
I) {
2314 I.getOperand(1)->getType(),
2315 I.getOperand(2)->getType()};
2317 B.SetInsertPoint(&
I);
2319 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
2320 replaceAllUsesWithAndErase(
B, &
I, NewI);
2325SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &
I) {
2332 B.SetInsertPoint(&
I);
2334 I.getIndexOperand()->getType()};
2335 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2336 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
2337 replaceAllUsesWithAndErase(
B, &
I, NewI);
2341Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &
I) {
2343 B.SetInsertPoint(&
I);
2346 Value *AggregateOp =
I.getAggregateOperand();
2350 Args.push_back(AggregateOp);
2351 Args.push_back(
I.getInsertedValueOperand());
2352 for (
auto &
Op :
I.indices())
2353 Args.push_back(
B.getInt32(
Op));
2355 B.CreateIntrinsic(Intrinsic::spv_insertv, {
Types}, {
Args});
2356 replaceMemInstrUses(&
I, NewI,
B);
2360Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &
I) {
2362 B.SetInsertPoint(&
I);
2363 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2372 for (
auto &
Op :
I.indices())
2373 Args.push_back(
B.getInt32(
Op));
2375 B.CreateIntrinsic(Intrinsic::spv_extractv, {
I.getType()}, {
Args});
2376 replaceAllUsesWithAndErase(
B, &
I, NewI);
2380Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &
I) {
2381 if (!
I.getType()->isAggregateType())
2384 B.SetInsertPoint(&
I);
2385 TrackConstants =
false;
2390 unsigned IntrinsicId;
2391 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2392 if (!
I.isAtomic()) {
2393 IntrinsicId = Intrinsic::spv_load;
2394 Args.push_back(
B.getInt32(
I.getAlign().value()));
2396 IntrinsicId = Intrinsic::spv_atomic_load;
2397 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2400 B.CreateIntrinsic(IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2402 replaceMemInstrUses(&
I, NewI,
B);
2406Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &
I) {
2410 B.SetInsertPoint(&
I);
2411 TrackConstants =
false;
2415 auto *PtrOp =
I.getPointerOperand();
2417 if (
I.getValueOperand()->getType()->isAggregateType()) {
2425 "Unexpected argument of aggregate type, should be spv_extractv!");
2429 unsigned IntrinsicId;
2430 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2432 if (!
I.isAtomic()) {
2433 IntrinsicId = Intrinsic::spv_store;
2434 Args.push_back(
B.getInt32(
I.getAlign().value()));
2436 IntrinsicId = Intrinsic::spv_atomic_store;
2437 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2439 auto *NewI =
B.CreateIntrinsic(
2440 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2442 I.eraseFromParent();
2446Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &
I) {
2447 Value *ArraySize =
nullptr;
2448 if (
I.isArrayAllocation()) {
2451 SPIRV::Extension::SPV_INTEL_variable_length_array))
2453 "array allocation: this instruction requires the following "
2454 "SPIR-V extension: SPV_INTEL_variable_length_array",
2456 ArraySize =
I.getArraySize();
2459 B.SetInsertPoint(&
I);
2460 TrackConstants =
false;
2461 Type *PtrTy =
I.getType();
2464 ?
B.CreateIntrinsic(Intrinsic::spv_alloca_array,
2465 {PtrTy, ArraySize->
getType()},
2466 {ArraySize,
B.getInt32(
I.getAlign().value())})
2467 :
B.CreateIntrinsic(
Intrinsic::spv_alloca, {PtrTy},
2468 {
B.getInt32(
I.getAlign().value())});
2469 replaceAllUsesWithAndErase(
B, &
I, NewI);
2473Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2474 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2476 B.SetInsertPoint(&
I);
2478 Args.push_back(
B.getInt32(
2479 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2482 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2483 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2484 uint32_t ScSem =
static_cast<uint32_t
>(
2486 Args.push_back(
B.getInt32(
2488 Args.push_back(
B.getInt32(
2490 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
2491 {
I.getPointerOperand()->getType()}, {
Args});
2492 replaceMemInstrUses(&
I, NewI,
B);
2501 case Intrinsic::spv_abort:
2503 case Intrinsic::trap:
2504 case Intrinsic::ubsantrap:
2506 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2526 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2527 "abort-like call must be the last non-debug instruction before its "
2528 "block's terminator");
2532Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &
I) {
2533 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2537 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2546 static const StringSet<> ArtificialGlobals{
"llvm.global.annotations",
2547 "llvm.compiler.used",
"llvm.used"};
2552 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2553 if (UserFunctions.contains(
F))
2558 if (!UserFunctions.empty())
2563 const Module &M = *
F->getParent();
2564 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2565 return F == &FirstDefinition;
2568Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(
Type *AggrTy,
2570 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2571 auto *Leaf =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
2573 AggrConstTypes[Leaf] = ElemTy;
2576 SmallVector<Value *, 4> Elems;
2578 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2581 DenseMap<Type *, Instruction *> LeafByType;
2582 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2584 auto &
Entry = LeafByType[ElemTy];
2586 Entry = MakeLeaf(ElemTy);
2590 auto *Composite =
B.CreateIntrinsic(Intrinsic::spv_const_composite,
2591 {
B.getInt32Ty()}, Elems);
2593 AggrConstTypes[Composite] = AggrTy;
2597void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2608 deduceElementTypeHelper(&GV,
false);
2610 Value *InitOp = Init;
2618 B.CreateIntrinsic(Intrinsic::spv_poison, {
B.getInt32Ty()}, {});
2623 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2628 auto *InitInst =
B.CreateIntrinsic(Intrinsic::spv_init_global,
2630 InitInst->setArgOperand(1, InitOp);
2633 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2639bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *
I,
2641 bool UnknownElemTypeI8) {
2647 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2654void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *
I,
2657 static StringMap<unsigned> ResTypeWellKnown = {
2658 {
"async_work_group_copy", WellKnownTypes::Event},
2659 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2660 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2664 bool IsKnown =
false;
2669 std::string DemangledName =
2672 if (DemangledName.length() > 0)
2674 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2675 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2676 if (ResIt != ResTypeWellKnown.
end()) {
2679 switch (ResIt->second) {
2680 case WellKnownTypes::Event:
2687 switch (DecorationId) {
2690 case FPDecorationId::SAT:
2693 case FPDecorationId::RTE:
2695 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2697 case FPDecorationId::RTZ:
2699 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2701 case FPDecorationId::RTP:
2703 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2705 case FPDecorationId::RTN:
2707 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2713 Type *Ty =
I->getType();
2716 Type *TypeToAssign = Ty;
2719 auto It = AggrConstTypes.
find(
II);
2720 if (It == AggrConstTypes.
end())
2722 TypeToAssign = It->second;
2723 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2724 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2725 TypeToAssign = It->second;
2727 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2728 TypeToAssign = It->second;
2732 for (
const auto &
Op :
I->operands()) {
2739 Type *OpTy =
Op->getType();
2741 CallInst *AssignCI =
2746 Type *OpTy =
Op->getType();
2761 CallInst *AssignCI =
2771bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2772 Instruction *Inst) {
2774 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2784void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *
I,
2786 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2788 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2793 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2794 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2795 if (shouldTryToAddMemAliasingDecoration(
I)) {
2796 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2797 ? SPIRV::Decoration::AliasScopeINTEL
2798 : SPIRV::Decoration::NoAliasINTEL;
2800 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2803 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2804 {
I->getType()}, {
Args});
2808 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2809 processMemAliasingDecoration(LLVMContext::MD_noalias);
2812 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2814 bool AllowFPMaxError =
2816 if (!AllowFPMaxError)
2820 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2824 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
2828 auto &Ctx =
B.getContext();
2830 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
2833 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
2835 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
2836 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
2839 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
2841 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
2843 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2851 &FPFastMathDefaultInfoMap,
2853 auto it = FPFastMathDefaultInfoMap.
find(
F);
2854 if (it != FPFastMathDefaultInfoMap.
end())
2862 SPIRV::FPFastMathMode::None);
2864 SPIRV::FPFastMathMode::None);
2866 SPIRV::FPFastMathMode::None);
2867 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
2873 size_t BitWidth = Ty->getScalarSizeInBits();
2877 assert(Index >= 0 && Index < 3 &&
2878 "Expected FPFastMathDefaultInfo for half, float, or double");
2879 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2880 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2881 return FPFastMathDefaultInfoVec[Index];
2884void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(
Module &M) {
2886 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2895 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
2897 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
2905 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
2908 [[maybe_unused]] GlobalVariable *GV =
2909 new GlobalVariable(M,
2910 Type::getInt32Ty(
M.getContext()),
2924 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
2925 FPFastMathDefaultInfoMap;
2927 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
2936 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2938 "Expected 4 operands for FPFastMathDefault");
2944 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2946 SPIRV::FPFastMathDefaultInfo &
Info =
2949 Info.FPFastMathDefault =
true;
2950 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
2952 "Expected no operands for ContractionOff");
2956 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2958 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2959 Info.ContractionOff =
true;
2961 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
2963 "Expected 1 operand for SignedZeroInfNanPreserve");
2964 unsigned TargetWidth =
2969 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2973 assert(Index >= 0 && Index < 3 &&
2974 "Expected FPFastMathDefaultInfo for half, float, or double");
2975 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2976 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2977 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
2981 std::unordered_map<unsigned, GlobalVariable *> GlobalVars;
2982 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
2983 if (FPFastMathDefaultInfoVec.
empty())
2986 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2987 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
2990 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
2991 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
2995 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
2997 "and AllowContract");
2999 if (
Info.SignedZeroInfNanPreserve &&
3001 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3002 SPIRV::FPFastMathMode::NSZ))) {
3003 if (
Info.FPFastMathDefault)
3005 "SignedZeroInfNanPreserve but at least one of "
3006 "NotNaN/NotInf/NSZ is enabled.");
3009 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3010 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3011 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3013 "AllowTransform requires AllowReassoc and "
3014 "AllowContract to be set.");
3017 auto it = GlobalVars.find(Flags);
3018 GlobalVariable *GV =
nullptr;
3019 if (it != GlobalVars.end()) {
3025 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3028 GV =
new GlobalVariable(M,
3029 Type::getInt32Ty(
M.getContext()),
3034 GlobalVars[
Flags] = GV;
3040void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *
I,
3043 bool IsConstComposite =
3044 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3045 if (IsConstComposite && TrackConstants) {
3047 auto t = AggrConsts.
find(
I);
3051 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3053 NewOp->setArgOperand(0,
I);
3056 for (
const auto &
Op :
I->operands()) {
3060 unsigned OpNo =
Op.getOperandNo();
3061 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3062 (!
II->isBundleOperand(OpNo) &&
3063 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3067 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3068 :
B.SetInsertPoint(
I);
3071 Type *OpTy =
Op->getType();
3079 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3081 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3082 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3084 SmallVector<Value *, 2>
Args = {
3087 CallInst *PtrCasted =
3088 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
3093 I->setOperand(OpNo, NewOp);
3095 if (Named.insert(
I).second)
3099Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *
F,
3101 std::unordered_set<Function *> FVisited;
3102 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3105Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
3106 Function *
F,
unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
3108 if (!FVisited.insert(
F).second)
3111 std::unordered_set<Value *> Visited;
3114 for (User *U :
F->users()) {
3126 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3129 for (User *OpU : OpArg->
users()) {
3131 if (!Inst || Inst == CI)
3134 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3141 if (FVisited.find(OuterF) != FVisited.end())
3143 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3144 if (OuterF->
getArg(i) == OpArg) {
3145 Lookup.push_back(std::make_pair(OuterF, i));
3152 for (
auto &Pair :
Lookup) {
3153 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3160void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *
F,
3162 B.SetInsertPointPastAllocas(
F);
3169 for (User *U : Arg->
users()) {
3171 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3189 for (User *U :
F->users()) {
3205 for (User *U : Arg->
users()) {
3209 CI->
getParent()->getParent() == CurrF) {
3211 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3222void SPIRVEmitIntrinsics::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3223 B.SetInsertPointPastAllocas(
F);
3229 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3231 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3233 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3245 bool IsNewFTy =
false;
3261bool SPIRVEmitIntrinsics::processFunctionPointers(
Module &M) {
3264 if (
F.isIntrinsic())
3266 if (
F.isDeclaration()) {
3267 for (User *U :
F.users()) {
3280 for (User *U :
F.users()) {
3282 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3284 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3285 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3292 if (Worklist.
empty())
3295 LLVMContext &Ctx =
M.getContext();
3300 for (Function *
F : Worklist) {
3302 for (
const auto &Arg :
F->args())
3304 IRB.CreateCall(
F, Args);
3306 IRB.CreateRetVoid();
3312void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3313 DenseMap<Function *, CallInst *> Ptrcasts;
3314 for (
auto It : FDeclPtrTys) {
3316 for (
auto *U :
F->users()) {
3321 for (
auto [Idx, ElemTy] : It.second) {
3329 B.SetInsertPointPastAllocas(Arg->
getParent());
3333 }
else if (isaGEP(Param)) {
3334 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3343 .getFirstNonPHIOrDbgOrAlloca());
3364SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP) {
3371 Type *SrcTy =
GEP->getSourceElementType();
3372 SmallVector<Value *, 8> Indices(
GEP->indices());
3374 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3375 Indices.erase(Indices.begin());
3376 SrcTy = ArrTy->getElementType();
3378 GEP->getNoWrapFlags(),
"",
3379 GEP->getIterator());
3384void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &
F,
3391 if (
ST->canUseExtension(
3392 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3393 for (BasicBlock &BB :
F) {
3395 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3399 SmallVector<unsigned, 1>
Ops =
3401 unsigned LC =
Ops[0];
3402 if (LC == SPIRV::LoopControl::None)
3406 B.SetInsertPoint(Term);
3407 SmallVector<Value *, 4> IntrArgs;
3408 for (
unsigned Op :
Ops)
3410 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3417 DominatorTree DT(
F);
3422 for (Loop *L : LI.getLoopsInPreorder()) {
3431 SmallVector<unsigned, 1> LoopControlOps =
3433 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3437 B.SetInsertPoint(Header->getTerminator());
3440 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3441 for (
unsigned Imm : LoopControlOps)
3442 Args.emplace_back(
B.getInt32(Imm));
3443 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3447bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3448 if (
Func.isDeclaration())
3452 GR =
ST.getSPIRVGlobalRegistry();
3456 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3461 AggrConstTypes.
clear();
3464 processParamTypesByFunHeader(CurrF,
B);
3468 SmallPtrSet<Instruction *, 4> DeadInsts;
3473 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3477 GR->addDeducedElementType(SGEP,
3482 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3484 GEP->replaceAllUsesWith(NewGEP);
3488 if (
Type *GepTy = getGEPType(
GEP))
3492 for (
auto *
I : DeadInsts) {
3493 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3494 I->eraseFromParent();
3504 Type *ElTy =
SI->getValueOperand()->getType();
3509 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3510 for (
auto &GV :
Func.getParent()->globals())
3511 processGlobalValue(GV,
B);
3513 preprocessUndefs(
B);
3514 preprocessPoisons(
B);
3515 simplifyNullAddrSpaceCasts();
3516 preprocessCompositeConstants(
B);
3524 Type *I32Ty =
B.getInt32Ty();
3528 if (!
I.getType()->isAggregateType())
3530 AggrConstTypes[&
I] =
I.getType();
3531 I.mutateType(I32Ty);
3534 preprocessBoolVectorBitcasts(Func);
3538 applyDemangledPtrArgTypes(
B);
3541 for (
auto &
I : Worklist) {
3543 if (isConvergenceIntrinsic(
I))
3546 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3548 insertAssignTypeIntrs(
I,
B);
3549 insertPtrCastOrAssignTypeInstr(
I,
B);
3553 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3554 insertAssignPtrTypeIntrs(
I,
B,
true);
3557 useRoundingMode(FPI,
B);
3562 SmallPtrSet<Instruction *, 4> IncompleteRets;
3564 deduceOperandElementType(&
I, &IncompleteRets);
3568 for (BasicBlock &BB : Func)
3569 for (PHINode &Phi : BB.
phis())
3571 deduceOperandElementType(&Phi,
nullptr);
3573 for (
auto *
I : Worklist) {
3574 TrackConstants =
true;
3584 if (isConvergenceIntrinsic(
I))
3588 processInstrAfterVisit(
I,
B);
3591 emitUnstructuredLoopControls(Func,
B);
3597bool SPIRVEmitIntrinsics::postprocessTypes(
Module &M) {
3598 if (!GR || TodoTypeSz == 0)
3601 unsigned SzTodo = TodoTypeSz;
3602 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3607 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3608 Type *KnownTy = GR->findDeducedElementType(
Op);
3609 if (!KnownTy || !AssignCI)
3615 std::unordered_set<Value *> Visited;
3616 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3617 if (ElemTy != KnownTy) {
3618 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3619 propagateElemType(CI, ElemTy, VisitedSubst);
3626 if (
Op->hasUseList()) {
3627 for (User *U :
Op->users()) {
3634 if (TodoTypeSz == 0)
3639 SmallPtrSet<Instruction *, 4> IncompleteRets;
3641 auto It = ToProcess.
find(&
I);
3642 if (It == ToProcess.
end())
3644 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3645 if (It->second.size() == 0)
3647 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3648 if (TodoTypeSz == 0)
3653 return SzTodo > TodoTypeSz;
3657void SPIRVEmitIntrinsics::parseFunDeclarations(
Module &M) {
3659 if (!
F.isDeclaration() ||
F.isIntrinsic())
3663 if (DemangledName.empty())
3667 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3668 DemangledName,
ST.getPreferredInstructionSet());
3669 if (Opcode != SPIRV::OpGroupAsyncCopy)
3672 SmallVector<unsigned> Idxs;
3681 LLVMContext &Ctx =
F.getContext();
3683 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3684 if (!TypeStrs.
size())
3687 for (
unsigned Idx : Idxs) {
3688 if (Idx >= TypeStrs.
size())
3691 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3694 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3699bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3700 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3702 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3703 if (!
ST.canUseExtension(
3704 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3705 I.getContext().emitError(
3706 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3710 I.eraseFromParent();
3716 Value *Ptrs =
I.getArgOperand(0);
3718 Value *Passthru =
I.getArgOperand(2);
3721 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3723 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3728 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3730 I.eraseFromParent();
3734 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3735 if (!
ST.canUseExtension(
3736 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3737 I.getContext().emitError(
3738 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3741 I.eraseFromParent();
3747 Value *Values =
I.getArgOperand(0);
3748 Value *Ptrs =
I.getArgOperand(1);
3753 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3755 SmallVector<Value *, 4>
Args = {Values, Ptrs,
B.getInt32(Alignment),
Mask};
3759 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3760 I.eraseFromParent();
3771void SPIRVEmitIntrinsics::preprocessBoolVectorBitcasts(Function &
F) {
3772 struct BoolVecBitcast {
3774 FixedVectorType *BoolVecTy;
3778 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3780 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3788 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3790 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3794 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3796 Value *Src = BC->getOperand(0);
3797 unsigned BoolVecN = BoolVecTy->getNumElements();
3799 Type *IntTy =
B.getIntNTy(BoolVecN);
3805 IntVal = ConstantInt::get(IntTy, 0);
3806 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3807 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3808 Value *Ext =
B.CreateZExt(Elem, IntTy);
3810 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3811 IntVal =
B.CreateOr(IntVal, Ext);
3817 if (!Src->getType()->isIntegerTy())
3818 IntVal =
B.CreateBitCast(Src, IntTy);
3823 if (!SrcIsBoolVec) {
3826 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3829 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
3830 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
3836 if (!BC->getDestTy()->isIntegerTy())
3837 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
3840 BC->replaceAllUsesWith(Result);
3841 BC->eraseFromParent();
3845bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(
Module &M) {
3849 if (!
F.isIntrinsic())
3852 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
3857 Changed |= processMaskedMemIntrinsic(*
II);
3861 F.eraseFromParent();
3867bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
3870 Changed |= convertMaskedMemIntrinsics(M);
3872 parseFunDeclarations(M);
3873 insertConstantsForFPFastMathDefault(M);
3884 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
3886 processParamTypes(&
F,
B);
3890 CanTodoType =
false;
3891 Changed |= postprocessTypes(M);
3894 Changed |= processFunctionPointers(M);
3901 SPIRVEmitIntrinsics Legacy(TM);
3902 if (Legacy.runOnModule(M))
3908 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 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 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 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 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)
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
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 arg_size() 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
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
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.
StringSet - A wrapper for StringMap that provides set-like functionality.
bool contains(StringRef key) const
Check if the set contains the given key.
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()
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.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
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)
@ 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)