29#include "llvm/IR/IntrinsicsSPIRV.h"
64#define DEBUG_TYPE "spirv-emit-intrinsics"
68 cl::desc(
"Emit OpName for all instructions"),
72#define GET_BuiltinGroup_DECL
73#include "SPIRVGenTables.inc"
78class GlobalVariableUsers {
79 template <
typename T1,
typename T2>
80 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
82 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
84 void collectGlobalUsers(
85 const GlobalVariable *GV,
86 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
87 &GlobalIsUsedByGlobal) {
89 while (!
Stack.empty()) {
93 GlobalIsUsedByFun[GV].insert(
I->getFunction());
98 GlobalIsUsedByGlobal[GV].insert(UserGV);
103 Stack.append(
C->user_begin(),
C->user_end());
107 bool propagateGlobalToGlobalUsers(
108 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
109 &GlobalIsUsedByGlobal) {
112 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
113 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
114 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
115 auto It = GlobalIsUsedByGlobal.find(UserGV);
116 if (It == GlobalIsUsedByGlobal.end())
124 void propagateGlobalToFunctionReferences(
125 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
126 &GlobalIsUsedByGlobal) {
127 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
128 auto &UserFunctions = GlobalIsUsedByFun[GV];
129 for (
const GlobalVariable *UserGV : UserGlobals) {
130 auto It = GlobalIsUsedByFun.find(UserGV);
131 if (It == GlobalIsUsedByFun.end())
142 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
143 GlobalIsUsedByGlobal;
144 GlobalIsUsedByFun.clear();
145 for (GlobalVariable &GV :
M.globals())
146 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
149 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
152 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
155 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
156 const FunctionSetType &
157 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
158 auto It = GlobalIsUsedByFun.find(&GV);
159 if (It != GlobalIsUsedByFun.end())
162 static const FunctionSetType
Empty{};
167static bool isaGEP(
const Value *V) {
173static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
179 return AT->getNumElements();
185class SPIRVEmitIntrinsicsImpl
186 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
187 const SPIRVTargetMachine &TM;
188 SPIRVGlobalRegistry *GR =
nullptr;
190 bool TrackConstants =
true;
191 bool HaveFunPtrs =
false;
192 bool CanUseAnyVectorRank =
false;
193 DenseMap<Instruction *, Constant *> AggrConsts;
194 DenseMap<Instruction *, Type *> AggrConstTypes;
195 SmallPtrSet<Instruction *, 0> AggrStores;
196 GlobalVariableUsers GVUsers;
197 SmallPtrSet<Value *, 0> Named;
200 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
203 bool CanTodoType =
true;
204 unsigned TodoTypeSz = 0;
205 DenseMap<Value *, bool> TodoType;
206 void insertTodoType(
Value *
Op) {
208 if (CanTodoType && !isaGEP(
Op)) {
209 auto It = TodoType.try_emplace(
Op,
true);
214 void eraseTodoType(
Value *
Op) {
215 auto It = TodoType.find(
Op);
216 if (It != TodoType.end() && It->second) {
224 auto It = TodoType.find(
Op);
225 return It != TodoType.end() && It->second;
229 SmallPtrSet<Instruction *, 0> TypeValidated;
232 enum WellKnownTypes { Event };
235 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
236 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
237 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
238 bool UnknownElemTypeI8,
239 bool IgnoreKnownType =
false);
240 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
241 bool UnknownElemTypeI8);
242 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
243 SmallPtrSetImpl<Value *> &Visited,
244 bool UnknownElemTypeI8,
245 std::optional<unsigned> AddrSpace = {});
247 SmallPtrSetImpl<Value *> &Visited,
248 bool UnknownElemTypeI8);
250 bool UnknownElemTypeI8);
253 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
254 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
255 SmallPtrSetImpl<Value *> &Visited,
256 bool UnknownElemTypeI8);
260 deduceOperandElementType(Instruction *
I,
261 SmallPtrSetImpl<Instruction *> *IncompleteRets,
262 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
263 bool IsPostprocessing =
false);
268 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
269 void simplifyNullAddrSpaceCasts();
271 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
272 bool IsPostprocessing);
274 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
276 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
277 bool UnknownElemTypeI8);
279 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
281 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
282 Type *ExpectedElementType,
283 unsigned OperandToReplace,
285 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
286 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
288 void insertConstantsForFPFastMathDefault(
Module &M);
291 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
294 Type *deduceFunParamElementType(
Function *
F,
unsigned OpIdx);
296 SmallPtrSetImpl<Function *> &FVisited);
298 bool deduceOperandElementTypeCalledFunction(
300 Type *&KnownElemTy,
bool &Incomplete);
301 void deduceOperandElementTypeFunctionPointer(
303 Type *&KnownElemTy,
bool IsPostprocessing);
304 bool deduceOperandElementTypeFunctionRet(
305 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
306 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
310 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
311 DenseMap<Function *, CallInst *> Ptrcasts);
313 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
316 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
317 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
318 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
319 SmallPtrSetImpl<Value *> &Visited,
320 DenseMap<Function *, CallInst *> Ptrcasts);
323 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
324 Instruction *Dest,
bool DeleteOld =
true);
328 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
331 bool postprocessTypes(
Module &M);
332 bool processFunctionPointers(
Module &M);
333 void parseFunDeclarations(
Module &M);
334 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
335 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
336 bool convertMaskedMemIntrinsics(
Module &M);
337 void preprocessBoolVectorBitcasts(
Function &
F);
356 bool walkLogicalAccessChain(
357 GetElementPtrInst &
GEP,
358 const std::function<
void(
Type *PointedType,
uint64_t Index)>
361 uint64_t Multiplier)> &OnDynamicIndexing);
363 bool walkLogicalAccessChainDynamic(
365 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
368 bool walkLogicalAccessChainConstant(
370 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing);
376 Type *getGEPType(GetElementPtrInst *
GEP);
383 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
385 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
388 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
391 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
394 Instruction *visitInsertElementInst(InsertElementInst &
I);
395 Instruction *visitExtractElementInst(ExtractElementInst &
I);
397 Instruction *visitExtractValueInst(ExtractValueInst &
I);
401 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
406 bool runOnModule(
Module &M);
409class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
410 const SPIRVTargetMachine &TM;
414 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
415 : ModulePass(ID), TM(TM) {}
417 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
419 bool runOnModule(
Module &M)
override {
420 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
426 Intrinsic::experimental_convergence_loop,
427 Intrinsic::experimental_convergence_anchor>());
430bool expectIgnoredInIRTranslation(
const Instruction *
I) {
432 Intrinsic::spv_resource_handlefrombinding,
433 Intrinsic::spv_resource_getbasepointer,
434 Intrinsic::spv_resource_getpointer>());
441 return getPointerRoot(V);
447char SPIRVEmitIntrinsicsLegacy::ID = 0;
450 "SPIRV emit intrinsics",
false,
false)
464 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
477 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
483 B.SetCurrentDebugLocation(
I->getDebugLoc());
484 if (
I->getType()->isVoidTy())
485 B.SetInsertPoint(
I->getNextNode());
487 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
497 if (
I->getType()->isTokenTy())
499 "does not support token type",
504 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
505 expectIgnoredInIRTranslation(
I))
516 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
527 std::vector<Value *> Args = {
530 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
533void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
537 if (isTodoType(Src)) {
540 insertTodoType(Dest);
544void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
549 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
550 Src->eraseFromParent();
553 if (Named.
insert(Dest).second)
568 V = V->stripPointerCasts();
589Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
590 bool UnknownElemTypeI8,
591 bool IsPostprocessing) {
595 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
609 if (UnknownElemTypeI8) {
610 if (!IsPostprocessing)
626 B.SetInsertPointPastAllocas(OpA->getParent());
629 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
631 Type *OpTy =
Op->getType();
633 SmallVector<Value *, 2>
Args = {
636 CallInst *PtrCasted =
637 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
642void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
644 DenseMap<Function *, CallInst *> Ptrcasts) {
646 CallInst *PtrCastedI =
nullptr;
647 auto It = Ptrcasts.
find(
F);
648 if (It == Ptrcasts.
end()) {
649 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
650 Ptrcasts[
F] = PtrCastedI;
652 PtrCastedI = It->second;
654 I->replaceUsesOfWith(
Op, PtrCastedI);
657void SPIRVEmitIntrinsicsImpl::propagateElemType(
659 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
660 DenseMap<Function *, CallInst *> Ptrcasts;
662 for (
auto *U :
Users) {
665 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
670 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
671 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
675void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
677 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
678 SmallPtrSet<Value *, 0> Visited;
679 DenseMap<Function *, CallInst *> Ptrcasts;
680 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
681 std::move(Ptrcasts));
684void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
686 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
687 SmallPtrSetImpl<Value *> &Visited,
688 DenseMap<Function *, CallInst *> Ptrcasts) {
692 for (
auto *U :
Users) {
695 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
700 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
701 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
708Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
709 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
710 SmallPtrSet<Value *, 0> Visited;
711 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
715Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
716 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
717 bool UnknownElemTypeI8, std::optional<unsigned> AddrSpace) {
722 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
724 NestedTy, AddrSpace.value_or(PtrTy->getAddressSpace()));
734Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
735 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
747 for (User *OpU :
Op->users()) {
749 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
761 Function *CalledF,
unsigned OpIdx) {
771Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
772 bool UnknownElemTypeI8) {
773 SmallPtrSet<Value *, 0> Visited;
774 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
777void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
779 bool UnknownElemTypeI8) {
781 if (!UnknownElemTypeI8)
790bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
792 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
799 if (
ST->getNumElements() == 0)
801 CurType =
ST->getElementType(0);
802 OnLiteralIndexing(CurType, 0);
810 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
811 return AT ==
nullptr;
814bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
816 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing) {
821 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
825 CurType = AT->getElementType();
826 OnLiteralIndexing(CurType, Index);
828 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
831 const auto &STL =
DL.getStructLayout(ST);
832 unsigned Element = STL->getElementContainingOffset(
Offset);
833 Offset -= STL->getElementOffset(Element);
834 CurType =
ST->getElementType(Element);
835 OnLiteralIndexing(CurType, Element);
837 Type *EltTy = VT->getElementType();
838 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
839 assert(EltSizeBits % 8 == 0 &&
840 "Element type size in bits must be a multiple of 8.");
841 uint32_t EltTypeSize = EltSizeBits / 8;
846 OnLiteralIndexing(CurType, Index);
856bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
857 GetElementPtrInst &
GEP,
858 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
862 std::optional<uint64_t> MultiplierOpt =
863 getByteAddressingMultiplier(
GEP.getSourceElementType());
864 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
865 uint64_t Multiplier = *MultiplierOpt;
868 Value *Src = getPointerRoot(
GEP.getPointerOperand());
869 Type *CurType = deduceElementType(Src,
true);
873 return walkLogicalAccessChainConstant(
874 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
876 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
877 OnLiteralIndexing, OnDynamicIndexing);
880Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
881 GetElementPtrInst &
GEP) {
884 B.SetInsertPoint(&
GEP);
886 std::vector<Value *> Indices;
887 Indices.push_back(ConstantInt::get(
888 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
889 walkLogicalAccessChain(
893 ConstantInt::get(
B.getInt64Ty(), Index,
false));
898 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
900 if (Multiplier == EltTypeSize) {
902 }
else if (EltTypeSize % Multiplier == 0) {
905 EltTypeSize / Multiplier,
909 ConstantInt::get(
Offset->getType(), Multiplier,
912 Index =
B.CreateUDiv(Index,
913 ConstantInt::get(
Offset->getType(), EltTypeSize,
917 Indices.push_back(Index);
921 SmallVector<Value *, 4>
Args;
922 Args.push_back(
B.getInt1(
GEP.isInBounds()));
923 Args.push_back(
GEP.getOperand(0));
926 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
927 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
931Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
933 Type *CurType =
GEP->getResultElementType();
935 bool Interrupted = walkLogicalAccessChain(
936 *
GEP, [&CurType](
Type *EltType,
uint64_t Index) { CurType = EltType; },
939 return Interrupted ?
GEP->getResultElementType() : CurType;
942Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
943 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
945 return getGEPTypeLogical(
Ref);
952 Ty =
Ref->getSourceElementType();
956 Ty =
Ref->getResultElementType();
961Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
962 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
963 bool IgnoreKnownType) {
969 if (!IgnoreKnownType)
981 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
983 Ty = getGEPType(
Ref);
985 Ty = SGEP->getResultElementType();
990 KnownTy =
Op->getType();
992 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
995 Ty = SPIRV::getOriginalFunctionType(*Fn);
1002 std::optional<unsigned> ProgramAS;
1007 SPIRV::Extension::SPV_INTEL_function_pointers))
1011 Ty = deduceElementTypeByValueDeep(
Ref->getValueType(),
Op, Visited,
1012 UnknownElemTypeI8, ProgramAS);
1015 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
1017 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1019 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1021 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1023 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1028 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1032 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1034 Type *BestTy =
nullptr;
1036 DenseMap<Type *, unsigned> PhiTys;
1037 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1038 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1045 if (It.first->second > MaxN) {
1046 MaxN = It.first->second;
1054 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1058 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1059 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1064 static StringMap<unsigned> ResTypeByArg = {
1070 {
"__to_private", 0},
1071 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1072 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1073 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1074 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1075 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1076 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1080 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1081 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1083 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1084 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1085 for (User *U :
II->users()) {
1090 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1092 Ty = HandleType->getTypeParameter(0);
1093 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1107 }
else if (
II &&
II->getIntrinsicID() ==
1108 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1112 std::string DemangledName =
1114 if (DemangledName.length() > 0)
1115 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1116 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1117 if (AsArgIt != ResTypeByArg.
end())
1118 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1119 Visited, UnknownElemTypeI8);
1126 if (Ty && !IgnoreKnownType) {
1137Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1138 bool UnknownElemTypeI8) {
1139 SmallPtrSet<Value *, 0> Visited;
1140 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1143Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1144 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1145 bool UnknownElemTypeI8) {
1154 if (!Visited.
insert(U).second)
1159 bool Change =
false;
1160 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1162 assert(
Op &&
"Operands should not be null.");
1163 Type *OpTy =
Op->getType();
1166 if (
Type *NestedTy =
1167 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1174 Change |= Ty != OpTy;
1178 Tys, OrigStructTy->isLiteral() ?
"" : OrigStructTy->getName(),
1179 OrigStructTy->isPacked());
1184 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1185 Type *OpTy = ArrTy->getElementType();
1188 if (
Type *NestedTy =
1189 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1196 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1202 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1203 Type *OpTy = VecTy->getElementType();
1206 if (
Type *NestedTy =
1207 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1214 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1225Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1226 bool UnknownElemTypeI8) {
1227 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1229 if (!UnknownElemTypeI8)
1232 return IntegerType::getInt8Ty(
I->getContext());
1236 Value *PointerOperand) {
1242 return I->getType();
1250bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1252 Type *&KnownElemTy,
bool &Incomplete) {
1256 std::string DemangledName =
1258 if (DemangledName.length() > 0 &&
1260 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1261 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1262 DemangledName,
ST.getPreferredInstructionSet());
1263 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1264 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1270 KnownElemTy = ElemTy;
1271 Ops.push_back(std::make_pair(
Op, i));
1273 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1280 case SPIRV::OpAtomicFAddEXT:
1281 case SPIRV::OpAtomicFMinEXT:
1282 case SPIRV::OpAtomicFMaxEXT:
1283 case SPIRV::OpAtomicLoad:
1284 case SPIRV::OpAtomicCompareExchangeWeak:
1285 case SPIRV::OpAtomicCompareExchange:
1286 case SPIRV::OpAtomicExchange:
1287 case SPIRV::OpAtomicIAdd:
1288 case SPIRV::OpAtomicISub:
1289 case SPIRV::OpAtomicOr:
1290 case SPIRV::OpAtomicXor:
1291 case SPIRV::OpAtomicAnd:
1292 case SPIRV::OpAtomicUMin:
1293 case SPIRV::OpAtomicUMax:
1294 case SPIRV::OpAtomicSMin:
1295 case SPIRV::OpAtomicSMax: {
1300 Incomplete = isTodoType(
Op);
1301 Ops.push_back(std::make_pair(
Op, 0));
1303 case SPIRV::OpAtomicStore: {
1312 Incomplete = isTodoType(
Op);
1313 Ops.push_back(std::make_pair(
Op, 0));
1322void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1324 Type *&KnownElemTy,
bool IsPostprocessing) {
1328 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1329 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1330 bool IsNewFTy =
false, IsIncomplete =
false;
1333 Type *ArgTy = Arg->getType();
1338 if (isTodoType(Arg))
1339 IsIncomplete =
true;
1341 IsIncomplete =
true;
1344 ArgTy = FTy->getFunctionParamType(ParmIdx);
1348 Type *RetTy = FTy->getReturnType();
1355 IsIncomplete =
true;
1357 IsIncomplete =
true;
1360 if (!IsPostprocessing && IsIncomplete)
1363 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1366bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1367 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1368 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1380 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1381 for (User *U :
F->users()) {
1390 propagateElemType(CI, PrevElemTy, VisitedSubst);
1400 for (Instruction *IncompleteRetI : *IncompleteRets)
1401 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1403 }
else if (IncompleteRets) {
1414void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1415 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1416 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1418 Type *KnownElemTy =
nullptr;
1419 bool Incomplete =
false;
1425 Incomplete = isTodoType(
I);
1426 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1429 Ops.push_back(std::make_pair(
Op, i));
1435 Incomplete = isTodoType(
I);
1436 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1443 Incomplete = isTodoType(
I);
1444 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1448 KnownElemTy =
Ref->getSourceElementType();
1449 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1454 KnownElemTy =
Ref->getBaseType();
1455 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1458 KnownElemTy =
I->getType();
1465 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1474 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1478 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1483 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1491 Incomplete = isTodoType(
Ref->getPointerOperand());
1492 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1500 Incomplete = isTodoType(
Ref->getPointerOperand());
1501 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1507 Incomplete = isTodoType(
I);
1508 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1511 Ops.push_back(std::make_pair(
Op, i));
1519 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1520 IsPostprocessing, KnownElemTy,
Op,
1523 Incomplete = isTodoType(CurrF);
1524 Ops.push_back(std::make_pair(
Op, 0));
1530 bool Incomplete0 = isTodoType(Op0);
1531 bool Incomplete1 = isTodoType(Op1);
1533 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1535 : GR->findDeducedElementType(Op0);
1537 KnownElemTy = ElemTy0;
1538 Incomplete = Incomplete0;
1539 Ops.push_back(std::make_pair(Op1, 1));
1540 }
else if (ElemTy1) {
1541 KnownElemTy = ElemTy1;
1542 Incomplete = Incomplete1;
1543 Ops.push_back(std::make_pair(Op0, 0));
1547 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1548 else if (HaveFunPtrs)
1549 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1554 if (!KnownElemTy ||
Ops.size() == 0)
1558 for (
auto &OpIt :
Ops) {
1562 Type *AskTy =
nullptr;
1563 CallInst *AskCI =
nullptr;
1564 if (IsPostprocessing && AskOps) {
1570 if (Ty == KnownElemTy)
1573 Type *OpTy =
Op->getType();
1579 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1587 else if (!IsPostprocessing)
1591 if (AssignCI ==
nullptr) {
1600 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1601 std::make_pair(
I,
Op)};
1602 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1606 CallInst *PtrCastI =
1607 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1608 if (OpIt.second == std::numeric_limits<unsigned>::max())
1611 I->setOperand(OpIt.second, PtrCastI);
1617void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1622 if (isAssignTypeInstr(U)) {
1623 B.SetInsertPoint(U);
1624 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1625 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1626 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1628 U->eraseFromParent();
1631 U->replaceUsesOfWith(Old, New);
1639 Type *NewArgTy =
New->getType();
1641 if (NewArgTy != ExpectedArgTy) {
1644 M, Intrinsic::spv_abort, {NewArgTy});
1654 "aggregate PHI/select/freeze should have been mutated to value-id "
1656 U->replaceUsesOfWith(Old, New);
1661 New->copyMetadata(*Old);
1667 bool HasPoisonExt) {
1674 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1675 "lowered as undef\n");
1677 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1678 Type *Ty = UV->getType();
1684 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1685 :
B.CreateIntrinsicWithoutFolding(IID, {});
1686 AggrConsts[
Call] = UV;
1687 AggrConstTypes[
Call] = Ty;
1692 return B.CreateIntrinsic(IID, {Ty}, {});
1699void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1704 SmallVector<Instruction *, 16> Insts;
1708 for (Instruction *
I : Insts) {
1709 bool BPrepared =
false;
1711 for (
unsigned Idx = 0;
Idx <
I->getNumOperands(); ++
Idx) {
1715 bool IsScalar = !
Op->getType()->isAggregateType();
1718 if (IsScalar && !AsPoison)
1722 if (IsScalar && Phi)
1723 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1724 else if (!BPrepared) {
1728 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1729 I->setOperand(Idx, Repl);
1738void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1742 ASC->replaceAllUsesWith(
1744 ASC->eraseFromParent();
1752 if (!V->getType()->isAggregateType())
1761 I.getType()->isAggregateType();
1767void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1770 for (Use &U :
I->operands()) {
1777 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1782 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1784 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1790void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1794 std::queue<Instruction *> Worklist;
1798 while (!Worklist.empty()) {
1799 auto *
I = Worklist.front();
1802 bool KeepInst =
false;
1803 for (
const auto &
Op :
I->operands()) {
1805 Type *ResTy =
nullptr;
1808 ResTy = COp->getType();
1820 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1823 auto PrepareInsert = [&]() {
1826 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1827 :
B.SetInsertPoint(
I);
1832 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1833 Args.push_back(COp->getElementAsConstant(i));
1839 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1848 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1854 auto *CI =
B.CreateIntrinsicWithoutFolding(
1855 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1859 AggrConsts[CI] = AggrConst;
1860 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1872 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1877 unsigned RoundingModeDeco,
1884 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1893 MDNode *SaturatedConversionNode =
1895 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1915 MDString *ConstraintString =
1920 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1924 B.SetInsertPoint(&
Call);
1925 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1930void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1933 if (!
RM.has_value())
1935 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1936 switch (
RM.value()) {
1940 case RoundingMode::NearestTiesToEven:
1941 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1943 case RoundingMode::TowardNegative:
1944 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1946 case RoundingMode::TowardPositive:
1947 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1949 case RoundingMode::TowardZero:
1950 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1952 case RoundingMode::Dynamic:
1953 case RoundingMode::NearestTiesToAway:
1957 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1963Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1967 B.SetInsertPoint(&
I);
1968 SmallVector<Value *, 4>
Args;
1970 Args.push_back(
I.getCondition());
1973 for (
auto &Case :
I.cases()) {
1974 Args.push_back(Case.getCaseValue());
1975 BBCases.
push_back(Case.getCaseSuccessor());
1978 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1979 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1983 I.eraseFromParent();
1986 B.SetInsertPoint(ParentBB);
1987 IndirectBrInst *BrI =
B.CreateIndirectBr(
1990 for (BasicBlock *BBCase : BBCases)
1999Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
2005 B.SetInsertPoint(&
I);
2007 SmallVector<Value *, 4>
Args;
2008 Args.push_back(
B.getInt1(
true));
2009 Args.push_back(
I.getOperand(0));
2010 Args.push_back(
B.getInt32(0));
2011 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
2012 Args.push_back(SGEP->getIndexOperand(J));
2015 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
2016 replaceAllUsesWithAndErase(
B, &
I, NewI);
2021SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2023 B.SetInsertPoint(&
I);
2028 unsigned N = RetVTy->getNumElements();
2029 Value *PtrOp =
I.getPointerOperand();
2031 Type *ResultPtrTy = RetVTy->getElementType();
2034 Value *InBounds =
B.getInt1(
I.isInBounds());
2035 Type *LanePointeeTy = getGEPType(&
I);
2036 Type *SrcElemTy =
I.getSourceElementType();
2045 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2046 Value *LaneIdx =
B.getInt32(Lane);
2047 Value *ScalarPtr = PtrOp;
2051 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2055 SmallVector<Value *, 4>
Args;
2056 Args.push_back(InBounds);
2057 Args.push_back(ScalarPtr);
2058 for (
Value *Idx :
I.indices()) {
2066 Args.push_back(visitExtractElementInst(*EI));
2070 Args.push_back(Idx);
2073 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2075 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2079 replaceAllUsesWithAndErase(
B, &
I, NewI);
2097 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2098 return buildLogicalAccessChainFromGEP(
I);
2103 Value *PtrOp =
I.getPointerOperand();
2104 Type *SrcElemTy =
I.getSourceElementType();
2105 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2108 if (ArrTy->getElementType() == SrcElemTy) {
2110 Type *FirstIdxType =
I.getOperand(1)->getType();
2111 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2112 for (
Value *Idx :
I.indices())
2116 SmallVector<Value *, 4>
Args;
2117 Args.push_back(
B.getInt1(
I.isInBounds()));
2118 Args.push_back(
I.getPointerOperand());
2121 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2123 replaceAllUsesWithAndErase(
B, &
I, NewI);
2130 SmallVector<Value *, 4>
Args;
2131 Args.push_back(
B.getInt1(
I.isInBounds()));
2134 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2135 replaceAllUsesWithAndErase(
B, &
I, NewI);
2139Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2141 B.SetInsertPoint(&
I);
2150 I.eraseFromParent();
2157 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2158 replaceAllUsesWithAndErase(
B, &
I, NewI);
2162void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2164 Type *VTy =
V->getType();
2169 if (ElemTy != AssignedType)
2182 if (CurrentType == AssignedType)
2189 " for value " +
V->getName(),
2198void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2199 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2204 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2205 if (PointerElemTy == ExpectedElementType ||
2210 Value *ExpectedElementVal =
2212 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2214 bool FirstPtrCastOrAssignPtrType =
true;
2220 for (
auto User :
Pointer->users()) {
2223 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2224 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2225 II->getOperand(0) != Pointer)
2230 FirstPtrCastOrAssignPtrType =
false;
2231 if (
II->getOperand(1) != VMD ||
2238 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2243 if (
II->getParent() !=
I->getParent())
2246 I->setOperand(OperandToReplace,
II);
2261 if (FirstPtrCastOrAssignPtrType) {
2266 }
else if (isTodoType(Pointer)) {
2267 eraseTodoType(Pointer);
2275 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2276 std::make_pair(
I, Pointer)};
2278 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2291 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
2297void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2302 replacePointerOperandWithPtrCast(
2303 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2309 Type *OpTy =
Op->getType();
2312 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2315 if (OpTy ==
Op->getType())
2316 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2317 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2322 Type *OpTy = LI->getType();
2333 Type *NewOpTy = OpTy;
2334 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2335 if (OpTy == NewOpTy)
2336 insertTodoType(Pointer);
2339 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2344 Type *OpTy =
nullptr;
2356 OpTy = GEPI->getSourceElementType();
2358 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2360 insertTodoType(Pointer);
2372 std::string DemangledName =
2376 bool HaveTypes =
false;
2377 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2395 for (User *U : CalledArg->
users()) {
2397 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2403 HaveTypes |= ElemTy !=
nullptr;
2408 if (DemangledName.empty() && !HaveTypes)
2412 TM.
getSubtarget<SPIRVSubtarget>(*CalledF).getPreferredInstructionSet();
2414 bool ParseBuiltinTypes =
2415 !DemangledName.empty() &&
2416 (!CalledF->
isDeclaration() || SPIRV::isBuiltin(DemangledName, Set));
2417 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2432 Type *ExpectedType =
2433 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2434 if (!ExpectedType && ParseBuiltinTypes)
2435 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2436 DemangledName, OpIdx,
I->getContext());
2437 if (!ExpectedType || ExpectedType->
isVoidTy())
2445 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2450SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2453 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2457 I.getOperand(1)->getType(),
2458 I.getOperand(2)->getType()};
2460 B.SetInsertPoint(&
I);
2462 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2464 replaceAllUsesWithAndErase(
B, &
I, NewI);
2469SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2472 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2476 B.SetInsertPoint(&
I);
2478 I.getIndexOperand()->getType()};
2479 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2480 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2482 replaceAllUsesWithAndErase(
B, &
I, NewI);
2486Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2488 B.SetInsertPoint(&
I);
2491 Value *AggregateOp =
I.getAggregateOperand();
2495 Args.push_back(AggregateOp);
2496 Args.push_back(
I.getInsertedValueOperand());
2497 for (
auto &
Op :
I.indices())
2498 Args.push_back(
B.getInt32(
Op));
2500 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2501 replaceMemInstrUses(&
I, NewI,
B);
2506SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2508 B.SetInsertPoint(&
I);
2509 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2518 for (
auto &
Op :
I.indices())
2519 Args.push_back(
B.getInt32(
Op));
2520 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2521 {
I.getType()}, {
Args});
2527 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2528 AggrConstTypes[NewI] =
I.getType();
2530 replaceMemInstrUses(&
I, NewI,
B);
2533 replaceAllUsesWithAndErase(
B, &
I, NewI);
2537 for (
const Use &U : NewI->
uses()) {
2538 User *Usr =
U.getUser();
2540 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2551 if (ArgNo < FT->getNumParams() &&
2552 !FT->getParamType(ArgNo)->isAggregateType()) {
2561Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2562 if (!
I.getType()->isAggregateType())
2565 B.SetInsertPoint(&
I);
2566 TrackConstants =
false;
2571 unsigned IntrinsicId;
2572 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2573 if (!
I.isAtomic()) {
2574 IntrinsicId = Intrinsic::spv_load;
2575 Args.push_back(
B.getInt32(
I.getAlign().value()));
2577 IntrinsicId = Intrinsic::spv_atomic_load;
2578 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2580 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2581 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2583 replaceMemInstrUses(&
I, NewI,
B);
2587Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2591 B.SetInsertPoint(&
I);
2592 TrackConstants =
false;
2596 auto *PtrOp =
I.getPointerOperand();
2598 if (
I.getValueOperand()->getType()->isAggregateType()) {
2606 "Unexpected argument of aggregate type, should be spv_extractv!");
2610 unsigned IntrinsicId;
2611 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2613 if (!
I.isAtomic()) {
2614 IntrinsicId = Intrinsic::spv_store;
2615 Args.push_back(
B.getInt32(
I.getAlign().value()));
2617 IntrinsicId = Intrinsic::spv_atomic_store;
2618 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2621 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2623 I.eraseFromParent();
2627Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2628 Value *ArraySize =
nullptr;
2629 if (
I.isArrayAllocation()) {
2632 SPIRV::Extension::SPV_INTEL_variable_length_array))
2634 "array allocation: this instruction requires the following "
2635 "SPIR-V extension: SPV_INTEL_variable_length_array",
2637 ArraySize =
I.getArraySize();
2640 B.SetInsertPoint(&
I);
2641 TrackConstants =
false;
2642 Type *PtrTy =
I.getType();
2645 ?
B.CreateIntrinsicWithoutFolding(
2646 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2647 {ArraySize,
B.getInt32(
I.getAlign().value())})
2648 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2649 {
B.getInt32(
I.getAlign().value())});
2650 replaceAllUsesWithAndErase(
B, &
I, NewI);
2655SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2656 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2658 B.SetInsertPoint(&
I);
2661 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2665 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2666 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2667 uint32_t ScSem =
static_cast<uint32_t
>(
2676 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2677 replaceMemInstrUses(&
I, NewI,
B);
2681Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &
I) {
2682 auto Op =
I.getOperation();
2693 B.SetInsertPoint(&
I);
2695 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2696 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2698 uint32_t
Scope =
static_cast<uint32_t
>(
2699 getMemScope(
M->getTargetTriple(),
I.getContext(),
I.getSyncScopeID()));
2700 uint32_t ScSem =
static_cast<uint32_t
>(
2703 M->getTargetTriple(),
2707 ?
"__translate_spirv_atomic_uinc_wrap"
2708 :
"__translate_spirv_atomic_udec_wrap");
2710 Type *ValTy =
I.getValOperand()->getType();
2711 Type *PtrTy =
I.getPointerOperand()->getType();
2713 raw_svector_ostream OS(FuncName);
2714 OS <<
"_p" << AS <<
"_";
2716 OS <<
"v" << VecTy->getNumElements();
2719 Type *Int32Ty =
B.getInt32Ty();
2720 Type *BoolTy =
B.getInt1Ty();
2722 ValTy, BoolTy, BoolTy};
2723 FunctionType *FT = FunctionType::get(ValTy, ArgTys,
false);
2724 FunctionCallee
FC =
M->getOrInsertFunction(FuncName, FT);
2728 I.getPointerOperand(),
B.getInt32(Scope),
2729 B.getInt32(MemSem),
I.getValOperand(),
2730 B.getInt1(
I.isVolatile()),
B.getInt1(
I.isElementwise())};
2731 CallInst *CI =
B.CreateCall(FC, Args);
2737 replaceAllUsesWithAndErase(
B, &
I, CI);
2746 case Intrinsic::spv_abort:
2748 case Intrinsic::trap:
2749 case Intrinsic::ubsantrap:
2751 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2767 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2768 "abort-like call must be the last non-debug instruction before its "
2769 "block's terminator");
2773Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2774 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2778 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2785 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2799 while (!Stack.empty()) {
2800 const Value *V = Stack.pop_back_val();
2801 if (!Visited.
insert(V).second)
2809 Stack.append(
C->user_begin(),
C->user_end());
2825 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2826 if (UserFunctions.contains(
F))
2831 if (!UserFunctions.empty())
2836 const Module &M = *
F->getParent();
2837 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2838 return F == &FirstDefinition;
2841Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2843 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2844 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2846 AggrConstTypes[Leaf] = ElemTy;
2849 SmallVector<Value *, 4> Elems;
2851 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2854 DenseMap<Type *, Instruction *> LeafByType;
2855 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2857 auto &
Entry = LeafByType[ElemTy];
2859 Entry = MakeLeaf(ElemTy);
2863 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2864 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2866 AggrConstTypes[Composite] = AggrTy;
2875void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2880 for (BasicBlock &BB : Func) {
2884 Value *RetVal = RI->getReturnValue();
2891 B.SetInsertPoint(RI);
2894 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2895 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2897 RI->setOperand(0, Rebuilt);
2901void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2911 deduceElementTypeHelper(&GV,
false);
2916 Value *InitOp = Init;
2923 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2924 {
B.getInt32Ty()}, {});
2929 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2934 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2935 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2941 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2947bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2949 bool UnknownElemTypeI8) {
2955 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2962void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2965 static StringMap<unsigned> ResTypeWellKnown = {
2966 {
"async_work_group_copy", WellKnownTypes::Event},
2967 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2968 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2972 bool IsKnown =
false;
2977 std::string DemangledName =
2980 if (DemangledName.length() > 0)
2982 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2983 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2984 if (ResIt != ResTypeWellKnown.
end()) {
2987 switch (ResIt->second) {
2988 case WellKnownTypes::Event:
2991 CanUseAnyVectorRank);
2996 switch (DecorationId) {
2999 case FPDecorationId::SAT:
3002 case FPDecorationId::RTE:
3004 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
3006 case FPDecorationId::RTZ:
3008 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
3010 case FPDecorationId::RTP:
3012 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
3014 case FPDecorationId::RTN:
3016 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
3022 Type *Ty =
I->getType();
3025 Type *TypeToAssign = Ty;
3028 auto It = AggrConstTypes.
find(
II);
3029 if (It == AggrConstTypes.
end())
3031 TypeToAssign = It->second;
3032 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
3033 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
3034 TypeToAssign = It->second;
3036 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
3037 TypeToAssign = It->second;
3041 for (
const auto &
Op :
I->operands()) {
3049 Type *OpTy =
Op->getType();
3051 CallInst *AssignCI =
3056 Type *OpTy =
Op->getType();
3072 Intrinsic::spv_assign_type, {OpTy},
3082bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
3083 Instruction *Inst) {
3085 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3095void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3097 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3099 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3104 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3105 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3106 if (shouldTryToAddMemAliasingDecoration(
I)) {
3107 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3108 ? SPIRV::Decoration::AliasScopeINTEL
3109 : SPIRV::Decoration::NoAliasINTEL;
3111 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3114 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3115 {
I->getType()}, {
Args});
3119 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3120 processMemAliasingDecoration(LLVMContext::MD_noalias);
3123 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3125 bool AllowFPMaxError =
3127 if (!AllowFPMaxError)
3131 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3137 LLVMContext &Ctx =
B.getContext();
3139 B.getInt32Ty(), SPIRV::Decoration::AuxDataInstructionMetadata));
3142 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3144 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3145 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3147 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.remote.memory")}));
3148 if (
I->hasMetadata(LLVMContext::MD_atomic_ignore_denormal_mode))
3150 Ctx, {AuxMD,
MDString::get(Ctx,
"atomic.ignore.denormal.mode")}));
3153 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3162 &FPFastMathDefaultInfoMap,
3164 auto it = FPFastMathDefaultInfoMap.
find(
F);
3165 if (it != FPFastMathDefaultInfoMap.
end())
3173 SPIRV::FPFastMathMode::None);
3175 SPIRV::FPFastMathMode::None);
3177 SPIRV::FPFastMathMode::None);
3178 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3184 size_t BitWidth = Ty->getScalarSizeInBits();
3188 assert(Index >= 0 && Index < 3 &&
3189 "Expected FPFastMathDefaultInfo for half, float, or double");
3190 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3191 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3192 return FPFastMathDefaultInfoVec[Index];
3195void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3197 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3206 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3208 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3216 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3219 [[maybe_unused]] GlobalVariable *GV =
3220 new GlobalVariable(M,
3221 Type::getInt32Ty(
M.getContext()),
3235 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3236 FPFastMathDefaultInfoMap;
3238 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3247 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3249 "Expected 4 operands for FPFastMathDefault");
3255 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3257 SPIRV::FPFastMathDefaultInfo &
Info =
3260 Info.FPFastMathDefault =
true;
3261 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3263 "Expected no operands for ContractionOff");
3267 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3269 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3270 Info.ContractionOff =
true;
3272 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3274 "Expected 1 operand for SignedZeroInfNanPreserve");
3275 unsigned TargetWidth =
3280 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3284 assert(Index >= 0 && Index < 3 &&
3285 "Expected FPFastMathDefaultInfo for half, float, or double");
3286 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3287 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3288 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3292 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3293 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3294 if (FPFastMathDefaultInfoVec.
empty())
3297 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3298 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3301 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3302 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3306 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3308 "and AllowContract");
3310 if (
Info.SignedZeroInfNanPreserve &&
3312 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3313 SPIRV::FPFastMathMode::NSZ))) {
3314 if (
Info.FPFastMathDefault)
3316 "SignedZeroInfNanPreserve but at least one of "
3317 "NotNaN/NotInf/NSZ is enabled.");
3320 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3321 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3322 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3324 "AllowTransform requires AllowReassoc and "
3325 "AllowContract to be set.");
3328 auto it = GlobalVars.
find(Flags);
3329 GlobalVariable *GV =
nullptr;
3330 if (it != GlobalVars.
end()) {
3336 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3339 GV =
new GlobalVariable(M,
3340 Type::getInt32Ty(
M.getContext()),
3345 GlobalVars[
Flags] = GV;
3351void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3354 bool IsConstComposite =
3355 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3356 if (IsConstComposite && TrackConstants) {
3358 auto t = AggrConsts.
find(
I);
3362 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3364 NewOp->setArgOperand(0,
I);
3367 for (
const auto &
Op :
I->operands()) {
3371 unsigned OpNo =
Op.getOperandNo();
3372 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3373 (!
II->isBundleOperand(OpNo) &&
3374 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3378 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3379 :
B.SetInsertPoint(
I);
3382 Type *OpTy =
Op->getType();
3390 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3392 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3393 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3395 SmallVector<Value *, 2>
Args = {
3399 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3405 I->setOperand(OpNo, NewOp);
3411Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3413 SmallPtrSet<Function *, 0> FVisited;
3414 return deduceFunParamElementType(
F, OpIdx, FVisited);
3417Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3418 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3420 if (!FVisited.
insert(
F).second)
3423 SmallPtrSet<Value *, 0> Visited;
3426 for (User *U :
F->users()) {
3428 if (!CI || OpIdx >= CI->
arg_size())
3438 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3441 for (User *OpU : OpArg->
users()) {
3443 if (!Inst || Inst == CI)
3446 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3453 if (FVisited.
find(OuterF) != FVisited.
end())
3455 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3456 if (OuterF->
getArg(i) == OpArg) {
3457 Lookup.push_back(std::make_pair(OuterF, i));
3464 for (
auto &Pair :
Lookup) {
3465 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3472void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3474 B.SetInsertPointPastAllocas(
F);
3475 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3481 for (User *U : Arg->
users()) {
3483 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3501 for (User *U :
F->users()) {
3503 if (!CI || OpIdx >= CI->
arg_size())
3517 for (User *U : Arg->
users()) {
3521 CI->
getParent()->getParent() == CurrF) {
3523 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3535 B.SetInsertPointPastAllocas(
F);
3536 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3541 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3543 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3547 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3559 bool IsNewFTy =
false;
3575bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3578 if (
F.isIntrinsic())
3580 if (
F.isDeclaration()) {
3581 for (User *U :
F.users()) {
3584 UF &&
UF->hasPersonalityFn() &&
UF->getPersonalityFn() == &
F)
3598 for (User *U :
F.users()) {
3600 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3602 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3603 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3611 if (Worklist.
empty())
3614 LLVMContext &Ctx =
M.getContext();
3621 for (
const auto &Arg :
F->args())
3624 IRB.CreateCall(
F, Args);
3626 IRB.CreateRetVoid();
3632void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3633 DenseMap<Function *, CallInst *> Ptrcasts;
3634 for (
auto It : FDeclPtrTys) {
3636 for (
auto *U :
F->users()) {
3641 for (
auto [Idx, ElemTy] : It.second) {
3649 B.SetInsertPointPastAllocas(Arg->
getParent());
3653 }
else if (isaGEP(Param)) {
3654 replaceUsesOfWithSpvPtrcast(
3655 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3664 .getFirstNonPHIOrDbgOrAlloca());
3682 FDeclPtrTys.
clear();
3685GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3686 GetElementPtrInst *
GEP) {
3693 Type *SrcTy =
GEP->getSourceElementType();
3694 SmallVector<Value *, 8> Indices(
GEP->indices());
3696 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3697 Indices.erase(Indices.begin());
3698 SrcTy = ArrTy->getElementType();
3700 GEP->getNoWrapFlags(),
"",
3701 GEP->getIterator());
3706void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3713 if (
ST->canUseExtension(
3714 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3715 for (BasicBlock &BB :
F) {
3717 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3721 SmallVector<unsigned, 1>
Ops =
3723 unsigned LC =
Ops[0];
3724 if (LC == SPIRV::LoopControl::None)
3728 B.SetInsertPoint(Term);
3729 SmallVector<Value *, 4> IntrArgs;
3730 for (
unsigned Op :
Ops)
3732 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3744 SmallPtrSet<BasicBlock *, 8> UsedMergeBlocks;
3751 SmallVector<unsigned, 1> LoopControlOps =
3753 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3766 for (BasicBlock *BB : {Latch, Header}) {
3770 if (!
L->contains(Succ) && !UsedMergeBlocks.
contains(Succ))
3773 if (!MergeBlock || !UsedMergeBlocks.
insert(MergeBlock).second)
3776 B.SetInsertPoint(Header->getTerminator());
3779 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3780 for (
unsigned Imm : LoopControlOps)
3781 Args.emplace_back(
B.getInt32(
Imm));
3782 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3786bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3787 if (
Func.isDeclaration())
3796 GR =
ST.getSPIRVGlobalRegistry();
3800 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3802 CanUseAnyVectorRank =
3803 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3807 AggrConstTypes.
clear();
3810 processParamTypesByFunHeader(CurrF,
B);
3814 SmallPtrSet<Instruction *, 4> DeadInsts;
3817 Type *ElTy =
SI->getValueOperand()->getType();
3832 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3836 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3838 GEP->replaceAllUsesWith(NewGEP);
3842 if (
Type *GepTy = getGEPType(
GEP))
3846 for (
auto *
I : DeadInsts) {
3847 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3848 I->eraseFromParent();
3851 B.SetInsertPoint(
Func.getEntryBlock().begin());
3852 for (
auto &GV :
Func.getParent()->globals())
3853 processGlobalValue(GV,
B);
3855 reconstructAggregateReturns(Func,
B);
3856 preprocessUndefsAndPoisons(
B);
3857 simplifyNullAddrSpaceCasts();
3858 preprocessCompositeConstants(
B);
3866 Type *I32Ty =
B.getInt32Ty();
3871 insertCompositeAggregateArms(&
I,
B);
3872 AggrConstTypes[&
I] =
I.getType();
3873 I.mutateType(I32Ty);
3876 preprocessBoolVectorBitcasts(Func);
3877 SmallVector<Instruction *> Worklist(
3880 applyDemangledPtrArgTypes(
B);
3883 for (
auto &
I : Worklist) {
3885 if (isConvergenceIntrinsic(
I))
3888 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3890 insertAssignTypeIntrs(
I,
B);
3891 insertPtrCastOrAssignTypeInstr(
I,
B);
3896 insertAssignPtrTypeIntrs(
I,
B,
true);
3899 useRoundingMode(FPI,
B);
3904 SmallPtrSet<Instruction *, 4> IncompleteRets;
3906 deduceOperandElementType(&
I, &IncompleteRets);
3910 for (BasicBlock &BB : Func)
3911 for (PHINode &Phi : BB.
phis())
3913 deduceOperandElementType(&Phi,
nullptr);
3915 for (
auto *
I : Worklist) {
3916 TrackConstants =
true;
3926 if (isConvergenceIntrinsic(
I))
3930 processInstrAfterVisit(
I,
B);
3933 emitUnstructuredLoopControls(Func,
B);
3939bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3940 if (!GR || TodoTypeSz == 0)
3943 unsigned SzTodo = TodoTypeSz;
3944 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3951 if (!KnownTy || !AssignCI)
3957 SmallPtrSet<Value *, 0> Visited;
3958 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3959 if (ElemTy != KnownTy) {
3960 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3961 propagateElemType(CI, ElemTy, VisitedSubst);
3968 if (
Op->hasUseList()) {
3969 for (User *U :
Op->users()) {
3976 if (TodoTypeSz == 0)
3981 SmallPtrSet<Instruction *, 4> IncompleteRets;
3983 auto It = ToProcess.
find(&
I);
3984 if (It == ToProcess.
end())
3986 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3987 if (It->second.size() == 0)
3989 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3990 if (TodoTypeSz == 0)
3995 return SzTodo > TodoTypeSz;
4009 .Cases({
"char",
"signed char",
"unsigned char",
"short",
4010 "unsigned short",
"int",
"unsigned int",
"_Float16",
"float",
4018 unsigned NumElts = 0;
4019 if (
Count.getAsInteger(10, NumElts) || NumElts == 0)
4026 TypeStr.
split(Quals,
' ', -1,
false);
4029 if (Qual !=
"const" && Qual !=
"volatile" && Qual !=
"restrict" &&
4030 !(Qual.consume_front(
"AS") && !Qual.getAsInteger(10, AS)))
4037void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
4039 if (!
F.isDeclaration() ||
F.isIntrinsic())
4042 if (DemangledName.empty())
4045 auto Set =
ST.getPreferredInstructionSet();
4046 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(DemangledName, Set);
4048 const bool IsBuiltin = Grp >= 0 || SPIRV::isBuiltin(DemangledName, Set);
4049 if (IsBuiltin && Opcode != SPIRV::OpGroupAsyncCopy)
4051 SmallVector<unsigned> Idxs;
4052 for (Argument &Arg :
F.args())
4057 LLVMContext &Ctx =
F.getContext();
4059 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
4060 if (TypeStrs.
empty())
4063 if (!IsBuiltin && (!
F.getName().starts_with(
"_Z") ||
F.hasStructRetAttr() ||
4064 StringRef(DemangledName).
count(
'(') != 1 ||
4065 StringRef(DemangledName).
count(
')') != 1 ||
4066 StringRef(DemangledName).
contains(
'<') ||
4067 TypeStrs.
size() !=
F.arg_size()))
4069 bool AllowLongVectors =
4070 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
4071 for (
unsigned Idx : Idxs) {
4072 if (Idx >= TypeStrs.
size())
4074 StringRef TypeStr = TypeStrs[
Idx].trim();
4075 Type *ElemTy = IsBuiltin
4076 ? SPIRV::parseBuiltinCallArgumentType(TypeStr, Ctx)
4086 FDeclPtrTys[&
F].emplace_back(Idx, ElemTy);
4088 ST.getSPIRVGlobalRegistry()->addDeducedElementType(
F.getArg(Idx),
4094bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
4095 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
4097 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
4098 if (!
ST.canUseExtension(
4099 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4100 I.getContext().emitError(
4101 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
4105 I.eraseFromParent();
4111 Value *Ptrs =
I.getArgOperand(0);
4113 Value *Passthru =
I.getArgOperand(2);
4116 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
4118 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
4123 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
4125 I.eraseFromParent();
4129 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
4130 if (!
ST.canUseExtension(
4131 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4132 I.getContext().emitError(
4133 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
4136 I.eraseFromParent();
4143 Value *Ptrs =
I.getArgOperand(1);
4148 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
4150 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
4154 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
4155 I.eraseFromParent();
4166void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
4167 struct BoolVecBitcast {
4169 FixedVectorType *BoolVecTy;
4173 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4175 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4183 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4185 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4189 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4191 Value *Src = BC->getOperand(0);
4192 unsigned BoolVecN = BoolVecTy->getNumElements();
4195 Type *OtherTy = SrcIsBoolVec ? BC->getDestTy() : Src->getType();
4196 unsigned NumElts = 1;
4198 NumElts = VTy->getNumElements();
4204 if (!SrcIsBoolVec) {
4207 auto GetLane = [&](
unsigned I) {
4210 Elt =
B.CreateExtractElement(IntVal,
B.getInt32(
I / EltBits));
4214 return B.CreateICmpNE(
And, ConstantInt::get(EltTy, 0));
4222 if (!Idx ||
Idx->getValue().uge(BoolVecN))
4224 B.SetInsertPoint(EE);
4225 EE->replaceAllUsesWith(GetLane(
Idx->getZExtValue()));
4226 EE->eraseFromParent();
4228 if (BC->use_empty()) {
4229 BC->eraseFromParent();
4233 B.SetInsertPoint(BC);
4235 for (
unsigned I = 0;
I < BoolVecN; ++
I)
4236 Result =
B.CreateInsertElement(Result, GetLane(
I),
B.getInt32(
I));
4240 for (
unsigned J = 0; J < NumElts; ++J) {
4241 Value *Elt = ConstantInt::get(EltTy, 0);
4242 for (
unsigned Bit = 0;
Bit < EltBits; ++
Bit) {
4244 B.CreateExtractElement(Src,
B.getInt32(J * EltBits + Bit));
4245 Value *Ext =
B.CreateZExt(Lane, EltTy);
4247 Ext =
B.CreateShl(Ext, ConstantInt::get(EltTy, Bit));
4248 Elt =
B.CreateOr(Elt, Ext);
4250 IntVal = NumElts > 1 ?
B.CreateInsertElement(IntVal, Elt,
B.getInt32(J))
4253 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4256 BC->replaceAllUsesWith(Result);
4257 BC->eraseFromParent();
4261bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4265 if (!
F.isIntrinsic())
4268 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4273 Changed |= processMaskedMemIntrinsic(*
II);
4277 F.eraseFromParent();
4283bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4286 Changed |= convertMaskedMemIntrinsics(M);
4288 parseFunDeclarations(M);
4289 insertConstantsForFPFastMathDefault(M);
4300 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4302 processParamTypes(&
F,
B);
4306 CanTodoType =
false;
4307 Changed |= postprocessTypes(M);
4310 Changed |= processFunctionPointers(M);
4317 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4323 return new SPIRVEmitIntrinsicsLegacy(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void replaceAllUsesWith(Value *Old, Value *New, SmallPtrSet< BasicBlock *, 32 > &FreshBBs, bool IsHuge)
Replace all old uses with new ones, and push the updated BBs into FreshBBs.
static Type * getPointeeType(Value *Ptr, const DataLayout &DL)
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
static bool runOnFunction(Function &F, bool PostInlining)
iv Induction Variable Users
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Machine Check Debug Module
uint64_t IntrinsicInst * II
OptimizedStructLayoutField Field
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrConstForceInt32(const Value *V)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, DenseMap< Function *, SPIRV::FPFastMathDefaultInfoVector > &FPFastMathDefaultInfoMap, Function *F)
static Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static void emitAssignName(Instruction *I, IRBuilder<> &B)
static bool isArtificialGlobal(StringRef Name)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void createRoundingModeDecoration(Instruction *I, unsigned RoundingModeDeco, IRBuilder<> &B)
static void createDecorationIntrinsic(Instruction *I, MDNode *Node, IRBuilder<> &B)
static bool hasOnlyArtificialUses(const GlobalVariable &GV)
static bool isAggregateValueIdInstr(const Instruction &I)
static SPIRV::FPFastMathDefaultInfo & getFPFastMathDefaultInfo(SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty)
static bool isAbortCall(const Instruction &I, const SPIRVSubtarget &ST)
static cl::opt< bool > SpirvEmitOpNames("spirv-emit-op-names", cl::desc("Emit OpName for all instructions"), cl::init(false))
static bool tracesToPointerAlloca(Value *V)
static bool isUseListGlobal(StringRef Name)
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool isSpvAggrPlaceholder(const Value *V)
static bool precededByAbortIntrinsic(const UnreachableInst &I, const SPIRVSubtarget &ST)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static bool isMultiRegisterAggregate(Value *V)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static Type * parseDeclPtrElemType(StringRef TypeStr, LLVMContext &Ctx)
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)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the SmallPtrSet class.
This file defines the SmallString class.
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
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
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
@ UIncWrap
Increment one up to a maximum value.
@ UDecWrap
Decrement one until a minimum value or zero.
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.
void setCallingConv(CallingConv::ID CC)
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI std::optional< RoundingMode > getRoundingMode() const
uint64_t getNumOperands() const
unsigned getProgramAddressSpace() const
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
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()
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Module * getParent()
Get the module that this global value is contained inside of...
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 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()
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
static unsigned getPointerOperandIndex()
SmallVector< LoopT *, 4 > getLoopsInPreorder() const
Return all of the loops in the function in preorder across the loop nests, with siblings in forward p...
void analyze(ParentT F)
Create the loop forest for a function.
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Flags
Flags values. These may be or'd together.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg, bool CanUseAnyVectorRank)
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)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
iterator find(ConstPtrType Ptr) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator find(StringRef Key)
Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
Check if the string is empty.
constexpr size_t size() const
Get the string size.
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
A switch()-like statement whose cases are string literals.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
const Triple & getTargetTriple() const
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
VendorType getVendor() const
Get the parsed vendor type of this triple.
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.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
This function has undefined behavior.
void setOperand(unsigned i, Value *Val)
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
iterator_range< use_iterator > uses()
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
const ParentTy * getParent() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ SPIR_KERNEL
Used for SPIR kernel functions.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
auto m_Value()
Match an arbitrary value and ignore it.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
std::string lookupBuiltinNameHelper(StringRef DemangledCall, FPDecorationId *DecorationId)
Parses the name part of the demangled builtin call.
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
unsigned getNumElements(Type *Ty)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
ModulePass * createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
RelativeUniformCounterPtr Values
uint32_t getMemSemanticsWithStorageClass(const Triple &TT, uint32_t OrderSem, uint32_t StorageClassSem)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
bool isUntypedPointerVectorTy(const Type *T)
bool isLongVectorEXT(const Type *Ty)
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...
bool sortBlocks(Function &F)
bool isa_and_nonnull(const Y &Val)
SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx, SyncScope::ID Id)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
bool isNestedPointer(const Type *Ty)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
Type * normalizeType(Type *Ty, bool CanUseAnyVectorRank)
auto reverse(ContainerTy &&C)
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
bool spirvPreserveAuxData(const Triple &TT)
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.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
@ Ref
The access may reference the value stored in memory.
@ And
Bitwise or logical AND of integers.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Type * parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx)
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)
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 CanUseAnyVectorRank)
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)