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)
552 V = V->stripPointerCasts();
573Type *SPIRVEmitIntrinsics::reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
574 bool IsPostprocessing) {
578 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
592 if (UnknownElemTypeI8) {
593 if (!IsPostprocessing)
601CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *
F,
Value *
Op,
609 B.SetInsertPointPastAllocas(OpA->getParent());
612 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
614 Type *OpTy =
Op->getType();
618 CallInst *PtrCasted =
619 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
624void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
626 DenseMap<Function *, CallInst *> Ptrcasts) {
628 CallInst *PtrCastedI =
nullptr;
629 auto It = Ptrcasts.
find(
F);
630 if (It == Ptrcasts.
end()) {
631 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
632 Ptrcasts[
F] = PtrCastedI;
634 PtrCastedI = It->second;
636 I->replaceUsesOfWith(
Op, PtrCastedI);
639void SPIRVEmitIntrinsics::propagateElemType(
641 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
642 DenseMap<Function *, CallInst *> Ptrcasts;
644 for (
auto *U :
Users) {
647 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
652 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
653 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
657void SPIRVEmitIntrinsics::propagateElemTypeRec(
659 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
660 std::unordered_set<Value *> Visited;
661 DenseMap<Function *, CallInst *> Ptrcasts;
662 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
663 std::move(Ptrcasts));
666void SPIRVEmitIntrinsics::propagateElemTypeRec(
668 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
669 std::unordered_set<Value *> &Visited,
670 DenseMap<Function *, CallInst *> Ptrcasts) {
671 if (!Visited.insert(
Op).second)
674 for (
auto *U :
Users) {
677 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
682 if (isaGEP(UI) || TypeValidated.find(UI) != TypeValidated.end())
683 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
691SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
692 bool UnknownElemTypeI8) {
693 std::unordered_set<Value *> Visited;
694 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
698Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
699 Type *ValueTy,
Value *Operand, std::unordered_set<Value *> &Visited,
700 bool UnknownElemTypeI8) {
705 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
716Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
717 Value *
Op, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8) {
729 for (User *OpU :
Op->users()) {
731 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
744 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
753Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I,
754 bool UnknownElemTypeI8) {
755 std::unordered_set<Value *> Visited;
756 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
759void SPIRVEmitIntrinsics::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
Type *RefTy,
760 bool UnknownElemTypeI8) {
762 if (!UnknownElemTypeI8)
771bool SPIRVEmitIntrinsics::walkLogicalAccessChainDynamic(
772 Type *CurType,
Value *Operand, uint64_t Multiplier,
773 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
774 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
780 if (
ST->getNumElements() == 0)
782 CurType =
ST->getElementType(0);
783 OnLiteralIndexing(CurType, 0);
791 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
792 return AT ==
nullptr;
795bool SPIRVEmitIntrinsics::walkLogicalAccessChainConstant(
797 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
802 uint32_t EltTypeSize =
DL.getTypeSizeInBits(AT->getElementType()) / 8;
806 CurType = AT->getElementType();
807 OnLiteralIndexing(CurType, Index);
809 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
812 const auto &STL =
DL.getStructLayout(ST);
813 unsigned Element = STL->getElementContainingOffset(
Offset);
814 Offset -= STL->getElementOffset(Element);
815 CurType =
ST->getElementType(Element);
816 OnLiteralIndexing(CurType, Element);
818 Type *EltTy = VT->getElementType();
819 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
820 assert(EltSizeBits % 8 == 0 &&
821 "Element type size in bits must be a multiple of 8.");
822 uint32_t EltTypeSize = EltSizeBits / 8;
827 OnLiteralIndexing(CurType, Index);
837bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
838 GetElementPtrInst &
GEP,
839 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
840 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
843 std::optional<uint64_t> MultiplierOpt =
844 getByteAddressingMultiplier(
GEP.getSourceElementType());
845 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
846 uint64_t Multiplier = *MultiplierOpt;
849 Value *Src = getPointerRoot(
GEP.getPointerOperand());
850 Type *CurType = deduceElementType(Src,
true);
854 return walkLogicalAccessChainConstant(
855 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
857 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
858 OnLiteralIndexing, OnDynamicIndexing);
862SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP) {
865 B.SetInsertPoint(&
GEP);
867 std::vector<Value *> Indices;
868 Indices.push_back(ConstantInt::get(
869 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
870 walkLogicalAccessChain(
872 [&Indices, &
B](
Type *EltType, uint64_t Index) {
874 ConstantInt::get(
B.getInt64Ty(), Index,
false));
877 uint64_t Multiplier) {
879 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
881 if (Multiplier == EltTypeSize) {
883 }
else if (EltTypeSize % Multiplier == 0) {
886 EltTypeSize / Multiplier,
890 ConstantInt::get(
Offset->getType(), Multiplier,
893 Index =
B.CreateUDiv(Index,
894 ConstantInt::get(
Offset->getType(), EltTypeSize,
898 Indices.push_back(Index);
902 SmallVector<Value *, 4>
Args;
903 Args.push_back(
B.getInt1(
GEP.isInBounds()));
904 Args.push_back(
GEP.getOperand(0));
906 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
907 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
911Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *
GEP) {
913 Type *CurType =
GEP->getResultElementType();
915 bool Interrupted = walkLogicalAccessChain(
916 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
917 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
919 return Interrupted ?
GEP->getResultElementType() : CurType;
922Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *
Ref) {
923 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
925 return getGEPTypeLogical(
Ref);
932 Ty =
Ref->getSourceElementType();
936 Ty =
Ref->getResultElementType();
941Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
942 Value *
I, std::unordered_set<Value *> &Visited,
bool UnknownElemTypeI8,
943 bool IgnoreKnownType) {
949 if (!IgnoreKnownType)
954 if (!Visited.insert(
I).second)
961 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
963 Ty = getGEPType(
Ref);
965 Ty = SGEP->getResultElementType();
970 KnownTy =
Op->getType();
972 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
975 Ty = SPIRV::getOriginalFunctionType(*Fn);
978 Ty = deduceElementTypeByValueDeep(
980 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
984 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
986 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
988 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
990 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
992 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
997 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1001 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1003 Type *BestTy =
nullptr;
1005 DenseMap<Type *, unsigned> PhiTys;
1006 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1007 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1014 if (It.first->second > MaxN) {
1015 MaxN = It.first->second;
1023 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1024 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1029 static StringMap<unsigned> ResTypeByArg = {
1033 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1034 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1035 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1036 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1037 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1038 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1042 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1043 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1045 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1046 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1047 for (User *U :
II->users()) {
1052 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1054 Ty = HandleType->getTypeParameter(0);
1055 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1069 }
else if (
II &&
II->getIntrinsicID() ==
1070 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1074 std::string DemangledName =
1076 if (DemangledName.length() > 0)
1077 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1078 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1079 if (AsArgIt != ResTypeByArg.
end())
1080 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1081 Visited, UnknownElemTypeI8);
1088 if (Ty && !IgnoreKnownType) {
1099Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1100 bool UnknownElemTypeI8) {
1101 std::unordered_set<Value *> Visited;
1102 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1105Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
1106 User *U,
Type *OrigTy, std::unordered_set<Value *> &Visited,
1107 bool UnknownElemTypeI8) {
1116 if (!Visited.insert(U).second)
1121 bool Change =
false;
1122 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1124 assert(
Op &&
"Operands should not be null.");
1125 Type *OpTy =
Op->getType();
1128 if (
Type *NestedTy =
1129 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1136 Change |= Ty != OpTy;
1144 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1145 Type *OpTy = ArrTy->getElementType();
1148 if (
Type *NestedTy =
1149 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1156 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1162 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1163 Type *OpTy = VecTy->getElementType();
1166 if (
Type *NestedTy =
1167 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1174 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1184Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I,
bool UnknownElemTypeI8) {
1185 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1187 if (!UnknownElemTypeI8)
1190 return IntegerType::getInt8Ty(
I->getContext());
1194 Value *PointerOperand) {
1200 return I->getType();
1208bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1210 Type *&KnownElemTy,
bool &Incomplete) {
1214 std::string DemangledName =
1216 if (DemangledName.length() > 0 &&
1218 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1219 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1220 DemangledName,
ST.getPreferredInstructionSet());
1221 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1222 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1228 KnownElemTy = ElemTy;
1229 Ops.push_back(std::make_pair(
Op, i));
1231 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1238 case SPIRV::OpAtomicFAddEXT:
1239 case SPIRV::OpAtomicFMinEXT:
1240 case SPIRV::OpAtomicFMaxEXT:
1241 case SPIRV::OpAtomicLoad:
1242 case SPIRV::OpAtomicCompareExchangeWeak:
1243 case SPIRV::OpAtomicCompareExchange:
1244 case SPIRV::OpAtomicExchange:
1245 case SPIRV::OpAtomicIAdd:
1246 case SPIRV::OpAtomicISub:
1247 case SPIRV::OpAtomicOr:
1248 case SPIRV::OpAtomicXor:
1249 case SPIRV::OpAtomicAnd:
1250 case SPIRV::OpAtomicUMin:
1251 case SPIRV::OpAtomicUMax:
1252 case SPIRV::OpAtomicSMin:
1253 case SPIRV::OpAtomicSMax: {
1258 Incomplete = isTodoType(
Op);
1259 Ops.push_back(std::make_pair(
Op, 0));
1261 case SPIRV::OpAtomicStore: {
1270 Incomplete = isTodoType(
Op);
1271 Ops.push_back(std::make_pair(
Op, 0));
1280void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1282 Type *&KnownElemTy,
bool IsPostprocessing) {
1286 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1287 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1288 bool IsNewFTy =
false, IsIncomplete =
false;
1291 Type *ArgTy = Arg->getType();
1296 if (isTodoType(Arg))
1297 IsIncomplete =
true;
1299 IsIncomplete =
true;
1302 ArgTy = FTy->getFunctionParamType(ParmIdx);
1306 Type *RetTy = FTy->getReturnType();
1313 IsIncomplete =
true;
1315 IsIncomplete =
true;
1318 if (!IsPostprocessing && IsIncomplete)
1321 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1324bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1325 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1326 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing,
1338 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1339 for (User *U :
F->users()) {
1347 propagateElemType(CI, PrevElemTy, VisitedSubst);
1357 for (Instruction *IncompleteRetI : *IncompleteRets)
1358 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1360 }
else if (IncompleteRets) {
1363 TypeValidated.insert(
I);
1371void SPIRVEmitIntrinsics::deduceOperandElementType(
1372 Instruction *
I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
1373 const SmallPtrSet<Value *, 4> *AskOps,
bool IsPostprocessing) {
1375 Type *KnownElemTy =
nullptr;
1376 bool Incomplete =
false;
1382 Incomplete = isTodoType(
I);
1383 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1386 Ops.push_back(std::make_pair(
Op, i));
1392 Incomplete = isTodoType(
I);
1393 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1400 Incomplete = isTodoType(
I);
1401 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1405 KnownElemTy =
Ref->getSourceElementType();
1406 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1411 KnownElemTy =
Ref->getBaseType();
1412 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1415 KnownElemTy =
I->getType();
1422 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1431 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1435 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1440 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1448 Incomplete = isTodoType(
Ref->getPointerOperand());
1449 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1457 Incomplete = isTodoType(
Ref->getPointerOperand());
1458 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1464 Incomplete = isTodoType(
I);
1465 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1468 Ops.push_back(std::make_pair(
Op, i));
1476 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1477 IsPostprocessing, KnownElemTy,
Op,
1480 Incomplete = isTodoType(CurrF);
1481 Ops.push_back(std::make_pair(
Op, 0));
1487 bool Incomplete0 = isTodoType(Op0);
1488 bool Incomplete1 = isTodoType(Op1);
1490 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1492 : GR->findDeducedElementType(Op0);
1494 KnownElemTy = ElemTy0;
1495 Incomplete = Incomplete0;
1496 Ops.push_back(std::make_pair(Op1, 1));
1497 }
else if (ElemTy1) {
1498 KnownElemTy = ElemTy1;
1499 Incomplete = Incomplete1;
1500 Ops.push_back(std::make_pair(Op0, 0));
1504 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1505 else if (HaveFunPtrs)
1506 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1511 if (!KnownElemTy ||
Ops.size() == 0)
1516 for (
auto &OpIt :
Ops) {
1520 Type *AskTy =
nullptr;
1521 CallInst *AskCI =
nullptr;
1522 if (IsPostprocessing && AskOps) {
1528 if (Ty == KnownElemTy)
1531 Type *OpTy =
Op->getType();
1537 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1544 else if (!IsPostprocessing)
1548 if (AssignCI ==
nullptr) {
1557 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1558 std::make_pair(
I,
Op)};
1559 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1563 CallInst *PtrCastI =
1564 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1565 if (OpIt.second == std::numeric_limits<unsigned>::max())
1568 I->setOperand(OpIt.second, PtrCastI);
1571 TypeValidated.insert(
I);
1574void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1579 if (isAssignTypeInstr(U)) {
1580 B.SetInsertPoint(U);
1581 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1582 CallInst *AssignCI =
1583 B.CreateIntrinsic(Intrinsic::spv_assign_type, {
New->getType()},
Args);
1585 U->eraseFromParent();
1588 U->replaceUsesOfWith(Old, New);
1596 Type *NewArgTy =
New->getType();
1598 if (NewArgTy != ExpectedArgTy) {
1601 M, Intrinsic::spv_abort, {NewArgTy});
1611 "aggregate PHI/select/freeze should have been mutated to value-id "
1613 U->replaceUsesOfWith(Old, New);
1618 New->copyMetadata(*Old);
1622void SPIRVEmitIntrinsics::preprocessUndefs(
IRBuilder<> &
B) {
1626 SmallVector<Instruction *, 16> Insts;
1630 for (Instruction *
I : Insts) {
1631 bool BPrepared =
false;
1632 for (
auto &
Op :
I->operands()) {
1634 if (!AggrUndef || !
Op->getType()->isAggregateType())
1639 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1640 "lowered as undef\n");
1646 auto *IntrUndef =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
1647 I->replaceUsesOfWith(
Op, IntrUndef);
1648 AggrConsts[IntrUndef] = AggrUndef;
1649 AggrConstTypes[IntrUndef] = AggrUndef->getType();
1654void SPIRVEmitIntrinsics::preprocessPoisons(
IRBuilder<> &
B) {
1660 bool BPrepared =
false;
1663 for (
unsigned Idx = 0; Idx <
I.getNumOperands(); ++Idx) {
1666 if (!
Poison ||
Op->getType()->isMetadataTy())
1669 Type *OpTy =
Op->getType();
1670 Value *Replacement =
nullptr;
1677 B.CreateIntrinsic(Intrinsic::spv_poison, {
B.getInt32Ty()}, {});
1679 AggrConstTypes[
Call] = OpTy;
1683 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1684 else if (!BPrepared) {
1688 Replacement =
B.CreateIntrinsic(Intrinsic::spv_poison, {OpTy}, {});
1690 I.setOperand(Idx, Replacement);
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 &&
1763 Type *PoisonTy =
Op->getType();
1765 auto *
Call =
B.CreateIntrinsic(Intrinsic::spv_poison,
1766 {
B.getInt32Ty()}, {});
1768 AggrConstTypes[
Call] = PoisonTy;
1771 Op =
B.CreateIntrinsic(Intrinsic::spv_poison, {PoisonTy}, {});
1778 B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {
Args});
1782 AggrConsts[CI] = AggrConst;
1783 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1795 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1800 unsigned RoundingModeDeco,
1807 ConstantInt::get(
Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1816 MDNode *SaturatedConversionNode =
1818 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1838 MDString *ConstraintString =
1847 B.SetInsertPoint(&
Call);
1848 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1853void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1856 if (!
RM.has_value())
1858 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1859 switch (
RM.value()) {
1863 case RoundingMode::NearestTiesToEven:
1864 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1866 case RoundingMode::TowardNegative:
1867 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1869 case RoundingMode::TowardPositive:
1870 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1872 case RoundingMode::TowardZero:
1873 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1875 case RoundingMode::Dynamic:
1876 case RoundingMode::NearestTiesToAway:
1880 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1886Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &
I) {
1890 B.SetInsertPoint(&
I);
1891 SmallVector<Value *, 4>
Args;
1893 Args.push_back(
I.getCondition());
1896 for (
auto &Case :
I.cases()) {
1897 Args.push_back(Case.getCaseValue());
1898 BBCases.
push_back(Case.getCaseSuccessor());
1901 CallInst *NewI =
B.CreateIntrinsic(Intrinsic::spv_switch,
1902 {
I.getOperand(0)->getType()}, {
Args});
1906 I.eraseFromParent();
1909 B.SetInsertPoint(ParentBB);
1910 IndirectBrInst *BrI =
B.CreateIndirectBr(
1913 for (BasicBlock *BBCase : BBCases)
1922Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &
I) {
1928 B.SetInsertPoint(&
I);
1930 SmallVector<Value *, 4>
Args;
1931 Args.push_back(
B.getInt1(
true));
1932 Args.push_back(
I.getOperand(0));
1933 Args.push_back(
B.getInt32(0));
1934 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1935 Args.push_back(SGEP->getIndexOperand(J));
1937 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, Types, Args);
1938 replaceAllUsesWithAndErase(
B, &
I, NewI);
1942Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &
I) {
1944 B.SetInsertPoint(&
I);
1949 unsigned N = RetVTy->getNumElements();
1950 Value *PtrOp =
I.getPointerOperand();
1952 Type *ResultPtrTy = RetVTy->getElementType();
1955 Value *InBounds =
B.getInt1(
I.isInBounds());
1956 Type *LanePointeeTy = getGEPType(&
I);
1957 Type *SrcElemTy =
I.getSourceElementType();
1966 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
1967 Value *LaneIdx =
B.getInt32(Lane);
1968 Value *ScalarPtr = PtrOp;
1972 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
1976 SmallVector<Value *, 4>
Args;
1977 Args.push_back(InBounds);
1978 Args.push_back(ScalarPtr);
1979 for (
Value *Idx :
I.indices()) {
1981 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
1983 Args.push_back(Idx);
1985 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
1987 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
1991 replaceAllUsesWithAndErase(
B, &
I, NewI);
2009 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2010 return buildLogicalAccessChainFromGEP(
I);
2015 Value *PtrOp =
I.getPointerOperand();
2016 Type *SrcElemTy =
I.getSourceElementType();
2017 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2020 if (ArrTy->getElementType() == SrcElemTy) {
2022 Type *FirstIdxType =
I.getOperand(1)->getType();
2023 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2024 for (
Value *Idx :
I.indices())
2028 SmallVector<Value *, 4>
Args;
2029 Args.push_back(
B.getInt1(
I.isInBounds()));
2030 Args.push_back(
I.getPointerOperand());
2033 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
2034 replaceAllUsesWithAndErase(
B, &
I, NewI);
2041 SmallVector<Value *, 4>
Args;
2042 Args.push_back(
B.getInt1(
I.isInBounds()));
2044 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
2045 replaceAllUsesWithAndErase(
B, &
I, NewI);
2049Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &
I) {
2051 B.SetInsertPoint(&
I);
2060 I.eraseFromParent();
2066 auto *NewI =
B.CreateIntrinsic(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,
2109 TypeValidated.insert(
I);
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 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
2355 replaceAllUsesWithAndErase(
B, &
I, NewI);
2360SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &
I) {
2367 B.SetInsertPoint(&
I);
2369 I.getIndexOperand()->getType()};
2370 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2371 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
2372 replaceAllUsesWithAndErase(
B, &
I, NewI);
2376Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &
I) {
2378 B.SetInsertPoint(&
I);
2381 Value *AggregateOp =
I.getAggregateOperand();
2385 Args.push_back(AggregateOp);
2386 Args.push_back(
I.getInsertedValueOperand());
2387 for (
auto &
Op :
I.indices())
2388 Args.push_back(
B.getInt32(
Op));
2390 B.CreateIntrinsic(Intrinsic::spv_insertv, {
Types}, {
Args});
2391 replaceMemInstrUses(&
I, NewI,
B);
2395Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &
I) {
2397 B.SetInsertPoint(&
I);
2398 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2407 for (
auto &
Op :
I.indices())
2408 Args.push_back(
B.getInt32(
Op));
2410 B.CreateIntrinsic(Intrinsic::spv_extractv, {
I.getType()}, {
Args});
2411 replaceAllUsesWithAndErase(
B, &
I, NewI);
2415Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &
I) {
2416 if (!
I.getType()->isAggregateType())
2419 B.SetInsertPoint(&
I);
2420 TrackConstants =
false;
2425 unsigned IntrinsicId;
2426 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2427 if (!
I.isAtomic()) {
2428 IntrinsicId = Intrinsic::spv_load;
2429 Args.push_back(
B.getInt32(
I.getAlign().value()));
2431 IntrinsicId = Intrinsic::spv_atomic_load;
2432 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2435 B.CreateIntrinsic(IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2437 replaceMemInstrUses(&
I, NewI,
B);
2441Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &
I) {
2445 B.SetInsertPoint(&
I);
2446 TrackConstants =
false;
2450 auto *PtrOp =
I.getPointerOperand();
2452 if (
I.getValueOperand()->getType()->isAggregateType()) {
2460 "Unexpected argument of aggregate type, should be spv_extractv!");
2464 unsigned IntrinsicId;
2465 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2467 if (!
I.isAtomic()) {
2468 IntrinsicId = Intrinsic::spv_store;
2469 Args.push_back(
B.getInt32(
I.getAlign().value()));
2471 IntrinsicId = Intrinsic::spv_atomic_store;
2472 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2474 auto *NewI =
B.CreateIntrinsic(
2475 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2477 I.eraseFromParent();
2481Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &
I) {
2482 Value *ArraySize =
nullptr;
2483 if (
I.isArrayAllocation()) {
2486 SPIRV::Extension::SPV_INTEL_variable_length_array))
2488 "array allocation: this instruction requires the following "
2489 "SPIR-V extension: SPV_INTEL_variable_length_array",
2491 ArraySize =
I.getArraySize();
2494 B.SetInsertPoint(&
I);
2495 TrackConstants =
false;
2496 Type *PtrTy =
I.getType();
2499 ?
B.CreateIntrinsic(Intrinsic::spv_alloca_array,
2500 {PtrTy, ArraySize->
getType()},
2501 {ArraySize,
B.getInt32(
I.getAlign().value())})
2502 :
B.CreateIntrinsic(
Intrinsic::spv_alloca, {PtrTy},
2503 {
B.getInt32(
I.getAlign().value())});
2504 replaceAllUsesWithAndErase(
B, &
I, NewI);
2508Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2509 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2511 B.SetInsertPoint(&
I);
2513 Args.push_back(
B.getInt32(
2514 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2517 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2518 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2519 uint32_t ScSem =
static_cast<uint32_t
>(
2521 Args.push_back(
B.getInt32(
2523 Args.push_back(
B.getInt32(
2525 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_cmpxchg,
2526 {
I.getPointerOperand()->getType()}, {
Args});
2527 replaceMemInstrUses(&
I, NewI,
B);
2536 case Intrinsic::spv_abort:
2538 case Intrinsic::trap:
2539 case Intrinsic::ubsantrap:
2541 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2561 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2562 "abort-like call must be the last non-debug instruction before its "
2563 "block's terminator");
2567Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &
I) {
2568 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2572 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2581 static const StringSet<> ArtificialGlobals{
"llvm.global.annotations",
2582 "llvm.compiler.used",
"llvm.used"};
2587 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2588 if (UserFunctions.contains(
F))
2593 if (!UserFunctions.empty())
2598 const Module &M = *
F->getParent();
2599 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2600 return F == &FirstDefinition;
2603Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(
Type *AggrTy,
2605 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2606 auto *Leaf =
B.CreateIntrinsic(Intrinsic::spv_undef, {});
2608 AggrConstTypes[Leaf] = ElemTy;
2611 SmallVector<Value *, 4> Elems;
2613 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2616 DenseMap<Type *, Instruction *> LeafByType;
2617 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2619 auto &
Entry = LeafByType[ElemTy];
2621 Entry = MakeLeaf(ElemTy);
2625 auto *Composite =
B.CreateIntrinsic(Intrinsic::spv_const_composite,
2626 {
B.getInt32Ty()}, Elems);
2628 AggrConstTypes[Composite] = AggrTy;
2632void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2643 deduceElementTypeHelper(&GV,
false);
2645 Value *InitOp = Init;
2653 B.CreateIntrinsic(Intrinsic::spv_poison, {
B.getInt32Ty()}, {});
2658 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2663 auto *InitInst =
B.CreateIntrinsic(Intrinsic::spv_init_global,
2665 InitInst->setArgOperand(1, InitOp);
2668 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2674bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *
I,
2676 bool UnknownElemTypeI8) {
2682 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2689void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *
I,
2692 static StringMap<unsigned> ResTypeWellKnown = {
2693 {
"async_work_group_copy", WellKnownTypes::Event},
2694 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2695 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2699 bool IsKnown =
false;
2704 std::string DemangledName =
2707 if (DemangledName.length() > 0)
2709 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2710 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2711 if (ResIt != ResTypeWellKnown.
end()) {
2714 switch (ResIt->second) {
2715 case WellKnownTypes::Event:
2722 switch (DecorationId) {
2725 case FPDecorationId::SAT:
2728 case FPDecorationId::RTE:
2730 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2732 case FPDecorationId::RTZ:
2734 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2736 case FPDecorationId::RTP:
2738 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2740 case FPDecorationId::RTN:
2742 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2748 Type *Ty =
I->getType();
2751 Type *TypeToAssign = Ty;
2754 auto It = AggrConstTypes.
find(
II);
2755 if (It == AggrConstTypes.
end())
2757 TypeToAssign = It->second;
2758 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2759 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2760 TypeToAssign = It->second;
2762 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2763 TypeToAssign = It->second;
2767 for (
const auto &
Op :
I->operands()) {
2774 Type *OpTy =
Op->getType();
2776 CallInst *AssignCI =
2781 Type *OpTy =
Op->getType();
2796 CallInst *AssignCI =
2806bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2807 Instruction *Inst) {
2809 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2819void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *
I,
2821 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2823 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2828 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2829 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2830 if (shouldTryToAddMemAliasingDecoration(
I)) {
2831 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2832 ? SPIRV::Decoration::AliasScopeINTEL
2833 : SPIRV::Decoration::NoAliasINTEL;
2835 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2838 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2839 {
I->getType()}, {
Args});
2843 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2844 processMemAliasingDecoration(LLVMContext::MD_noalias);
2847 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2849 bool AllowFPMaxError =
2851 if (!AllowFPMaxError)
2855 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2859 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
2863 auto &Ctx =
B.getContext();
2865 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
2868 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
2870 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
2871 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
2874 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
2876 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
2878 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2886 &FPFastMathDefaultInfoMap,
2888 auto it = FPFastMathDefaultInfoMap.
find(
F);
2889 if (it != FPFastMathDefaultInfoMap.
end())
2897 SPIRV::FPFastMathMode::None);
2899 SPIRV::FPFastMathMode::None);
2901 SPIRV::FPFastMathMode::None);
2902 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
2908 size_t BitWidth = Ty->getScalarSizeInBits();
2912 assert(Index >= 0 && Index < 3 &&
2913 "Expected FPFastMathDefaultInfo for half, float, or double");
2914 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
2915 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2916 return FPFastMathDefaultInfoVec[Index];
2919void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(
Module &M) {
2921 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2930 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
2932 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
2940 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
2943 [[maybe_unused]] GlobalVariable *GV =
2944 new GlobalVariable(M,
2945 Type::getInt32Ty(
M.getContext()),
2959 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
2960 FPFastMathDefaultInfoMap;
2962 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
2971 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2973 "Expected 4 operands for FPFastMathDefault");
2979 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2981 SPIRV::FPFastMathDefaultInfo &
Info =
2984 Info.FPFastMathDefault =
true;
2985 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
2987 "Expected no operands for ContractionOff");
2991 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2993 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2994 Info.ContractionOff =
true;
2996 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
2998 "Expected 1 operand for SignedZeroInfNanPreserve");
2999 unsigned TargetWidth =
3004 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3008 assert(Index >= 0 && Index < 3 &&
3009 "Expected FPFastMathDefaultInfo for half, float, or double");
3010 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3011 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3012 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3016 std::unordered_map<unsigned, GlobalVariable *> GlobalVars;
3017 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3018 if (FPFastMathDefaultInfoVec.
empty())
3021 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3022 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3025 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3026 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3030 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3032 "and AllowContract");
3034 if (
Info.SignedZeroInfNanPreserve &&
3036 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3037 SPIRV::FPFastMathMode::NSZ))) {
3038 if (
Info.FPFastMathDefault)
3040 "SignedZeroInfNanPreserve but at least one of "
3041 "NotNaN/NotInf/NSZ is enabled.");
3044 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3045 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3046 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3048 "AllowTransform requires AllowReassoc and "
3049 "AllowContract to be set.");
3052 auto it = GlobalVars.find(Flags);
3053 GlobalVariable *GV =
nullptr;
3054 if (it != GlobalVars.end()) {
3060 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3063 GV =
new GlobalVariable(M,
3064 Type::getInt32Ty(
M.getContext()),
3069 GlobalVars[
Flags] = GV;
3075void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *
I,
3078 bool IsConstComposite =
3079 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3080 if (IsConstComposite && TrackConstants) {
3082 auto t = AggrConsts.
find(
I);
3086 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3088 NewOp->setArgOperand(0,
I);
3091 for (
const auto &
Op :
I->operands()) {
3095 unsigned OpNo =
Op.getOperandNo();
3096 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3097 (!
II->isBundleOperand(OpNo) &&
3098 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3102 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3103 :
B.SetInsertPoint(
I);
3106 Type *OpTy =
Op->getType();
3114 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3116 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3117 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3119 SmallVector<Value *, 2>
Args = {
3122 CallInst *PtrCasted =
3123 B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
3128 I->setOperand(OpNo, NewOp);
3130 if (Named.insert(
I).second)
3134Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *
F,
3136 std::unordered_set<Function *> FVisited;
3137 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3140Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
3141 Function *
F,
unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
3143 if (!FVisited.insert(
F).second)
3146 std::unordered_set<Value *> Visited;
3149 for (User *U :
F->users()) {
3161 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3164 for (User *OpU : OpArg->
users()) {
3166 if (!Inst || Inst == CI)
3169 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3176 if (FVisited.find(OuterF) != FVisited.end())
3178 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3179 if (OuterF->
getArg(i) == OpArg) {
3180 Lookup.push_back(std::make_pair(OuterF, i));
3187 for (
auto &Pair :
Lookup) {
3188 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3195void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *
F,
3197 B.SetInsertPointPastAllocas(
F);
3204 for (User *U : Arg->
users()) {
3206 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3224 for (User *U :
F->users()) {
3240 for (User *U : Arg->
users()) {
3244 CI->
getParent()->getParent() == CurrF) {
3246 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3257void SPIRVEmitIntrinsics::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3258 B.SetInsertPointPastAllocas(
F);
3264 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3266 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3268 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3280 bool IsNewFTy =
false;
3296bool SPIRVEmitIntrinsics::processFunctionPointers(
Module &M) {
3299 if (
F.isIntrinsic())
3301 if (
F.isDeclaration()) {
3302 for (User *U :
F.users()) {
3315 for (User *U :
F.users()) {
3317 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3319 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3320 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3327 if (Worklist.
empty())
3330 LLVMContext &Ctx =
M.getContext();
3335 for (Function *
F : Worklist) {
3337 for (
const auto &Arg :
F->args())
3339 IRB.CreateCall(
F, Args);
3341 IRB.CreateRetVoid();
3347void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3348 DenseMap<Function *, CallInst *> Ptrcasts;
3349 for (
auto It : FDeclPtrTys) {
3351 for (
auto *U :
F->users()) {
3356 for (
auto [Idx, ElemTy] : It.second) {
3364 B.SetInsertPointPastAllocas(Arg->
getParent());
3368 }
else if (isaGEP(Param)) {
3369 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3378 .getFirstNonPHIOrDbgOrAlloca());
3399SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP) {
3406 Type *SrcTy =
GEP->getSourceElementType();
3407 SmallVector<Value *, 8> Indices(
GEP->indices());
3409 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3410 Indices.erase(Indices.begin());
3411 SrcTy = ArrTy->getElementType();
3413 GEP->getNoWrapFlags(),
"",
3414 GEP->getIterator());
3419void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &
F,
3426 if (
ST->canUseExtension(
3427 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3428 for (BasicBlock &BB :
F) {
3430 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3434 SmallVector<unsigned, 1>
Ops =
3436 unsigned LC =
Ops[0];
3437 if (LC == SPIRV::LoopControl::None)
3441 B.SetInsertPoint(Term);
3442 SmallVector<Value *, 4> IntrArgs;
3443 for (
unsigned Op :
Ops)
3445 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3452 DominatorTree DT(
F);
3457 for (Loop *L : LI.getLoopsInPreorder()) {
3466 SmallVector<unsigned, 1> LoopControlOps =
3468 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3472 B.SetInsertPoint(Header->getTerminator());
3475 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3476 for (
unsigned Imm : LoopControlOps)
3477 Args.emplace_back(
B.getInt32(Imm));
3478 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3482bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3483 if (
Func.isDeclaration())
3487 GR =
ST.getSPIRVGlobalRegistry();
3491 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3496 AggrConstTypes.
clear();
3499 processParamTypesByFunHeader(CurrF,
B);
3503 SmallPtrSet<Instruction *, 4> DeadInsts;
3508 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3512 GR->addDeducedElementType(SGEP,
3517 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3519 GEP->replaceAllUsesWith(NewGEP);
3523 if (
Type *GepTy = getGEPType(
GEP))
3527 for (
auto *
I : DeadInsts) {
3528 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3529 I->eraseFromParent();
3539 Type *ElTy =
SI->getValueOperand()->getType();
3544 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3545 for (
auto &GV :
Func.getParent()->globals())
3546 processGlobalValue(GV,
B);
3548 preprocessUndefs(
B);
3549 preprocessPoisons(
B);
3550 simplifyNullAddrSpaceCasts();
3551 preprocessCompositeConstants(
B);
3559 Type *I32Ty =
B.getInt32Ty();
3563 if (!
I.getType()->isAggregateType())
3565 AggrConstTypes[&
I] =
I.getType();
3566 I.mutateType(I32Ty);
3569 preprocessBoolVectorBitcasts(Func);
3573 applyDemangledPtrArgTypes(
B);
3576 for (
auto &
I : Worklist) {
3578 if (isConvergenceIntrinsic(
I))
3581 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3583 insertAssignTypeIntrs(
I,
B);
3584 insertPtrCastOrAssignTypeInstr(
I,
B);
3588 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3589 insertAssignPtrTypeIntrs(
I,
B,
true);
3592 useRoundingMode(FPI,
B);
3597 SmallPtrSet<Instruction *, 4> IncompleteRets;
3599 deduceOperandElementType(&
I, &IncompleteRets);
3603 for (BasicBlock &BB : Func)
3604 for (PHINode &Phi : BB.
phis())
3606 deduceOperandElementType(&Phi,
nullptr);
3608 for (
auto *
I : Worklist) {
3609 TrackConstants =
true;
3619 if (isConvergenceIntrinsic(
I))
3623 processInstrAfterVisit(
I,
B);
3626 emitUnstructuredLoopControls(Func,
B);
3632bool SPIRVEmitIntrinsics::postprocessTypes(
Module &M) {
3633 if (!GR || TodoTypeSz == 0)
3636 unsigned SzTodo = TodoTypeSz;
3637 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3642 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3643 Type *KnownTy = GR->findDeducedElementType(
Op);
3644 if (!KnownTy || !AssignCI)
3650 std::unordered_set<Value *> Visited;
3651 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3652 if (ElemTy != KnownTy) {
3653 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3654 propagateElemType(CI, ElemTy, VisitedSubst);
3661 if (
Op->hasUseList()) {
3662 for (User *U :
Op->users()) {
3669 if (TodoTypeSz == 0)
3674 SmallPtrSet<Instruction *, 4> IncompleteRets;
3676 auto It = ToProcess.
find(&
I);
3677 if (It == ToProcess.
end())
3679 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3680 if (It->second.size() == 0)
3682 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3683 if (TodoTypeSz == 0)
3688 return SzTodo > TodoTypeSz;
3692void SPIRVEmitIntrinsics::parseFunDeclarations(
Module &M) {
3694 if (!
F.isDeclaration() ||
F.isIntrinsic())
3698 if (DemangledName.empty())
3702 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3703 DemangledName,
ST.getPreferredInstructionSet());
3704 if (Opcode != SPIRV::OpGroupAsyncCopy)
3707 SmallVector<unsigned> Idxs;
3716 LLVMContext &Ctx =
F.getContext();
3718 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3719 if (!TypeStrs.
size())
3722 for (
unsigned Idx : Idxs) {
3723 if (Idx >= TypeStrs.
size())
3726 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3729 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3734bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3735 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3737 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3738 if (!
ST.canUseExtension(
3739 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3740 I.getContext().emitError(
3741 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3745 I.eraseFromParent();
3751 Value *Ptrs =
I.getArgOperand(0);
3753 Value *Passthru =
I.getArgOperand(2);
3756 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3758 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3763 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3765 I.eraseFromParent();
3769 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3770 if (!
ST.canUseExtension(
3771 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3772 I.getContext().emitError(
3773 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3776 I.eraseFromParent();
3782 Value *Values =
I.getArgOperand(0);
3783 Value *Ptrs =
I.getArgOperand(1);
3788 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3790 SmallVector<Value *, 4>
Args = {Values, Ptrs,
B.getInt32(Alignment),
Mask};
3794 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3795 I.eraseFromParent();
3806void SPIRVEmitIntrinsics::preprocessBoolVectorBitcasts(Function &
F) {
3807 struct BoolVecBitcast {
3809 FixedVectorType *BoolVecTy;
3813 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3815 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3823 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3825 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3829 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3831 Value *Src = BC->getOperand(0);
3832 unsigned BoolVecN = BoolVecTy->getNumElements();
3834 Type *IntTy =
B.getIntNTy(BoolVecN);
3840 IntVal = ConstantInt::get(IntTy, 0);
3841 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3842 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3843 Value *Ext =
B.CreateZExt(Elem, IntTy);
3845 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3846 IntVal =
B.CreateOr(IntVal, Ext);
3852 if (!Src->getType()->isIntegerTy())
3853 IntVal =
B.CreateBitCast(Src, IntTy);
3858 if (!SrcIsBoolVec) {
3861 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3864 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
3865 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
3871 if (!BC->getDestTy()->isIntegerTy())
3872 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
3875 BC->replaceAllUsesWith(Result);
3876 BC->eraseFromParent();
3880bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(
Module &M) {
3884 if (!
F.isIntrinsic())
3887 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
3892 Changed |= processMaskedMemIntrinsic(*
II);
3896 F.eraseFromParent();
3902bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
3905 Changed |= convertMaskedMemIntrinsics(M);
3907 parseFunDeclarations(M);
3908 insertConstantsForFPFastMathDefault(M);
3919 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
3921 processParamTypes(&
F,
B);
3925 CanTodoType =
false;
3926 Changed |= postprocessTypes(M);
3929 Changed |= processFunctionPointers(M);
3936 SPIRVEmitIntrinsics Legacy(TM);
3937 if (Legacy.runOnModule(M))
3943 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 tracesToPointerAlloca(Value *V)
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)
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)