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()->getFirstNonPHIOrAlloca());
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();
598Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
599 bool UnknownElemTypeI8,
600 bool IsPostprocessing) {
604 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
618 if (UnknownElemTypeI8) {
619 if (!IsPostprocessing)
635 B.SetInsertPointPastAllocas(OpA->getParent());
638 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrAlloca());
640 Type *OpTy =
Op->getType();
642 SmallVector<Value *, 2>
Args = {
645 CallInst *PtrCasted =
646 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
651void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
653 DenseMap<Function *, CallInst *> Ptrcasts) {
655 CallInst *PtrCastedI =
nullptr;
656 auto It = Ptrcasts.
find(
F);
657 if (It == Ptrcasts.
end()) {
658 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
659 Ptrcasts[
F] = PtrCastedI;
661 PtrCastedI = It->second;
663 I->replaceUsesOfWith(
Op, PtrCastedI);
666void SPIRVEmitIntrinsicsImpl::propagateElemType(
668 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
669 DenseMap<Function *, CallInst *> Ptrcasts;
671 for (
auto *U :
Users) {
674 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
679 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
680 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
684void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
686 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
687 SmallPtrSet<Value *, 0> Visited;
688 DenseMap<Function *, CallInst *> Ptrcasts;
689 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
690 std::move(Ptrcasts));
693void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
695 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
696 SmallPtrSetImpl<Value *> &Visited,
697 DenseMap<Function *, CallInst *> Ptrcasts) {
701 for (
auto *U :
Users) {
704 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
709 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
710 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
717Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
718 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
719 SmallPtrSet<Value *, 0> Visited;
720 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
724Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
725 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
726 bool UnknownElemTypeI8, std::optional<unsigned> AddrSpace) {
731 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
733 NestedTy, AddrSpace.value_or(PtrTy->getAddressSpace()));
743Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
744 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
756 for (User *OpU :
Op->users()) {
758 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
770 Function *CalledF,
unsigned OpIdx) {
776 if (Name ==
"printf" || Name ==
"get_fence")
784Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
785 bool UnknownElemTypeI8) {
786 SmallPtrSet<Value *, 0> Visited;
787 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
790void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
792 bool UnknownElemTypeI8) {
794 if (!UnknownElemTypeI8)
803bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
805 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
812 if (
ST->getNumElements() == 0)
814 CurType =
ST->getElementType(0);
815 OnLiteralIndexing(CurType, 0);
823 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
824 return AT ==
nullptr;
827bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
829 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing) {
834 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
838 CurType = AT->getElementType();
839 OnLiteralIndexing(CurType, Index);
841 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
844 const auto &STL =
DL.getStructLayout(ST);
845 unsigned Element = STL->getElementContainingOffset(
Offset);
846 Offset -= STL->getElementOffset(Element);
847 CurType =
ST->getElementType(Element);
848 OnLiteralIndexing(CurType, Element);
850 Type *EltTy = VT->getElementType();
851 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
852 assert(EltSizeBits % 8 == 0 &&
853 "Element type size in bits must be a multiple of 8.");
854 uint32_t EltTypeSize = EltSizeBits / 8;
859 OnLiteralIndexing(CurType, Index);
869bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
870 GetElementPtrInst &
GEP,
871 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
875 std::optional<uint64_t> MultiplierOpt =
876 getByteAddressingMultiplier(
GEP.getSourceElementType());
877 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
878 uint64_t Multiplier = *MultiplierOpt;
881 Value *Src = getPointerRoot(
GEP.getPointerOperand());
882 Type *CurType = deduceElementType(Src,
true);
886 return walkLogicalAccessChainConstant(
887 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
889 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
890 OnLiteralIndexing, OnDynamicIndexing);
893Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
894 GetElementPtrInst &
GEP) {
897 B.SetInsertPoint(&
GEP);
899 std::vector<Value *> Indices;
900 Indices.push_back(ConstantInt::get(
901 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
902 walkLogicalAccessChain(
906 ConstantInt::get(
B.getInt64Ty(), Index,
false));
911 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
913 if (Multiplier == EltTypeSize) {
915 }
else if (EltTypeSize % Multiplier == 0) {
918 EltTypeSize / Multiplier,
922 ConstantInt::get(
Offset->getType(), Multiplier,
925 Index =
B.CreateUDiv(Index,
926 ConstantInt::get(
Offset->getType(), EltTypeSize,
930 Indices.push_back(Index);
934 SmallVector<Value *, 4>
Args;
935 Args.push_back(
B.getInt1(
GEP.isInBounds()));
936 Args.push_back(
GEP.getOperand(0));
939 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
940 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
944Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
946 Type *CurType =
GEP->getResultElementType();
948 bool Interrupted = walkLogicalAccessChain(
949 *
GEP, [&CurType](
Type *EltType,
uint64_t Index) { CurType = EltType; },
952 return Interrupted ?
GEP->getResultElementType() : CurType;
955Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
956 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
958 return getGEPTypeLogical(
Ref);
965 Ty =
Ref->getSourceElementType();
969 Ty =
Ref->getResultElementType();
974Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
975 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
976 bool IgnoreKnownType) {
982 if (!IgnoreKnownType)
994 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
996 Ty = getGEPType(
Ref);
998 Ty = SGEP->getResultElementType();
1003 KnownTy =
Op->getType();
1005 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
1008 Ty = SPIRV::getOriginalFunctionType(*Fn);
1015 std::optional<unsigned> ProgramAS;
1020 SPIRV::Extension::SPV_INTEL_function_pointers))
1024 Ty = deduceElementTypeByValueDeep(
Ref->getValueType(),
Op, Visited,
1025 UnknownElemTypeI8, ProgramAS);
1028 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
1030 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1032 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1034 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1036 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1042 reconstructType(
Ref->getAggregateOperand(),
false,
false),
1047 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1051 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1053 Type *BestTy =
nullptr;
1055 DenseMap<Type *, unsigned> PhiTys;
1056 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1057 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1064 if (It.first->second > MaxN) {
1065 MaxN = It.first->second;
1073 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1077 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1078 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1083 static StringMap<unsigned> ResTypeByArg = {
1089 {
"__to_private", 0},
1090 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1091 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1092 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1093 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1094 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1095 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1099 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1100 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1102 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1103 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1104 for (User *U :
II->users()) {
1109 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1111 Ty = HandleType->getTypeParameter(0);
1112 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1126 }
else if (
II &&
II->getIntrinsicID() ==
1127 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1131 std::string DemangledName =
1133 if (DemangledName.length() > 0)
1134 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1135 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1136 if (AsArgIt != ResTypeByArg.
end())
1137 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1138 Visited, UnknownElemTypeI8);
1145 if (Ty && !IgnoreKnownType) {
1156Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1157 bool UnknownElemTypeI8) {
1158 SmallPtrSet<Value *, 0> Visited;
1159 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1162Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1163 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1164 bool UnknownElemTypeI8) {
1173 if (!Visited.
insert(U).second)
1178 bool Change =
false;
1179 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1181 assert(
Op &&
"Operands should not be null.");
1182 Type *OpTy =
Op->getType();
1185 if (
Type *NestedTy =
1186 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1193 Change |= Ty != OpTy;
1197 Tys, OrigStructTy->isLiteral() ?
"" : OrigStructTy->getName(),
1198 OrigStructTy->isPacked());
1203 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1204 Type *OpTy = ArrTy->getElementType();
1207 if (
Type *NestedTy =
1208 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1215 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1221 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1222 Type *OpTy = VecTy->getElementType();
1225 if (
Type *NestedTy =
1226 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1233 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1244Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1245 bool UnknownElemTypeI8) {
1246 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1248 if (!UnknownElemTypeI8)
1251 return IntegerType::getInt8Ty(
I->getContext());
1255 Value *PointerOperand) {
1261 return I->getType();
1269bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1271 Type *&KnownElemTy,
bool &Incomplete) {
1275 std::string DemangledName =
1277 if (DemangledName.length() > 0 &&
1279 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1280 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1281 DemangledName,
ST.getPreferredInstructionSet());
1282 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1283 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1289 KnownElemTy = ElemTy;
1290 Ops.push_back(std::make_pair(
Op, i));
1292 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1299 case SPIRV::OpAtomicFAddEXT:
1300 case SPIRV::OpAtomicFMinEXT:
1301 case SPIRV::OpAtomicFMaxEXT:
1302 case SPIRV::OpAtomicLoad:
1303 case SPIRV::OpAtomicCompareExchangeWeak:
1304 case SPIRV::OpAtomicCompareExchange:
1305 case SPIRV::OpAtomicExchange:
1306 case SPIRV::OpAtomicIAdd:
1307 case SPIRV::OpAtomicISub:
1308 case SPIRV::OpAtomicOr:
1309 case SPIRV::OpAtomicXor:
1310 case SPIRV::OpAtomicAnd:
1311 case SPIRV::OpAtomicUMin:
1312 case SPIRV::OpAtomicUMax:
1313 case SPIRV::OpAtomicSMin:
1314 case SPIRV::OpAtomicSMax: {
1319 Incomplete = isTodoType(
Op);
1320 Ops.push_back(std::make_pair(
Op, 0));
1322 case SPIRV::OpAtomicStore: {
1331 Incomplete = isTodoType(
Op);
1332 Ops.push_back(std::make_pair(
Op, 0));
1341void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1343 Type *&KnownElemTy,
bool IsPostprocessing) {
1347 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1348 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1349 bool IsNewFTy =
false, IsIncomplete =
false;
1352 Type *ArgTy = Arg->getType();
1357 if (isTodoType(Arg))
1358 IsIncomplete =
true;
1360 IsIncomplete =
true;
1363 ArgTy = FTy->getFunctionParamType(ParmIdx);
1367 Type *RetTy = FTy->getReturnType();
1374 IsIncomplete =
true;
1376 IsIncomplete =
true;
1379 if (!IsPostprocessing && IsIncomplete)
1382 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1385bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1386 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1387 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1399 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1400 for (User *U :
F->users()) {
1409 propagateElemType(CI, PrevElemTy, VisitedSubst);
1419 for (Instruction *IncompleteRetI : *IncompleteRets)
1420 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1422 }
else if (IncompleteRets) {
1433void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1434 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1435 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1437 Type *KnownElemTy =
nullptr;
1438 bool Incomplete =
false;
1444 Incomplete = isTodoType(
I);
1445 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1448 Ops.push_back(std::make_pair(
Op, i));
1454 Incomplete = isTodoType(
I);
1455 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1462 Incomplete = isTodoType(
I);
1463 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1467 KnownElemTy =
Ref->getSourceElementType();
1468 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1473 KnownElemTy =
Ref->getBaseType();
1474 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1477 KnownElemTy =
I->getType();
1484 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1493 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1497 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1502 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1510 Incomplete = isTodoType(
Ref->getPointerOperand());
1511 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1519 Incomplete = isTodoType(
Ref->getPointerOperand());
1520 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1526 Incomplete = isTodoType(
I);
1527 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1530 Ops.push_back(std::make_pair(
Op, i));
1538 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1539 IsPostprocessing, KnownElemTy,
Op,
1542 Incomplete = isTodoType(CurrF);
1543 Ops.push_back(std::make_pair(
Op, 0));
1549 bool Incomplete0 = isTodoType(Op0);
1550 bool Incomplete1 = isTodoType(Op1);
1552 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1554 : GR->findDeducedElementType(Op0);
1556 KnownElemTy = ElemTy0;
1557 Incomplete = Incomplete0;
1558 Ops.push_back(std::make_pair(Op1, 1));
1559 }
else if (ElemTy1) {
1560 KnownElemTy = ElemTy1;
1561 Incomplete = Incomplete1;
1562 Ops.push_back(std::make_pair(Op0, 0));
1566 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1567 else if (HaveFunPtrs)
1568 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1573 if (!KnownElemTy ||
Ops.size() == 0)
1577 for (
auto &OpIt :
Ops) {
1581 Type *AskTy =
nullptr;
1582 CallInst *AskCI =
nullptr;
1583 if (IsPostprocessing && AskOps) {
1589 if (Ty == KnownElemTy)
1592 Type *OpTy =
Op->getType();
1598 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1606 else if (!IsPostprocessing)
1610 if (AssignCI ==
nullptr) {
1619 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1620 std::make_pair(
I,
Op)};
1621 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1625 CallInst *PtrCastI =
1626 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1627 if (OpIt.second == std::numeric_limits<unsigned>::max())
1630 I->setOperand(OpIt.second, PtrCastI);
1636void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1641 if (isAssignTypeInstr(U)) {
1642 B.SetInsertPoint(U);
1643 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1644 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1645 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1647 U->eraseFromParent();
1650 U->replaceUsesOfWith(Old, New);
1658 Type *NewArgTy =
New->getType();
1660 if (NewArgTy != ExpectedArgTy) {
1663 M, Intrinsic::spv_abort, {NewArgTy});
1673 "aggregate PHI/select/freeze should have been mutated to value-id "
1675 U->replaceUsesOfWith(Old, New);
1680 New->copyMetadata(*Old);
1686 bool HasPoisonExt) {
1693 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1694 "lowered as undef\n");
1696 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1697 Type *Ty = UV->getType();
1703 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1704 :
B.CreateIntrinsicWithoutFolding(IID, {});
1705 AggrConsts[
Call] = UV;
1706 AggrConstTypes[
Call] = Ty;
1711 return B.CreateIntrinsic(IID, {Ty}, {});
1718void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1723 SmallVector<Instruction *, 16> Insts;
1727 for (Instruction *
I : Insts) {
1728 bool BPrepared =
false;
1730 for (
unsigned Idx = 0;
Idx <
I->getNumOperands(); ++
Idx) {
1734 bool IsScalar = !
Op->getType()->isAggregateType();
1737 if (IsScalar && !AsPoison)
1741 if (IsScalar && Phi)
1742 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1743 else if (!BPrepared) {
1747 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1748 I->setOperand(Idx, Repl);
1757void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1761 ASC->replaceAllUsesWith(
1763 ASC->eraseFromParent();
1771 if (!V->getType()->isAggregateType())
1780 I.getType()->isAggregateType();
1786void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1789 for (Use &U :
I->operands()) {
1796 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1801 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1803 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1809void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1813 std::queue<Instruction *> Worklist;
1817 while (!Worklist.empty()) {
1818 auto *
I = Worklist.front();
1821 bool KeepInst =
false;
1822 for (
const auto &
Op :
I->operands()) {
1824 Type *ResTy =
nullptr;
1827 ResTy = COp->getType();
1839 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1842 auto PrepareInsert = [&]() {
1845 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1846 :
B.SetInsertPoint(
I);
1851 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1852 Args.push_back(COp->getElementAsConstant(i));
1858 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1867 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1873 auto *CI =
B.CreateIntrinsicWithoutFolding(
1874 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1878 AggrConsts[CI] = AggrConst;
1879 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1891 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1896 unsigned RoundingModeDeco,
1903 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1912 MDNode *SaturatedConversionNode =
1914 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1934 MDString *ConstraintString =
1939 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1943 B.SetInsertPoint(&
Call);
1944 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1949void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1952 if (!
RM.has_value())
1954 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1955 switch (
RM.value()) {
1959 case RoundingMode::NearestTiesToEven:
1960 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1962 case RoundingMode::TowardNegative:
1963 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1965 case RoundingMode::TowardPositive:
1966 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1968 case RoundingMode::TowardZero:
1969 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1971 case RoundingMode::Dynamic:
1972 case RoundingMode::NearestTiesToAway:
1976 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1982Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1986 B.SetInsertPoint(&
I);
1987 SmallVector<Value *, 4>
Args;
1989 Args.push_back(
I.getCondition());
1992 for (
auto &Case :
I.cases()) {
1993 Args.push_back(Case.getCaseValue());
1994 BBCases.
push_back(Case.getCaseSuccessor());
1997 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1998 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
2002 I.eraseFromParent();
2005 B.SetInsertPoint(ParentBB);
2006 IndirectBrInst *BrI =
B.CreateIndirectBr(
2009 for (BasicBlock *BBCase : BBCases)
2018Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
2024 B.SetInsertPoint(&
I);
2026 SmallVector<Value *, 4>
Args;
2027 Args.push_back(
B.getInt1(
true));
2028 Args.push_back(
I.getOperand(0));
2029 Args.push_back(
B.getInt32(0));
2030 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
2031 Args.push_back(SGEP->getIndexOperand(J));
2034 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
2035 replaceAllUsesWithAndErase(
B, &
I, NewI);
2040SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2042 B.SetInsertPoint(&
I);
2047 unsigned N = RetVTy->getNumElements();
2048 Value *PtrOp =
I.getPointerOperand();
2050 Type *ResultPtrTy = RetVTy->getElementType();
2053 Value *InBounds =
B.getInt1(
I.isInBounds());
2054 Type *LanePointeeTy = getGEPType(&
I);
2055 Type *SrcElemTy =
I.getSourceElementType();
2064 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2065 Value *LaneIdx =
B.getInt32(Lane);
2066 Value *ScalarPtr = PtrOp;
2070 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2074 SmallVector<Value *, 4>
Args;
2075 Args.push_back(InBounds);
2076 Args.push_back(ScalarPtr);
2077 for (
Value *Idx :
I.indices()) {
2085 Args.push_back(visitExtractElementInst(*EI));
2089 Args.push_back(Idx);
2092 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2094 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2098 replaceAllUsesWithAndErase(
B, &
I, NewI);
2116 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2117 return buildLogicalAccessChainFromGEP(
I);
2122 Value *PtrOp =
I.getPointerOperand();
2123 Type *SrcElemTy =
I.getSourceElementType();
2124 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2127 if (ArrTy->getElementType() == SrcElemTy) {
2129 Type *FirstIdxType =
I.getOperand(1)->getType();
2130 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2131 for (
Value *Idx :
I.indices())
2135 SmallVector<Value *, 4>
Args;
2136 Args.push_back(
B.getInt1(
I.isInBounds()));
2137 Args.push_back(
I.getPointerOperand());
2140 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2142 replaceAllUsesWithAndErase(
B, &
I, NewI);
2149 SmallVector<Value *, 4>
Args;
2150 Args.push_back(
B.getInt1(
I.isInBounds()));
2153 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2154 replaceAllUsesWithAndErase(
B, &
I, NewI);
2158Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2160 B.SetInsertPoint(&
I);
2169 I.eraseFromParent();
2176 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2177 replaceAllUsesWithAndErase(
B, &
I, NewI);
2181void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2183 Type *VTy =
V->getType();
2188 if (ElemTy != AssignedType)
2201 if (CurrentType == AssignedType)
2208 " for value " +
V->getName(),
2217void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2218 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2223 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2224 if (PointerElemTy == ExpectedElementType ||
2229 Value *ExpectedElementVal =
2231 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2233 bool FirstPtrCastOrAssignPtrType =
true;
2239 for (
auto User :
Pointer->users()) {
2242 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2243 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2244 II->getOperand(0) != Pointer)
2249 FirstPtrCastOrAssignPtrType =
false;
2250 if (
II->getOperand(1) != VMD ||
2257 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2262 if (
II->getParent() !=
I->getParent())
2265 I->setOperand(OperandToReplace,
II);
2280 if (FirstPtrCastOrAssignPtrType) {
2285 }
else if (isTodoType(Pointer)) {
2286 eraseTodoType(Pointer);
2294 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2295 std::make_pair(
I, Pointer)};
2297 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2310 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
2316void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2321 replacePointerOperandWithPtrCast(
2322 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2328 Type *OpTy =
Op->getType();
2331 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2334 if (OpTy ==
Op->getType())
2335 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2336 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2341 Type *OpTy = LI->getType();
2352 Type *NewOpTy = OpTy;
2353 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2354 if (OpTy == NewOpTy)
2355 insertTodoType(Pointer);
2358 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2363 Type *OpTy =
nullptr;
2375 OpTy = GEPI->getSourceElementType();
2377 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2379 insertTodoType(Pointer);
2385 Value *
Op = IVI->getInsertedValueOperand();
2387 replacePointerOperandWithPtrCast(
2401 std::string DemangledName =
2405 bool HaveTypes =
false;
2406 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2424 for (User *U : CalledArg->
users()) {
2426 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2432 HaveTypes |= ElemTy !=
nullptr;
2437 if (DemangledName.empty() && !HaveTypes)
2441 TM.
getSubtarget<SPIRVSubtarget>(*CalledF).getPreferredInstructionSet();
2443 bool ParseBuiltinTypes =
2444 !DemangledName.empty() &&
2445 (!CalledF->
isDeclaration() || SPIRV::isBuiltin(DemangledName, Set));
2446 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2461 Type *ExpectedType =
2462 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2463 if (!ExpectedType && ParseBuiltinTypes)
2464 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2465 DemangledName, OpIdx,
I->getContext());
2466 if (!ExpectedType || ExpectedType->
isVoidTy())
2474 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2479SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2482 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2486 I.getOperand(1)->getType(),
2487 I.getOperand(2)->getType()};
2489 B.SetInsertPoint(&
I);
2491 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2493 replaceAllUsesWithAndErase(
B, &
I, NewI);
2498SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2501 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2505 B.SetInsertPoint(&
I);
2507 I.getIndexOperand()->getType()};
2508 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2509 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2511 replaceAllUsesWithAndErase(
B, &
I, NewI);
2515Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2517 B.SetInsertPoint(&
I);
2520 Value *AggregateOp =
I.getAggregateOperand();
2524 Args.push_back(AggregateOp);
2525 Args.push_back(
I.getInsertedValueOperand());
2526 for (
auto &
Op :
I.indices())
2527 Args.push_back(
B.getInt32(
Op));
2529 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2530 replaceMemInstrUses(&
I, NewI,
B);
2535SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2537 B.SetInsertPoint(&
I);
2538 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2547 for (
auto &
Op :
I.indices())
2548 Args.push_back(
B.getInt32(
Op));
2549 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2550 {
I.getType()}, {
Args});
2556 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2557 AggrConstTypes[NewI] =
I.getType();
2559 replaceMemInstrUses(&
I, NewI,
B);
2562 replaceAllUsesWithAndErase(
B, &
I, NewI);
2566 for (
const Use &U : NewI->
uses()) {
2567 User *Usr =
U.getUser();
2569 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2580 if (ArgNo < FT->getNumParams() &&
2581 !FT->getParamType(ArgNo)->isAggregateType()) {
2590Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2591 if (!
I.getType()->isAggregateType())
2594 B.SetInsertPoint(&
I);
2595 TrackConstants =
false;
2600 unsigned IntrinsicId;
2601 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2602 if (!
I.isAtomic()) {
2603 IntrinsicId = Intrinsic::spv_load;
2604 Args.push_back(
B.getInt32(
I.getAlign().value()));
2606 IntrinsicId = Intrinsic::spv_atomic_load;
2607 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2609 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2610 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2612 replaceMemInstrUses(&
I, NewI,
B);
2616Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2620 B.SetInsertPoint(&
I);
2621 TrackConstants =
false;
2625 auto *PtrOp =
I.getPointerOperand();
2627 if (
I.getValueOperand()->getType()->isAggregateType()) {
2635 "Unexpected argument of aggregate type, should be spv_extractv!");
2639 unsigned IntrinsicId;
2640 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2642 if (!
I.isAtomic()) {
2643 IntrinsicId = Intrinsic::spv_store;
2644 Args.push_back(
B.getInt32(
I.getAlign().value()));
2646 IntrinsicId = Intrinsic::spv_atomic_store;
2647 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2650 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2652 I.eraseFromParent();
2656Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2657 Value *ArraySize =
nullptr;
2658 if (
I.isArrayAllocation()) {
2661 SPIRV::Extension::SPV_INTEL_variable_length_array))
2663 "array allocation: this instruction requires the following "
2664 "SPIR-V extension: SPV_INTEL_variable_length_array",
2666 ArraySize =
I.getArraySize();
2669 B.SetInsertPoint(&
I);
2670 TrackConstants =
false;
2671 Type *PtrTy =
I.getType();
2674 ?
B.CreateIntrinsicWithoutFolding(
2675 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2676 {ArraySize,
B.getInt32(
I.getAlign().value())})
2677 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2678 {
B.getInt32(
I.getAlign().value())});
2679 replaceAllUsesWithAndErase(
B, &
I, NewI);
2684SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2685 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2687 B.SetInsertPoint(&
I);
2690 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2694 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2695 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2696 uint32_t ScSem =
static_cast<uint32_t
>(
2705 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2706 replaceMemInstrUses(&
I, NewI,
B);
2710Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &
I) {
2711 auto Op =
I.getOperation();
2722 B.SetInsertPoint(&
I);
2724 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2725 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2727 uint32_t
Scope =
static_cast<uint32_t
>(
2728 getMemScope(
M->getTargetTriple(),
I.getContext(),
I.getSyncScopeID()));
2729 uint32_t ScSem =
static_cast<uint32_t
>(
2732 M->getTargetTriple(),
2736 ?
"__translate_spirv_atomic_uinc_wrap"
2737 :
"__translate_spirv_atomic_udec_wrap");
2739 Type *ValTy =
I.getValOperand()->getType();
2740 Type *PtrTy =
I.getPointerOperand()->getType();
2742 raw_svector_ostream OS(FuncName);
2743 OS <<
"_p" << AS <<
"_";
2745 OS <<
"v" << VecTy->getNumElements();
2748 Type *Int32Ty =
B.getInt32Ty();
2749 Type *BoolTy =
B.getInt1Ty();
2751 ValTy, BoolTy, BoolTy};
2752 FunctionType *FT = FunctionType::get(ValTy, ArgTys,
false);
2753 FunctionCallee
FC =
M->getOrInsertFunction(FuncName, FT);
2757 I.getPointerOperand(),
B.getInt32(Scope),
2758 B.getInt32(MemSem),
I.getValOperand(),
2759 B.getInt1(
I.isVolatile()),
B.getInt1(
I.isElementwise())};
2760 CallInst *CI =
B.CreateCall(FC, Args);
2766 replaceAllUsesWithAndErase(
B, &
I, CI);
2775 case Intrinsic::spv_abort:
2777 case Intrinsic::trap:
2778 case Intrinsic::ubsantrap:
2780 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2796 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2797 "abort-like call must be the last non-debug instruction before its "
2798 "block's terminator");
2802Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2803 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2807 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2814 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2828 while (!Stack.empty()) {
2829 const Value *V = Stack.pop_back_val();
2830 if (!Visited.
insert(V).second)
2838 Stack.append(
C->user_begin(),
C->user_end());
2854 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2855 if (UserFunctions.contains(
F))
2860 if (!UserFunctions.empty())
2865 const Module &M = *
F->getParent();
2866 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2867 return F == &FirstDefinition;
2870Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2872 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2873 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2875 AggrConstTypes[Leaf] = ElemTy;
2878 SmallVector<Value *, 4> Elems;
2880 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2883 DenseMap<Type *, Instruction *> LeafByType;
2884 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2886 auto &
Entry = LeafByType[ElemTy];
2888 Entry = MakeLeaf(ElemTy);
2892 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2893 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2895 AggrConstTypes[Composite] = AggrTy;
2904void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2909 for (BasicBlock &BB : Func) {
2913 Value *RetVal = RI->getReturnValue();
2920 B.SetInsertPoint(RI);
2923 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2924 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2926 RI->setOperand(0, Rebuilt);
2930void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2940 deduceElementTypeHelper(&GV,
false);
2945 Value *InitOp = Init;
2952 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2953 {
B.getInt32Ty()}, {});
2958 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2963 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2964 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2970 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2976bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2978 bool UnknownElemTypeI8) {
2984 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2991void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2994 static StringMap<unsigned> ResTypeWellKnown = {
2995 {
"async_work_group_copy", WellKnownTypes::Event},
2996 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2997 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
3001 bool IsKnown =
false;
3006 std::string DemangledName =
3009 if (DemangledName.length() > 0)
3011 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
3012 auto ResIt = ResTypeWellKnown.
find(DemangledName);
3013 if (ResIt != ResTypeWellKnown.
end()) {
3016 switch (ResIt->second) {
3017 case WellKnownTypes::Event:
3020 CanUseAnyVectorRank);
3025 switch (DecorationId) {
3028 case FPDecorationId::SAT:
3031 case FPDecorationId::RTE:
3033 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
3035 case FPDecorationId::RTZ:
3037 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
3039 case FPDecorationId::RTP:
3041 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
3043 case FPDecorationId::RTN:
3045 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
3051 Type *Ty =
I->getType();
3054 Type *TypeToAssign = Ty;
3057 auto It = AggrConstTypes.
find(
II);
3058 if (It == AggrConstTypes.
end())
3060 TypeToAssign = It->second;
3061 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
3062 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
3063 TypeToAssign = It->second;
3065 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
3066 TypeToAssign = It->second;
3070 for (
const auto &
Op :
I->operands()) {
3078 Type *OpTy =
Op->getType();
3080 CallInst *AssignCI =
3085 Type *OpTy =
Op->getType();
3101 Intrinsic::spv_assign_type, {OpTy},
3111bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
3112 Instruction *Inst) {
3114 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3124void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3126 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3128 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3133 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3134 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3135 if (shouldTryToAddMemAliasingDecoration(
I)) {
3136 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3137 ? SPIRV::Decoration::AliasScopeINTEL
3138 : SPIRV::Decoration::NoAliasINTEL;
3140 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3143 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3144 {
I->getType()}, {
Args});
3148 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3149 processMemAliasingDecoration(LLVMContext::MD_noalias);
3152 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3154 bool AllowFPMaxError =
3156 if (!AllowFPMaxError)
3160 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3166 LLVMContext &Ctx =
B.getContext();
3168 B.getInt32Ty(), SPIRV::Decoration::AuxDataInstructionMetadata));
3171 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3173 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3174 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3176 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.remote.memory")}));
3177 if (
I->hasMetadata(LLVMContext::MD_atomic_ignore_denormal_mode))
3179 Ctx, {AuxMD,
MDString::get(Ctx,
"atomic.ignore.denormal.mode")}));
3182 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3191 &FPFastMathDefaultInfoMap,
3193 auto it = FPFastMathDefaultInfoMap.
find(
F);
3194 if (it != FPFastMathDefaultInfoMap.
end())
3202 SPIRV::FPFastMathMode::None);
3204 SPIRV::FPFastMathMode::None);
3206 SPIRV::FPFastMathMode::None);
3207 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3213 size_t BitWidth = Ty->getScalarSizeInBits();
3217 assert(Index >= 0 && Index < 3 &&
3218 "Expected FPFastMathDefaultInfo for half, float, or double");
3219 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3220 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3221 return FPFastMathDefaultInfoVec[Index];
3224void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3226 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3235 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3237 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3245 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3248 [[maybe_unused]] GlobalVariable *GV =
3249 new GlobalVariable(M,
3250 Type::getInt32Ty(
M.getContext()),
3264 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3265 FPFastMathDefaultInfoMap;
3267 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3276 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3278 "Expected 4 operands for FPFastMathDefault");
3284 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3286 SPIRV::FPFastMathDefaultInfo &
Info =
3289 Info.FPFastMathDefault =
true;
3290 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3292 "Expected no operands for ContractionOff");
3296 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3298 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3299 Info.ContractionOff =
true;
3301 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3303 "Expected 1 operand for SignedZeroInfNanPreserve");
3304 unsigned TargetWidth =
3309 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3313 assert(Index >= 0 && Index < 3 &&
3314 "Expected FPFastMathDefaultInfo for half, float, or double");
3315 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3316 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3317 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3321 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3322 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3323 if (FPFastMathDefaultInfoVec.
empty())
3326 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3327 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3330 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3331 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3335 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3337 "and AllowContract");
3339 if (
Info.SignedZeroInfNanPreserve &&
3341 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3342 SPIRV::FPFastMathMode::NSZ))) {
3343 if (
Info.FPFastMathDefault)
3345 "SignedZeroInfNanPreserve but at least one of "
3346 "NotNaN/NotInf/NSZ is enabled.");
3349 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3350 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3351 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3353 "AllowTransform requires AllowReassoc and "
3354 "AllowContract to be set.");
3357 auto it = GlobalVars.
find(Flags);
3358 GlobalVariable *GV =
nullptr;
3359 if (it != GlobalVars.
end()) {
3365 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3368 GV =
new GlobalVariable(M,
3369 Type::getInt32Ty(
M.getContext()),
3374 GlobalVars[
Flags] = GV;
3380void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3383 bool IsConstComposite =
3384 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3385 if (IsConstComposite && TrackConstants) {
3387 auto t = AggrConsts.
find(
I);
3391 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3393 NewOp->setArgOperand(0,
I);
3396 for (
const auto &
Op :
I->operands()) {
3400 unsigned OpNo =
Op.getOperandNo();
3401 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3402 (!
II->isBundleOperand(OpNo) &&
3403 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3407 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3408 :
B.SetInsertPoint(
I);
3411 Type *OpTy =
Op->getType();
3419 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3421 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3422 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3424 SmallVector<Value *, 2>
Args = {
3428 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3434 I->setOperand(OpNo, NewOp);
3440Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3442 SmallPtrSet<Function *, 0> FVisited;
3443 return deduceFunParamElementType(
F, OpIdx, FVisited);
3446Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3447 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3449 if (!FVisited.
insert(
F).second)
3452 SmallPtrSet<Value *, 0> Visited;
3455 for (User *U :
F->users()) {
3457 if (!CI || OpIdx >= CI->
arg_size())
3467 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3470 for (User *OpU : OpArg->
users()) {
3472 if (!Inst || Inst == CI)
3475 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3482 if (FVisited.
find(OuterF) != FVisited.
end())
3484 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3485 if (OuterF->
getArg(i) == OpArg) {
3486 Lookup.push_back(std::make_pair(OuterF, i));
3493 for (
auto &Pair :
Lookup) {
3494 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3501void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3503 B.SetInsertPointPastAllocas(
F);
3504 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3510 for (User *U : Arg->
users()) {
3512 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3530 for (User *U :
F->users()) {
3532 if (!CI || OpIdx >= CI->
arg_size())
3546 for (User *U : Arg->
users()) {
3550 CI->
getParent()->getParent() == CurrF) {
3552 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3564 B.SetInsertPointPastAllocas(
F);
3565 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3570 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3572 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3576 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3588 bool IsNewFTy =
false;
3604bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3607 if (
F.isIntrinsic())
3609 if (
F.isDeclaration()) {
3610 for (User *U :
F.users()) {
3613 UF &&
UF->hasPersonalityFn() &&
UF->getPersonalityFn() == &
F)
3627 for (User *U :
F.users()) {
3629 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3631 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3632 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3640 if (Worklist.
empty())
3643 LLVMContext &Ctx =
M.getContext();
3650 for (
const auto &Arg :
F->args())
3653 IRB.CreateCall(
F, Args);
3655 IRB.CreateRetVoid();
3661void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3662 DenseMap<Function *, CallInst *> Ptrcasts;
3663 for (
auto It : FDeclPtrTys) {
3665 for (
auto *U :
F->users()) {
3670 for (
auto [Idx, ElemTy] : It.second) {
3678 B.SetInsertPointPastAllocas(Arg->
getParent());
3682 }
else if (isaGEP(Param)) {
3683 replaceUsesOfWithSpvPtrcast(
3684 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3693 .getFirstNonPHIOrAlloca());
3711 FDeclPtrTys.
clear();
3714GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3715 GetElementPtrInst *
GEP) {
3722 Type *SrcTy =
GEP->getSourceElementType();
3723 SmallVector<Value *, 8> Indices(
GEP->indices());
3725 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3726 Indices.erase(Indices.begin());
3727 SrcTy = ArrTy->getElementType();
3729 GEP->getNoWrapFlags(),
"",
3730 GEP->getIterator());
3735void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3742 if (
ST->canUseExtension(
3743 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3744 for (BasicBlock &BB :
F) {
3746 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3750 SmallVector<unsigned, 1>
Ops =
3752 unsigned LC =
Ops[0];
3753 if (LC == SPIRV::LoopControl::None)
3757 B.SetInsertPoint(Term);
3758 SmallVector<Value *, 4> IntrArgs;
3759 for (
unsigned Op :
Ops)
3761 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3773 SmallPtrSet<BasicBlock *, 8> UsedMergeBlocks;
3780 SmallVector<unsigned, 1> LoopControlOps =
3782 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3795 for (BasicBlock *BB : {Latch, Header}) {
3799 if (!
L->contains(Succ) && !UsedMergeBlocks.
contains(Succ))
3802 if (!MergeBlock || !UsedMergeBlocks.
insert(MergeBlock).second)
3805 B.SetInsertPoint(Header->getTerminator());
3808 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3809 for (
unsigned Imm : LoopControlOps)
3810 Args.emplace_back(
B.getInt32(
Imm));
3811 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3815bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3816 if (
Func.isDeclaration())
3825 GR =
ST.getSPIRVGlobalRegistry();
3829 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3831 CanUseAnyVectorRank =
3832 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3836 AggrConstTypes.
clear();
3839 processParamTypesByFunHeader(CurrF,
B);
3843 SmallPtrSet<Instruction *, 4> DeadInsts;
3846 Type *ElTy =
SI->getValueOperand()->getType();
3861 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3865 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3867 GEP->replaceAllUsesWith(NewGEP);
3871 if (
Type *GepTy = getGEPType(
GEP))
3875 for (
auto *
I : DeadInsts) {
3876 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3877 I->eraseFromParent();
3880 B.SetInsertPoint(
Func.getEntryBlock().begin());
3881 for (
auto &GV :
Func.getParent()->globals())
3882 processGlobalValue(GV,
B);
3884 reconstructAggregateReturns(Func,
B);
3885 preprocessUndefsAndPoisons(
B);
3886 simplifyNullAddrSpaceCasts();
3887 preprocessCompositeConstants(
B);
3895 Type *I32Ty =
B.getInt32Ty();
3900 insertCompositeAggregateArms(&
I,
B);
3901 AggrConstTypes[&
I] =
I.getType();
3902 I.mutateType(I32Ty);
3905 preprocessBoolVectorBitcasts(Func);
3906 SmallVector<Instruction *> Worklist(
3909 applyDemangledPtrArgTypes(
B);
3912 for (
auto &
I : Worklist) {
3914 if (isConvergenceIntrinsic(
I))
3917 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3919 insertAssignTypeIntrs(
I,
B);
3920 insertPtrCastOrAssignTypeInstr(
I,
B);
3925 insertAssignPtrTypeIntrs(
I,
B,
true);
3928 useRoundingMode(FPI,
B);
3933 SmallPtrSet<Instruction *, 4> IncompleteRets;
3935 deduceOperandElementType(&
I, &IncompleteRets);
3939 for (BasicBlock &BB : Func)
3940 for (PHINode &Phi : BB.
phis())
3942 deduceOperandElementType(&Phi,
nullptr);
3944 for (
auto *
I : Worklist) {
3945 TrackConstants =
true;
3955 if (isConvergenceIntrinsic(
I))
3959 processInstrAfterVisit(
I,
B);
3962 emitUnstructuredLoopControls(Func,
B);
3968bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3969 if (!GR || TodoTypeSz == 0)
3972 unsigned SzTodo = TodoTypeSz;
3973 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3980 if (!KnownTy || !AssignCI)
3986 SmallPtrSet<Value *, 0> Visited;
3987 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3988 if (ElemTy != KnownTy) {
3989 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3990 propagateElemType(CI, ElemTy, VisitedSubst);
3997 if (
Op->hasUseList()) {
3998 for (User *U :
Op->users()) {
4005 if (TodoTypeSz == 0)
4010 SmallPtrSet<Instruction *, 4> IncompleteRets;
4012 auto It = ToProcess.
find(&
I);
4013 if (It == ToProcess.
end())
4015 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
4016 if (It->second.size() == 0)
4018 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
4019 if (TodoTypeSz == 0)
4024 return SzTodo > TodoTypeSz;
4038 .Cases({
"char",
"signed char",
"unsigned char",
"short",
4039 "unsigned short",
"int",
"unsigned int",
"_Float16",
"float",
4047 unsigned NumElts = 0;
4048 if (
Count.getAsInteger(10, NumElts) || NumElts == 0)
4055 TypeStr.
split(Quals,
' ', -1,
false);
4058 if (Qual !=
"const" && Qual !=
"volatile" && Qual !=
"restrict" &&
4059 !(Qual.consume_front(
"AS") && !Qual.getAsInteger(10, AS)))
4066void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
4068 if (!
F.isDeclaration() ||
F.isIntrinsic())
4071 if (DemangledName.empty())
4074 auto Set =
ST.getPreferredInstructionSet();
4075 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(DemangledName, Set);
4077 const bool IsBuiltin = Grp >= 0 || SPIRV::isBuiltin(DemangledName, Set);
4078 if (IsBuiltin && Opcode != SPIRV::OpGroupAsyncCopy)
4080 SmallVector<unsigned> Idxs;
4081 for (Argument &Arg :
F.args())
4086 LLVMContext &Ctx =
F.getContext();
4088 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
4089 if (TypeStrs.
empty())
4092 if (!IsBuiltin && (!
F.getName().starts_with(
"_Z") ||
F.hasStructRetAttr() ||
4093 StringRef(DemangledName).
count(
'(') != 1 ||
4094 StringRef(DemangledName).
count(
')') != 1 ||
4095 StringRef(DemangledName).
contains(
'<') ||
4096 TypeStrs.
size() !=
F.arg_size()))
4098 bool AllowLongVectors =
4099 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
4100 for (
unsigned Idx : Idxs) {
4101 if (Idx >= TypeStrs.
size())
4103 StringRef TypeStr = TypeStrs[
Idx].trim();
4104 Type *ElemTy = IsBuiltin
4105 ? SPIRV::parseBuiltinCallArgumentType(TypeStr, Ctx)
4115 FDeclPtrTys[&
F].emplace_back(Idx, ElemTy);
4117 ST.getSPIRVGlobalRegistry()->addDeducedElementType(
F.getArg(Idx),
4123bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
4124 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
4126 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
4127 if (!
ST.canUseExtension(
4128 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4129 I.getContext().emitError(
4130 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
4134 I.eraseFromParent();
4140 Value *Ptrs =
I.getArgOperand(0);
4142 Value *Passthru =
I.getArgOperand(2);
4145 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
4147 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
4152 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
4154 I.eraseFromParent();
4158 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
4159 if (!
ST.canUseExtension(
4160 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4161 I.getContext().emitError(
4162 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
4165 I.eraseFromParent();
4172 Value *Ptrs =
I.getArgOperand(1);
4177 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
4179 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
4183 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
4184 I.eraseFromParent();
4195void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
4196 struct BoolVecBitcast {
4198 FixedVectorType *BoolVecTy;
4202 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4204 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4212 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4214 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4218 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4220 Value *Src = BC->getOperand(0);
4221 unsigned BoolVecN = BoolVecTy->getNumElements();
4224 Type *OtherTy = SrcIsBoolVec ? BC->getDestTy() : Src->getType();
4225 unsigned NumElts = 1;
4227 NumElts = VTy->getNumElements();
4233 if (!SrcIsBoolVec) {
4236 auto GetLane = [&](
unsigned I) {
4239 Elt =
B.CreateExtractElement(IntVal,
B.getInt32(
I / EltBits));
4243 return B.CreateICmpNE(
And, ConstantInt::get(EltTy, 0));
4251 if (!Idx ||
Idx->getValue().uge(BoolVecN))
4253 B.SetInsertPoint(EE);
4254 EE->replaceAllUsesWith(GetLane(
Idx->getZExtValue()));
4255 EE->eraseFromParent();
4257 if (BC->use_empty()) {
4258 BC->eraseFromParent();
4262 B.SetInsertPoint(BC);
4264 for (
unsigned I = 0;
I < BoolVecN; ++
I)
4265 Result =
B.CreateInsertElement(Result, GetLane(
I),
B.getInt32(
I));
4269 for (
unsigned J = 0; J < NumElts; ++J) {
4270 Value *Elt = ConstantInt::get(EltTy, 0);
4271 for (
unsigned Bit = 0;
Bit < EltBits; ++
Bit) {
4273 B.CreateExtractElement(Src,
B.getInt32(J * EltBits + Bit));
4274 Value *Ext =
B.CreateZExt(Lane, EltTy);
4276 Ext =
B.CreateShl(Ext, ConstantInt::get(EltTy, Bit));
4277 Elt =
B.CreateOr(Elt, Ext);
4279 IntVal = NumElts > 1 ?
B.CreateInsertElement(IntVal, Elt,
B.getInt32(J))
4282 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4285 BC->replaceAllUsesWith(Result);
4286 BC->eraseFromParent();
4290bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4294 if (!
F.isIntrinsic())
4297 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4302 Changed |= processMaskedMemIntrinsic(*
II);
4306 F.eraseFromParent();
4312bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4315 Changed |= convertMaskedMemIntrinsics(M);
4317 parseFunDeclarations(M);
4318 insertConstantsForFPFastMathDefault(M);
4329 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4331 processParamTypes(&
F,
B);
4335 CanTodoType =
false;
4336 Changed |= postprocessTypes(M);
4339 Changed |= processFunctionPointers(M);
4346 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4352 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 Type * getMemberPointeeType(Type *AggrTy, ArrayRef< unsigned > Indices)
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
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.
static unsigned getInsertedValueOperandIndex()
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.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
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.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
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)