27#include "llvm/IR/IntrinsicsSPIRV.h"
62#define DEBUG_TYPE "spirv-emit-intrinsics"
66 cl::desc(
"Emit OpName for all instructions"),
70#define GET_BuiltinGroup_DECL
71#include "SPIRVGenTables.inc"
76class GlobalVariableUsers {
77 template <
typename T1,
typename T2>
78 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
80 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
82 void collectGlobalUsers(
83 const GlobalVariable *GV,
84 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
85 &GlobalIsUsedByGlobal) {
87 while (!
Stack.empty()) {
91 GlobalIsUsedByFun[GV].insert(
I->getFunction());
96 GlobalIsUsedByGlobal[GV].insert(UserGV);
101 Stack.append(
C->user_begin(),
C->user_end());
105 bool propagateGlobalToGlobalUsers(
106 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
107 &GlobalIsUsedByGlobal) {
110 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
111 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
112 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
113 auto It = GlobalIsUsedByGlobal.find(UserGV);
114 if (It == GlobalIsUsedByGlobal.end())
122 void propagateGlobalToFunctionReferences(
123 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
124 &GlobalIsUsedByGlobal) {
125 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
126 auto &UserFunctions = GlobalIsUsedByFun[GV];
127 for (
const GlobalVariable *UserGV : UserGlobals) {
128 auto It = GlobalIsUsedByFun.find(UserGV);
129 if (It == GlobalIsUsedByFun.end())
140 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
141 GlobalIsUsedByGlobal;
142 GlobalIsUsedByFun.clear();
143 for (GlobalVariable &GV :
M.globals())
144 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
147 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
150 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
153 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
154 const FunctionSetType &
155 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
156 auto It = GlobalIsUsedByFun.find(&GV);
157 if (It != GlobalIsUsedByFun.end())
160 static const FunctionSetType
Empty{};
165static bool isaGEP(
const Value *V) {
171static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
177 return AT->getNumElements();
183class SPIRVEmitIntrinsicsImpl
184 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
185 const SPIRVTargetMachine &TM;
186 SPIRVGlobalRegistry *GR =
nullptr;
188 bool TrackConstants =
true;
189 bool HaveFunPtrs =
false;
190 bool CanUseAnyVectorRank =
false;
191 DenseMap<Instruction *, Constant *> AggrConsts;
192 DenseMap<Instruction *, Type *> AggrConstTypes;
193 SmallPtrSet<Instruction *, 0> AggrStores;
194 GlobalVariableUsers GVUsers;
195 SmallPtrSet<Value *, 0> Named;
198 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
201 bool CanTodoType =
true;
202 unsigned TodoTypeSz = 0;
203 DenseMap<Value *, bool> TodoType;
204 void insertTodoType(
Value *
Op) {
206 if (CanTodoType && !isaGEP(
Op)) {
207 auto It = TodoType.try_emplace(
Op,
true);
212 void eraseTodoType(
Value *
Op) {
213 auto It = TodoType.find(
Op);
214 if (It != TodoType.end() && It->second) {
222 auto It = TodoType.find(
Op);
223 return It != TodoType.end() && It->second;
227 SmallPtrSet<Instruction *, 0> TypeValidated;
230 enum WellKnownTypes { Event };
233 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
234 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
235 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
236 bool UnknownElemTypeI8,
237 bool IgnoreKnownType =
false);
238 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
239 bool UnknownElemTypeI8);
240 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
241 SmallPtrSetImpl<Value *> &Visited,
242 bool UnknownElemTypeI8);
244 SmallPtrSetImpl<Value *> &Visited,
245 bool UnknownElemTypeI8);
247 bool UnknownElemTypeI8);
250 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
251 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
252 SmallPtrSetImpl<Value *> &Visited,
253 bool UnknownElemTypeI8);
257 deduceOperandElementType(Instruction *
I,
258 SmallPtrSetImpl<Instruction *> *IncompleteRets,
259 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
260 bool IsPostprocessing =
false);
265 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
266 void simplifyNullAddrSpaceCasts();
268 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
269 bool IsPostprocessing);
271 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
273 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
274 bool UnknownElemTypeI8);
276 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
278 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
279 Type *ExpectedElementType,
280 unsigned OperandToReplace,
282 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
283 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
285 void insertConstantsForFPFastMathDefault(
Module &M);
288 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
291 Type *deduceFunParamElementType(
Function *
F,
unsigned OpIdx);
293 SmallPtrSetImpl<Function *> &FVisited);
295 bool deduceOperandElementTypeCalledFunction(
297 Type *&KnownElemTy,
bool &Incomplete);
298 void deduceOperandElementTypeFunctionPointer(
300 Type *&KnownElemTy,
bool IsPostprocessing);
301 bool deduceOperandElementTypeFunctionRet(
302 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
303 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
307 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
308 DenseMap<Function *, CallInst *> Ptrcasts);
310 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
313 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
314 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
315 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
316 SmallPtrSetImpl<Value *> &Visited,
317 DenseMap<Function *, CallInst *> Ptrcasts);
320 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
321 Instruction *Dest,
bool DeleteOld =
true);
325 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
328 bool postprocessTypes(
Module &M);
329 bool processFunctionPointers(
Module &M);
330 void parseFunDeclarations(
Module &M);
331 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
332 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
333 bool convertMaskedMemIntrinsics(
Module &M);
334 void preprocessBoolVectorBitcasts(
Function &
F);
353 bool walkLogicalAccessChain(
354 GetElementPtrInst &
GEP,
355 const std::function<
void(
Type *PointedType,
uint64_t Index)>
358 uint64_t Multiplier)> &OnDynamicIndexing);
360 bool walkLogicalAccessChainDynamic(
362 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
365 bool walkLogicalAccessChainConstant(
367 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing);
373 Type *getGEPType(GetElementPtrInst *
GEP);
380 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
382 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
385 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
388 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
391 Instruction *visitInsertElementInst(InsertElementInst &
I);
392 Instruction *visitExtractElementInst(ExtractElementInst &
I);
394 Instruction *visitExtractValueInst(ExtractValueInst &
I);
398 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
403 bool runOnModule(
Module &M);
406class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
407 const SPIRVTargetMachine &TM;
411 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
412 : ModulePass(ID), TM(TM) {}
414 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
416 bool runOnModule(
Module &M)
override {
417 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
423 Intrinsic::experimental_convergence_loop,
424 Intrinsic::experimental_convergence_anchor>());
427bool expectIgnoredInIRTranslation(
const Instruction *
I) {
429 Intrinsic::spv_resource_handlefrombinding,
430 Intrinsic::spv_resource_getbasepointer,
431 Intrinsic::spv_resource_getpointer>());
438 return getPointerRoot(V);
444char SPIRVEmitIntrinsicsLegacy::ID = 0;
447 "SPIRV emit intrinsics",
false,
false)
461 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
474 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
480 B.SetCurrentDebugLocation(
I->getDebugLoc());
481 if (
I->getType()->isVoidTy())
482 B.SetInsertPoint(
I->getNextNode());
484 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
494 if (
I->getType()->isTokenTy())
496 "does not support token type",
501 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
502 expectIgnoredInIRTranslation(
I))
513 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
524 std::vector<Value *> Args = {
527 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
530void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
534 if (isTodoType(Src)) {
537 insertTodoType(Dest);
541void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
546 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
547 Src->eraseFromParent();
550 if (Named.
insert(Dest).second)
565 V = V->stripPointerCasts();
586Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
587 bool UnknownElemTypeI8,
588 bool IsPostprocessing) {
592 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
606 if (UnknownElemTypeI8) {
607 if (!IsPostprocessing)
623 B.SetInsertPointPastAllocas(OpA->getParent());
626 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
628 Type *OpTy =
Op->getType();
630 SmallVector<Value *, 2>
Args = {
633 CallInst *PtrCasted =
634 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
639void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
641 DenseMap<Function *, CallInst *> Ptrcasts) {
643 CallInst *PtrCastedI =
nullptr;
644 auto It = Ptrcasts.
find(
F);
645 if (It == Ptrcasts.
end()) {
646 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
647 Ptrcasts[
F] = PtrCastedI;
649 PtrCastedI = It->second;
651 I->replaceUsesOfWith(
Op, PtrCastedI);
654void SPIRVEmitIntrinsicsImpl::propagateElemType(
656 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
657 DenseMap<Function *, CallInst *> Ptrcasts;
659 for (
auto *U :
Users) {
662 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
667 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
668 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
672void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
674 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
675 SmallPtrSet<Value *, 0> Visited;
676 DenseMap<Function *, CallInst *> Ptrcasts;
677 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
678 std::move(Ptrcasts));
681void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
683 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
684 SmallPtrSetImpl<Value *> &Visited,
685 DenseMap<Function *, CallInst *> Ptrcasts) {
689 for (
auto *U :
Users) {
692 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
697 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
698 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
705Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
706 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
707 SmallPtrSet<Value *, 0> Visited;
708 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
712Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
713 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
714 bool UnknownElemTypeI8) {
719 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
730Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
731 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
743 for (User *OpU :
Op->users()) {
745 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
757 Function *CalledF,
unsigned OpIdx) {
758 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
767Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
768 bool UnknownElemTypeI8) {
769 SmallPtrSet<Value *, 0> Visited;
770 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
773void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
775 bool UnknownElemTypeI8) {
777 if (!UnknownElemTypeI8)
786bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
788 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
795 if (
ST->getNumElements() == 0)
797 CurType =
ST->getElementType(0);
798 OnLiteralIndexing(CurType, 0);
806 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
807 return AT ==
nullptr;
810bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
812 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing) {
817 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
821 CurType = AT->getElementType();
822 OnLiteralIndexing(CurType, Index);
824 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
827 const auto &STL =
DL.getStructLayout(ST);
828 unsigned Element = STL->getElementContainingOffset(
Offset);
829 Offset -= STL->getElementOffset(Element);
830 CurType =
ST->getElementType(Element);
831 OnLiteralIndexing(CurType, Element);
833 Type *EltTy = VT->getElementType();
834 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
835 assert(EltSizeBits % 8 == 0 &&
836 "Element type size in bits must be a multiple of 8.");
837 uint32_t EltTypeSize = EltSizeBits / 8;
842 OnLiteralIndexing(CurType, Index);
852bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
853 GetElementPtrInst &
GEP,
854 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
858 std::optional<uint64_t> MultiplierOpt =
859 getByteAddressingMultiplier(
GEP.getSourceElementType());
860 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
861 uint64_t Multiplier = *MultiplierOpt;
864 Value *Src = getPointerRoot(
GEP.getPointerOperand());
865 Type *CurType = deduceElementType(Src,
true);
869 return walkLogicalAccessChainConstant(
870 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
872 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
873 OnLiteralIndexing, OnDynamicIndexing);
876Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
877 GetElementPtrInst &
GEP) {
880 B.SetInsertPoint(&
GEP);
882 std::vector<Value *> Indices;
883 Indices.push_back(ConstantInt::get(
884 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
885 walkLogicalAccessChain(
889 ConstantInt::get(
B.getInt64Ty(), Index,
false));
894 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
896 if (Multiplier == EltTypeSize) {
898 }
else if (EltTypeSize % Multiplier == 0) {
901 EltTypeSize / Multiplier,
905 ConstantInt::get(
Offset->getType(), Multiplier,
908 Index =
B.CreateUDiv(Index,
909 ConstantInt::get(
Offset->getType(), EltTypeSize,
913 Indices.push_back(Index);
917 SmallVector<Value *, 4>
Args;
918 Args.push_back(
B.getInt1(
GEP.isInBounds()));
919 Args.push_back(
GEP.getOperand(0));
922 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
923 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
927Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
929 Type *CurType =
GEP->getResultElementType();
931 bool Interrupted = walkLogicalAccessChain(
932 *
GEP, [&CurType](
Type *EltType,
uint64_t Index) { CurType = EltType; },
935 return Interrupted ?
GEP->getResultElementType() : CurType;
938Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
939 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
941 return getGEPTypeLogical(
Ref);
948 Ty =
Ref->getSourceElementType();
952 Ty =
Ref->getResultElementType();
957Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
958 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
959 bool IgnoreKnownType) {
965 if (!IgnoreKnownType)
977 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
979 Ty = getGEPType(
Ref);
981 Ty = SGEP->getResultElementType();
986 KnownTy =
Op->getType();
988 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
991 Ty = SPIRV::getOriginalFunctionType(*Fn);
994 Ty = deduceElementTypeByValueDeep(
996 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
1000 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
1002 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1004 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1006 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1008 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1013 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1017 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1019 Type *BestTy =
nullptr;
1021 DenseMap<Type *, unsigned> PhiTys;
1022 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1023 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1030 if (It.first->second > MaxN) {
1031 MaxN = It.first->second;
1039 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1043 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1044 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1049 static StringMap<unsigned> ResTypeByArg = {
1053 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1054 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1055 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1056 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1057 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1058 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1062 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1063 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1065 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1066 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1067 for (User *U :
II->users()) {
1072 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1074 Ty = HandleType->getTypeParameter(0);
1075 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1089 }
else if (
II &&
II->getIntrinsicID() ==
1090 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1094 std::string DemangledName =
1096 if (DemangledName.length() > 0)
1097 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1098 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1099 if (AsArgIt != ResTypeByArg.
end())
1100 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1101 Visited, UnknownElemTypeI8);
1108 if (Ty && !IgnoreKnownType) {
1119Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1120 bool UnknownElemTypeI8) {
1121 SmallPtrSet<Value *, 0> Visited;
1122 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1125Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1126 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1127 bool UnknownElemTypeI8) {
1136 if (!Visited.
insert(U).second)
1141 bool Change =
false;
1142 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1144 assert(
Op &&
"Operands should not be null.");
1145 Type *OpTy =
Op->getType();
1148 if (
Type *NestedTy =
1149 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1156 Change |= Ty != OpTy;
1160 Tys, OrigStructTy->isLiteral() ?
"" : OrigStructTy->getName(),
1161 OrigStructTy->isPacked());
1166 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1167 Type *OpTy = ArrTy->getElementType();
1170 if (
Type *NestedTy =
1171 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1178 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1184 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1185 Type *OpTy = VecTy->getElementType();
1188 if (
Type *NestedTy =
1189 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1196 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1207Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1208 bool UnknownElemTypeI8) {
1209 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1211 if (!UnknownElemTypeI8)
1214 return IntegerType::getInt8Ty(
I->getContext());
1218 Value *PointerOperand) {
1224 return I->getType();
1232bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1234 Type *&KnownElemTy,
bool &Incomplete) {
1238 std::string DemangledName =
1240 if (DemangledName.length() > 0 &&
1242 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1243 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1244 DemangledName,
ST.getPreferredInstructionSet());
1245 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1246 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1252 KnownElemTy = ElemTy;
1253 Ops.push_back(std::make_pair(
Op, i));
1255 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1262 case SPIRV::OpAtomicFAddEXT:
1263 case SPIRV::OpAtomicFMinEXT:
1264 case SPIRV::OpAtomicFMaxEXT:
1265 case SPIRV::OpAtomicLoad:
1266 case SPIRV::OpAtomicCompareExchangeWeak:
1267 case SPIRV::OpAtomicCompareExchange:
1268 case SPIRV::OpAtomicExchange:
1269 case SPIRV::OpAtomicIAdd:
1270 case SPIRV::OpAtomicISub:
1271 case SPIRV::OpAtomicOr:
1272 case SPIRV::OpAtomicXor:
1273 case SPIRV::OpAtomicAnd:
1274 case SPIRV::OpAtomicUMin:
1275 case SPIRV::OpAtomicUMax:
1276 case SPIRV::OpAtomicSMin:
1277 case SPIRV::OpAtomicSMax: {
1282 Incomplete = isTodoType(
Op);
1283 Ops.push_back(std::make_pair(
Op, 0));
1285 case SPIRV::OpAtomicStore: {
1294 Incomplete = isTodoType(
Op);
1295 Ops.push_back(std::make_pair(
Op, 0));
1304void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1306 Type *&KnownElemTy,
bool IsPostprocessing) {
1310 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1311 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1312 bool IsNewFTy =
false, IsIncomplete =
false;
1315 Type *ArgTy = Arg->getType();
1320 if (isTodoType(Arg))
1321 IsIncomplete =
true;
1323 IsIncomplete =
true;
1326 ArgTy = FTy->getFunctionParamType(ParmIdx);
1330 Type *RetTy = FTy->getReturnType();
1337 IsIncomplete =
true;
1339 IsIncomplete =
true;
1342 if (!IsPostprocessing && IsIncomplete)
1345 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1348bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1349 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1350 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1362 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1363 for (User *U :
F->users()) {
1372 propagateElemType(CI, PrevElemTy, VisitedSubst);
1382 for (Instruction *IncompleteRetI : *IncompleteRets)
1383 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1385 }
else if (IncompleteRets) {
1396void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1397 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1398 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1400 Type *KnownElemTy =
nullptr;
1401 bool Incomplete =
false;
1407 Incomplete = isTodoType(
I);
1408 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1411 Ops.push_back(std::make_pair(
Op, i));
1417 Incomplete = isTodoType(
I);
1418 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1425 Incomplete = isTodoType(
I);
1426 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1430 KnownElemTy =
Ref->getSourceElementType();
1431 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1436 KnownElemTy =
Ref->getBaseType();
1437 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1440 KnownElemTy =
I->getType();
1447 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1456 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1460 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1465 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1473 Incomplete = isTodoType(
Ref->getPointerOperand());
1474 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1482 Incomplete = isTodoType(
Ref->getPointerOperand());
1483 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1489 Incomplete = isTodoType(
I);
1490 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1493 Ops.push_back(std::make_pair(
Op, i));
1501 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1502 IsPostprocessing, KnownElemTy,
Op,
1505 Incomplete = isTodoType(CurrF);
1506 Ops.push_back(std::make_pair(
Op, 0));
1512 bool Incomplete0 = isTodoType(Op0);
1513 bool Incomplete1 = isTodoType(Op1);
1515 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1517 : GR->findDeducedElementType(Op0);
1519 KnownElemTy = ElemTy0;
1520 Incomplete = Incomplete0;
1521 Ops.push_back(std::make_pair(Op1, 1));
1522 }
else if (ElemTy1) {
1523 KnownElemTy = ElemTy1;
1524 Incomplete = Incomplete1;
1525 Ops.push_back(std::make_pair(Op0, 0));
1529 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1530 else if (HaveFunPtrs)
1531 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1536 if (!KnownElemTy ||
Ops.size() == 0)
1541 for (
auto &OpIt :
Ops) {
1545 Type *AskTy =
nullptr;
1546 CallInst *AskCI =
nullptr;
1547 if (IsPostprocessing && AskOps) {
1553 if (Ty == KnownElemTy)
1556 Type *OpTy =
Op->getType();
1562 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1570 else if (!IsPostprocessing)
1574 if (AssignCI ==
nullptr) {
1583 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1584 std::make_pair(
I,
Op)};
1585 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1589 CallInst *PtrCastI =
1590 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1591 if (OpIt.second == std::numeric_limits<unsigned>::max())
1594 I->setOperand(OpIt.second, PtrCastI);
1600void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1605 if (isAssignTypeInstr(U)) {
1606 B.SetInsertPoint(U);
1607 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1608 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1609 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1611 U->eraseFromParent();
1614 U->replaceUsesOfWith(Old, New);
1622 Type *NewArgTy =
New->getType();
1624 if (NewArgTy != ExpectedArgTy) {
1627 M, Intrinsic::spv_abort, {NewArgTy});
1637 "aggregate PHI/select/freeze should have been mutated to value-id "
1639 U->replaceUsesOfWith(Old, New);
1644 New->copyMetadata(*Old);
1650 bool HasPoisonExt) {
1657 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1658 "lowered as undef\n");
1660 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1661 Type *Ty = UV->getType();
1667 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1668 :
B.CreateIntrinsicWithoutFolding(IID, {});
1669 AggrConsts[
Call] = UV;
1670 AggrConstTypes[
Call] = Ty;
1675 return B.CreateIntrinsic(IID, {Ty}, {});
1682void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1687 SmallVector<Instruction *, 16> Insts;
1691 for (Instruction *
I : Insts) {
1692 bool BPrepared =
false;
1694 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1698 bool IsScalar = !
Op->getType()->isAggregateType();
1701 if (IsScalar && !AsPoison)
1705 if (IsScalar && Phi)
1706 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1707 else if (!BPrepared) {
1711 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1712 I->setOperand(Idx, Repl);
1721void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1725 ASC->replaceAllUsesWith(
1727 ASC->eraseFromParent();
1735 if (!V->getType()->isAggregateType())
1744 I.getType()->isAggregateType();
1750void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1753 for (Use &U :
I->operands()) {
1760 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1765 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1767 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1773void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1777 std::queue<Instruction *> Worklist;
1781 while (!Worklist.empty()) {
1782 auto *
I = Worklist.front();
1785 bool KeepInst =
false;
1786 for (
const auto &
Op :
I->operands()) {
1788 Type *ResTy =
nullptr;
1791 ResTy = COp->getType();
1803 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1806 auto PrepareInsert = [&]() {
1809 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1810 :
B.SetInsertPoint(
I);
1815 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1816 Args.push_back(COp->getElementAsConstant(i));
1822 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1831 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1837 auto *CI =
B.CreateIntrinsicWithoutFolding(
1838 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1842 AggrConsts[CI] = AggrConst;
1843 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1855 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1860 unsigned RoundingModeDeco,
1867 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1876 MDNode *SaturatedConversionNode =
1878 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1898 MDString *ConstraintString =
1903 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1907 B.SetInsertPoint(&
Call);
1908 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1913void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1916 if (!
RM.has_value())
1918 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1919 switch (
RM.value()) {
1923 case RoundingMode::NearestTiesToEven:
1924 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1926 case RoundingMode::TowardNegative:
1927 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1929 case RoundingMode::TowardPositive:
1930 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1932 case RoundingMode::TowardZero:
1933 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1935 case RoundingMode::Dynamic:
1936 case RoundingMode::NearestTiesToAway:
1940 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1946Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1950 B.SetInsertPoint(&
I);
1951 SmallVector<Value *, 4>
Args;
1953 Args.push_back(
I.getCondition());
1956 for (
auto &Case :
I.cases()) {
1957 Args.push_back(Case.getCaseValue());
1958 BBCases.
push_back(Case.getCaseSuccessor());
1961 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1962 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1966 I.eraseFromParent();
1969 B.SetInsertPoint(ParentBB);
1970 IndirectBrInst *BrI =
B.CreateIndirectBr(
1973 for (BasicBlock *BBCase : BBCases)
1982Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
1988 B.SetInsertPoint(&
I);
1990 SmallVector<Value *, 4>
Args;
1991 Args.push_back(
B.getInt1(
true));
1992 Args.push_back(
I.getOperand(0));
1993 Args.push_back(
B.getInt32(0));
1994 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1995 Args.push_back(SGEP->getIndexOperand(J));
1998 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1999 replaceAllUsesWithAndErase(
B, &
I, NewI);
2004SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2006 B.SetInsertPoint(&
I);
2011 unsigned N = RetVTy->getNumElements();
2012 Value *PtrOp =
I.getPointerOperand();
2014 Type *ResultPtrTy = RetVTy->getElementType();
2017 Value *InBounds =
B.getInt1(
I.isInBounds());
2018 Type *LanePointeeTy = getGEPType(&
I);
2019 Type *SrcElemTy =
I.getSourceElementType();
2028 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2029 Value *LaneIdx =
B.getInt32(Lane);
2030 Value *ScalarPtr = PtrOp;
2034 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2038 SmallVector<Value *, 4>
Args;
2039 Args.push_back(InBounds);
2040 Args.push_back(ScalarPtr);
2041 for (
Value *Idx :
I.indices()) {
2049 Args.push_back(visitExtractElementInst(*EI));
2053 Args.push_back(Idx);
2056 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2058 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2062 replaceAllUsesWithAndErase(
B, &
I, NewI);
2080 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2081 return buildLogicalAccessChainFromGEP(
I);
2086 Value *PtrOp =
I.getPointerOperand();
2087 Type *SrcElemTy =
I.getSourceElementType();
2088 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2091 if (ArrTy->getElementType() == SrcElemTy) {
2093 Type *FirstIdxType =
I.getOperand(1)->getType();
2094 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2095 for (
Value *Idx :
I.indices())
2099 SmallVector<Value *, 4>
Args;
2100 Args.push_back(
B.getInt1(
I.isInBounds()));
2101 Args.push_back(
I.getPointerOperand());
2104 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2106 replaceAllUsesWithAndErase(
B, &
I, NewI);
2113 SmallVector<Value *, 4>
Args;
2114 Args.push_back(
B.getInt1(
I.isInBounds()));
2117 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2118 replaceAllUsesWithAndErase(
B, &
I, NewI);
2122Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2124 B.SetInsertPoint(&
I);
2133 I.eraseFromParent();
2140 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2141 replaceAllUsesWithAndErase(
B, &
I, NewI);
2145void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2147 Type *VTy =
V->getType();
2152 if (ElemTy != AssignedType)
2165 if (CurrentType == AssignedType)
2172 " for value " +
V->getName(),
2181void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2182 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2187 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2188 if (PointerElemTy == ExpectedElementType ||
2193 Value *ExpectedElementVal =
2195 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2197 bool FirstPtrCastOrAssignPtrType =
true;
2203 for (
auto User :
Pointer->users()) {
2206 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2207 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2208 II->getOperand(0) != Pointer)
2213 FirstPtrCastOrAssignPtrType =
false;
2214 if (
II->getOperand(1) != VMD ||
2221 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2226 if (
II->getParent() !=
I->getParent())
2229 I->setOperand(OperandToReplace,
II);
2244 if (FirstPtrCastOrAssignPtrType) {
2249 }
else if (isTodoType(Pointer)) {
2250 eraseTodoType(Pointer);
2258 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2259 std::make_pair(
I, Pointer)};
2261 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2273 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2279void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2284 replacePointerOperandWithPtrCast(
2285 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2291 Type *OpTy =
Op->getType();
2294 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2297 if (OpTy ==
Op->getType())
2298 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2299 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2304 Type *OpTy = LI->getType();
2309 Type *NewOpTy = OpTy;
2310 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2311 if (OpTy == NewOpTy)
2312 insertTodoType(Pointer);
2315 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2320 Type *OpTy =
nullptr;
2332 OpTy = GEPI->getSourceElementType();
2334 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2336 insertTodoType(Pointer);
2348 std::string DemangledName =
2352 bool HaveTypes =
false;
2353 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2371 for (User *U : CalledArg->
users()) {
2373 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2379 HaveTypes |= ElemTy !=
nullptr;
2384 if (DemangledName.empty() && !HaveTypes)
2387 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2402 Type *ExpectedType =
2403 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2404 if (!ExpectedType && !DemangledName.empty())
2405 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2406 DemangledName, OpIdx,
I->getContext());
2407 if (!ExpectedType || ExpectedType->
isVoidTy())
2415 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2420SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2423 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2427 I.getOperand(1)->getType(),
2428 I.getOperand(2)->getType()};
2430 B.SetInsertPoint(&
I);
2432 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2434 replaceAllUsesWithAndErase(
B, &
I, NewI);
2439SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2442 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2446 B.SetInsertPoint(&
I);
2448 I.getIndexOperand()->getType()};
2449 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2450 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2452 replaceAllUsesWithAndErase(
B, &
I, NewI);
2456Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2458 B.SetInsertPoint(&
I);
2461 Value *AggregateOp =
I.getAggregateOperand();
2465 Args.push_back(AggregateOp);
2466 Args.push_back(
I.getInsertedValueOperand());
2467 for (
auto &
Op :
I.indices())
2468 Args.push_back(
B.getInt32(
Op));
2470 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2471 replaceMemInstrUses(&
I, NewI,
B);
2476SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2478 B.SetInsertPoint(&
I);
2479 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2488 for (
auto &
Op :
I.indices())
2489 Args.push_back(
B.getInt32(
Op));
2490 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2491 {
I.getType()}, {
Args});
2497 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2498 AggrConstTypes[NewI] =
I.getType();
2500 replaceMemInstrUses(&
I, NewI,
B);
2503 replaceAllUsesWithAndErase(
B, &
I, NewI);
2507 for (
const Use &U : NewI->
uses()) {
2508 User *Usr =
U.getUser();
2510 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2521 if (ArgNo < FT->getNumParams() &&
2522 !FT->getParamType(ArgNo)->isAggregateType()) {
2531Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2532 if (!
I.getType()->isAggregateType())
2535 B.SetInsertPoint(&
I);
2536 TrackConstants =
false;
2541 unsigned IntrinsicId;
2542 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2543 if (!
I.isAtomic()) {
2544 IntrinsicId = Intrinsic::spv_load;
2545 Args.push_back(
B.getInt32(
I.getAlign().value()));
2547 IntrinsicId = Intrinsic::spv_atomic_load;
2548 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2550 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2551 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2553 replaceMemInstrUses(&
I, NewI,
B);
2557Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2561 B.SetInsertPoint(&
I);
2562 TrackConstants =
false;
2566 auto *PtrOp =
I.getPointerOperand();
2568 if (
I.getValueOperand()->getType()->isAggregateType()) {
2576 "Unexpected argument of aggregate type, should be spv_extractv!");
2580 unsigned IntrinsicId;
2581 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2583 if (!
I.isAtomic()) {
2584 IntrinsicId = Intrinsic::spv_store;
2585 Args.push_back(
B.getInt32(
I.getAlign().value()));
2587 IntrinsicId = Intrinsic::spv_atomic_store;
2588 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2591 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2593 I.eraseFromParent();
2597Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2598 Value *ArraySize =
nullptr;
2599 if (
I.isArrayAllocation()) {
2602 SPIRV::Extension::SPV_INTEL_variable_length_array))
2604 "array allocation: this instruction requires the following "
2605 "SPIR-V extension: SPV_INTEL_variable_length_array",
2607 ArraySize =
I.getArraySize();
2610 B.SetInsertPoint(&
I);
2611 TrackConstants =
false;
2612 Type *PtrTy =
I.getType();
2615 ?
B.CreateIntrinsicWithoutFolding(
2616 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2617 {ArraySize,
B.getInt32(
I.getAlign().value())})
2618 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2619 {
B.getInt32(
I.getAlign().value())});
2620 replaceAllUsesWithAndErase(
B, &
I, NewI);
2625SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2626 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2628 B.SetInsertPoint(&
I);
2631 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2635 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2636 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2637 uint32_t ScSem =
static_cast<uint32_t
>(
2646 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2647 replaceMemInstrUses(&
I, NewI,
B);
2651Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &
I) {
2652 auto Op =
I.getOperation();
2663 B.SetInsertPoint(&
I);
2665 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2666 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2668 uint32_t
Scope =
static_cast<uint32_t
>(
2670 uint32_t ScSem =
static_cast<uint32_t
>(
2677 ?
"__translate_spirv_atomic_uinc_wrap"
2678 :
"__translate_spirv_atomic_udec_wrap");
2680 Type *ValTy =
I.getValOperand()->getType();
2681 Type *PtrTy =
I.getPointerOperand()->getType();
2683 raw_svector_ostream OS(FuncName);
2684 OS <<
"_p" << AS <<
"_";
2686 OS <<
"v" << VecTy->getNumElements();
2689 Type *Int32Ty =
B.getInt32Ty();
2690 Type *BoolTy =
B.getInt1Ty();
2692 ValTy, BoolTy, BoolTy};
2693 FunctionType *FT = FunctionType::get(ValTy, ArgTys,
false);
2694 FunctionCallee
FC =
M->getOrInsertFunction(FuncName, FT);
2698 I.getPointerOperand(),
B.getInt32(Scope),
2699 B.getInt32(MemSem),
I.getValOperand(),
2700 B.getInt1(
I.isVolatile()),
B.getInt1(
I.isElementwise())};
2701 CallInst *CI =
B.CreateCall(FC, Args);
2707 replaceAllUsesWithAndErase(
B, &
I, CI);
2716 case Intrinsic::spv_abort:
2718 case Intrinsic::trap:
2719 case Intrinsic::ubsantrap:
2721 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2741 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2742 "abort-like call must be the last non-debug instruction before its "
2743 "block's terminator");
2747Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2748 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2752 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2759 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2773 while (!Stack.empty()) {
2774 const Value *V = Stack.pop_back_val();
2775 if (!Visited.
insert(V).second)
2783 Stack.append(
C->user_begin(),
C->user_end());
2799 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2800 if (UserFunctions.contains(
F))
2805 if (!UserFunctions.empty())
2810 const Module &M = *
F->getParent();
2811 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2812 return F == &FirstDefinition;
2815Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2817 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2818 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2820 AggrConstTypes[Leaf] = ElemTy;
2823 SmallVector<Value *, 4> Elems;
2825 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2828 DenseMap<Type *, Instruction *> LeafByType;
2829 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2831 auto &
Entry = LeafByType[ElemTy];
2833 Entry = MakeLeaf(ElemTy);
2837 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2838 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2840 AggrConstTypes[Composite] = AggrTy;
2849void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2854 for (BasicBlock &BB : Func) {
2858 Value *RetVal = RI->getReturnValue();
2865 B.SetInsertPoint(RI);
2868 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2869 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2871 RI->setOperand(0, Rebuilt);
2875void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2885 deduceElementTypeHelper(&GV,
false);
2890 Value *InitOp = Init;
2897 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2898 {
B.getInt32Ty()}, {});
2903 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2908 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2909 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2915 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2921bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2923 bool UnknownElemTypeI8) {
2929 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2936void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2939 static StringMap<unsigned> ResTypeWellKnown = {
2940 {
"async_work_group_copy", WellKnownTypes::Event},
2941 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2942 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2946 bool IsKnown =
false;
2951 std::string DemangledName =
2954 if (DemangledName.length() > 0)
2956 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2957 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2958 if (ResIt != ResTypeWellKnown.
end()) {
2961 switch (ResIt->second) {
2962 case WellKnownTypes::Event:
2965 CanUseAnyVectorRank);
2970 switch (DecorationId) {
2973 case FPDecorationId::SAT:
2976 case FPDecorationId::RTE:
2978 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2980 case FPDecorationId::RTZ:
2982 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2984 case FPDecorationId::RTP:
2986 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2988 case FPDecorationId::RTN:
2990 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2996 Type *Ty =
I->getType();
2999 Type *TypeToAssign = Ty;
3002 auto It = AggrConstTypes.
find(
II);
3003 if (It == AggrConstTypes.
end())
3005 TypeToAssign = It->second;
3006 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
3007 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
3008 TypeToAssign = It->second;
3010 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
3011 TypeToAssign = It->second;
3015 for (
const auto &
Op :
I->operands()) {
3023 Type *OpTy =
Op->getType();
3025 CallInst *AssignCI =
3030 Type *OpTy =
Op->getType();
3046 Intrinsic::spv_assign_type, {OpTy},
3056bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
3057 Instruction *Inst) {
3059 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3069void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3071 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3073 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3078 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3079 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3080 if (shouldTryToAddMemAliasingDecoration(
I)) {
3081 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3082 ? SPIRV::Decoration::AliasScopeINTEL
3083 : SPIRV::Decoration::NoAliasINTEL;
3085 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3088 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3089 {
I->getType()}, {
Args});
3093 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3094 processMemAliasingDecoration(LLVMContext::MD_noalias);
3097 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3099 bool AllowFPMaxError =
3101 if (!AllowFPMaxError)
3105 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3109 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
3113 auto &Ctx =
B.getContext();
3115 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
3118 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3120 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3121 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3124 if (
I->hasMetadata(LLVMContext::MD_atomic_ignore_denormal_mode))
3126 Ctx, {US,
MDString::get(Ctx,
"atomic.ignore.denormal.mode")}));
3128 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3136 &FPFastMathDefaultInfoMap,
3138 auto it = FPFastMathDefaultInfoMap.
find(
F);
3139 if (it != FPFastMathDefaultInfoMap.
end())
3147 SPIRV::FPFastMathMode::None);
3149 SPIRV::FPFastMathMode::None);
3151 SPIRV::FPFastMathMode::None);
3152 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3158 size_t BitWidth = Ty->getScalarSizeInBits();
3162 assert(Index >= 0 && Index < 3 &&
3163 "Expected FPFastMathDefaultInfo for half, float, or double");
3164 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3165 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3166 return FPFastMathDefaultInfoVec[Index];
3169void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3171 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3180 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3182 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3190 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3193 [[maybe_unused]] GlobalVariable *GV =
3194 new GlobalVariable(M,
3195 Type::getInt32Ty(
M.getContext()),
3209 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3210 FPFastMathDefaultInfoMap;
3212 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3221 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3223 "Expected 4 operands for FPFastMathDefault");
3229 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3231 SPIRV::FPFastMathDefaultInfo &
Info =
3234 Info.FPFastMathDefault =
true;
3235 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3237 "Expected no operands for ContractionOff");
3241 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3243 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3244 Info.ContractionOff =
true;
3246 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3248 "Expected 1 operand for SignedZeroInfNanPreserve");
3249 unsigned TargetWidth =
3254 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3258 assert(Index >= 0 && Index < 3 &&
3259 "Expected FPFastMathDefaultInfo for half, float, or double");
3260 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3261 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3262 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3266 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3267 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3268 if (FPFastMathDefaultInfoVec.
empty())
3271 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3272 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3275 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3276 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3280 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3282 "and AllowContract");
3284 if (
Info.SignedZeroInfNanPreserve &&
3286 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3287 SPIRV::FPFastMathMode::NSZ))) {
3288 if (
Info.FPFastMathDefault)
3290 "SignedZeroInfNanPreserve but at least one of "
3291 "NotNaN/NotInf/NSZ is enabled.");
3294 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3295 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3296 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3298 "AllowTransform requires AllowReassoc and "
3299 "AllowContract to be set.");
3302 auto it = GlobalVars.
find(Flags);
3303 GlobalVariable *GV =
nullptr;
3304 if (it != GlobalVars.
end()) {
3310 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3313 GV =
new GlobalVariable(M,
3314 Type::getInt32Ty(
M.getContext()),
3319 GlobalVars[
Flags] = GV;
3325void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3328 bool IsConstComposite =
3329 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3330 if (IsConstComposite && TrackConstants) {
3332 auto t = AggrConsts.
find(
I);
3336 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3338 NewOp->setArgOperand(0,
I);
3341 for (
const auto &
Op :
I->operands()) {
3345 unsigned OpNo =
Op.getOperandNo();
3346 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3347 (!
II->isBundleOperand(OpNo) &&
3348 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3352 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3353 :
B.SetInsertPoint(
I);
3356 Type *OpTy =
Op->getType();
3364 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3366 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3367 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3369 SmallVector<Value *, 2>
Args = {
3373 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3379 I->setOperand(OpNo, NewOp);
3385Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3387 SmallPtrSet<Function *, 0> FVisited;
3388 return deduceFunParamElementType(
F, OpIdx, FVisited);
3391Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3392 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3394 if (!FVisited.
insert(
F).second)
3397 SmallPtrSet<Value *, 0> Visited;
3400 for (User *U :
F->users()) {
3402 if (!CI || OpIdx >= CI->
arg_size())
3412 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3415 for (User *OpU : OpArg->
users()) {
3417 if (!Inst || Inst == CI)
3420 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3427 if (FVisited.
find(OuterF) != FVisited.
end())
3429 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3430 if (OuterF->
getArg(i) == OpArg) {
3431 Lookup.push_back(std::make_pair(OuterF, i));
3438 for (
auto &Pair :
Lookup) {
3439 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3446void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3448 B.SetInsertPointPastAllocas(
F);
3449 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3455 for (User *U : Arg->
users()) {
3457 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3475 for (User *U :
F->users()) {
3477 if (!CI || OpIdx >= CI->
arg_size())
3491 for (User *U : Arg->
users()) {
3495 CI->
getParent()->getParent() == CurrF) {
3497 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3509 B.SetInsertPointPastAllocas(
F);
3510 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3515 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3517 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3521 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3533 bool IsNewFTy =
false;
3549bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3552 if (
F.isIntrinsic())
3554 if (
F.isDeclaration()) {
3555 for (User *U :
F.users()) {
3568 for (User *U :
F.users()) {
3570 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3572 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3573 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3581 if (Worklist.
empty())
3584 LLVMContext &Ctx =
M.getContext();
3591 for (
const auto &Arg :
F->args())
3594 IRB.CreateCall(
F, Args);
3596 IRB.CreateRetVoid();
3602void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3603 DenseMap<Function *, CallInst *> Ptrcasts;
3604 for (
auto It : FDeclPtrTys) {
3606 for (
auto *U :
F->users()) {
3611 for (
auto [Idx, ElemTy] : It.second) {
3619 B.SetInsertPointPastAllocas(Arg->
getParent());
3623 }
else if (isaGEP(Param)) {
3624 replaceUsesOfWithSpvPtrcast(
3625 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3634 .getFirstNonPHIOrDbgOrAlloca());
3654GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3655 GetElementPtrInst *
GEP) {
3662 Type *SrcTy =
GEP->getSourceElementType();
3663 SmallVector<Value *, 8> Indices(
GEP->indices());
3665 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3666 Indices.erase(Indices.begin());
3667 SrcTy = ArrTy->getElementType();
3669 GEP->getNoWrapFlags(),
"",
3670 GEP->getIterator());
3675void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3682 if (
ST->canUseExtension(
3683 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3684 for (BasicBlock &BB :
F) {
3686 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3690 SmallVector<unsigned, 1>
Ops =
3692 unsigned LC =
Ops[0];
3693 if (LC == SPIRV::LoopControl::None)
3697 B.SetInsertPoint(Term);
3698 SmallVector<Value *, 4> IntrArgs;
3699 for (
unsigned Op :
Ops)
3701 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3722 SmallVector<unsigned, 1> LoopControlOps =
3724 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3728 B.SetInsertPoint(Header->getTerminator());
3731 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3732 for (
unsigned Imm : LoopControlOps)
3733 Args.emplace_back(
B.getInt32(
Imm));
3734 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3738bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3739 if (
Func.isDeclaration())
3743 GR =
ST.getSPIRVGlobalRegistry();
3747 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3749 CanUseAnyVectorRank =
3750 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3754 AggrConstTypes.
clear();
3757 processParamTypesByFunHeader(CurrF,
B);
3761 SmallPtrSet<Instruction *, 4> DeadInsts;
3764 Type *ElTy =
SI->getValueOperand()->getType();
3773 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3777 GR->addDeducedElementType(
3779 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3783 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3785 GEP->replaceAllUsesWith(NewGEP);
3789 if (
Type *GepTy = getGEPType(
GEP))
3793 for (
auto *
I : DeadInsts) {
3794 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3795 I->eraseFromParent();
3798 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3799 for (
auto &GV :
Func.getParent()->globals())
3800 processGlobalValue(GV,
B);
3802 reconstructAggregateReturns(Func,
B);
3803 preprocessUndefsAndPoisons(
B);
3804 simplifyNullAddrSpaceCasts();
3805 preprocessCompositeConstants(
B);
3813 Type *I32Ty =
B.getInt32Ty();
3818 insertCompositeAggregateArms(&
I,
B);
3819 AggrConstTypes[&
I] =
I.getType();
3820 I.mutateType(I32Ty);
3823 preprocessBoolVectorBitcasts(Func);
3824 SmallVector<Instruction *> Worklist(
3827 applyDemangledPtrArgTypes(
B);
3830 for (
auto &
I : Worklist) {
3832 if (isConvergenceIntrinsic(
I))
3835 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3837 insertAssignTypeIntrs(
I,
B);
3838 insertPtrCastOrAssignTypeInstr(
I,
B);
3842 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3843 insertAssignPtrTypeIntrs(
I,
B,
true);
3846 useRoundingMode(FPI,
B);
3851 SmallPtrSet<Instruction *, 4> IncompleteRets;
3853 deduceOperandElementType(&
I, &IncompleteRets);
3857 for (BasicBlock &BB : Func)
3858 for (PHINode &Phi : BB.
phis())
3860 deduceOperandElementType(&Phi,
nullptr);
3862 for (
auto *
I : Worklist) {
3863 TrackConstants =
true;
3873 if (isConvergenceIntrinsic(
I))
3877 processInstrAfterVisit(
I,
B);
3880 emitUnstructuredLoopControls(Func,
B);
3886bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3887 if (!GR || TodoTypeSz == 0)
3890 unsigned SzTodo = TodoTypeSz;
3891 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3896 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3897 Type *KnownTy = GR->findDeducedElementType(
Op);
3898 if (!KnownTy || !AssignCI)
3904 SmallPtrSet<Value *, 0> Visited;
3905 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3906 if (ElemTy != KnownTy) {
3907 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3908 propagateElemType(CI, ElemTy, VisitedSubst);
3915 if (
Op->hasUseList()) {
3916 for (User *U :
Op->users()) {
3923 if (TodoTypeSz == 0)
3928 SmallPtrSet<Instruction *, 4> IncompleteRets;
3930 auto It = ToProcess.
find(&
I);
3931 if (It == ToProcess.
end())
3933 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3934 if (It->second.size() == 0)
3936 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3937 if (TodoTypeSz == 0)
3942 return SzTodo > TodoTypeSz;
3946void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
3948 if (!
F.isDeclaration() ||
F.isIntrinsic())
3952 if (DemangledName.empty())
3956 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3957 DemangledName,
ST.getPreferredInstructionSet());
3958 if (Opcode != SPIRV::OpGroupAsyncCopy)
3961 SmallVector<unsigned> Idxs;
3962 for (
unsigned OpIdx = 0; OpIdx <
F.arg_size(); ++OpIdx) {
3970 LLVMContext &Ctx =
F.getContext();
3972 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3973 if (!TypeStrs.
size())
3976 for (
unsigned Idx : Idxs) {
3977 if (Idx >= TypeStrs.
size())
3980 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3983 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3988bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3989 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3991 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3992 if (!
ST.canUseExtension(
3993 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3994 I.getContext().emitError(
3995 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3999 I.eraseFromParent();
4005 Value *Ptrs =
I.getArgOperand(0);
4007 Value *Passthru =
I.getArgOperand(2);
4010 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
4012 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
4017 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
4019 I.eraseFromParent();
4023 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
4024 if (!
ST.canUseExtension(
4025 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4026 I.getContext().emitError(
4027 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
4030 I.eraseFromParent();
4037 Value *Ptrs =
I.getArgOperand(1);
4042 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
4044 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
4048 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
4049 I.eraseFromParent();
4060void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
4061 struct BoolVecBitcast {
4063 FixedVectorType *BoolVecTy;
4067 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4069 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4077 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4079 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4083 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4085 Value *Src = BC->getOperand(0);
4086 unsigned BoolVecN = BoolVecTy->getNumElements();
4088 Type *IntTy =
B.getIntNTy(BoolVecN);
4094 IntVal = ConstantInt::get(IntTy, 0);
4095 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4096 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
4097 Value *Ext =
B.CreateZExt(Elem, IntTy);
4099 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
4100 IntVal =
B.CreateOr(IntVal, Ext);
4106 if (!Src->getType()->isIntegerTy())
4107 IntVal =
B.CreateBitCast(Src, IntTy);
4112 if (!SrcIsBoolVec) {
4115 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4118 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
4119 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4125 if (!BC->getDestTy()->isIntegerTy())
4126 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4129 BC->replaceAllUsesWith(Result);
4130 BC->eraseFromParent();
4134bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4138 if (!
F.isIntrinsic())
4141 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4146 Changed |= processMaskedMemIntrinsic(*
II);
4150 F.eraseFromParent();
4156bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4159 Changed |= convertMaskedMemIntrinsics(M);
4161 parseFunDeclarations(M);
4162 insertConstantsForFPFastMathDefault(M);
4173 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4175 processParamTypes(&
F,
B);
4179 CanTodoType =
false;
4180 Changed |= postprocessTypes(M);
4183 Changed |= processFunctionPointers(M);
4190 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4196 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 bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
This file defines the SmallPtrSet class.
This file defines the SmallString class.
static SymbolRef::Type getType(const Symbol *Sym)
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
This class represents an incoming formal argument to a Function.
const Function * getParent() const
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
@ 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
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Type * getParamType(unsigned i) const
Parameter type accessors.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Type * getReturnType() const
Returns the type of the ret val.
Argument * getArg(unsigned i) const
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static LLVM_ABI Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static unsigned getPointerOperandIndex()
PointerType * getType() const
Global values are always pointers.
@ InternalLinkage
Rename collisions when linking (static functions).
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI void addDestination(BasicBlock *Dest)
Add a destination.
Base class for instruction visitors.
LLVM_ABI bool isDebugOrPseudoInst() const LLVM_READONLY
Return true if the instruction is a DbgInfoIntrinsic or PseudoProbeInst.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
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.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
const 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 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.
@ 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.
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
bool isUntypedPointerVectorTy(const Type *T)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx, SyncScope::ID Id)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(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)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
@ Ref
The access may reference the value stored in memory.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
bool hasInitializer(const GlobalVariable *GV)
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)