28#include "llvm/IR/IntrinsicsSPIRV.h"
61#define DEBUG_TYPE "spirv-emit-intrinsics"
65 cl::desc(
"Emit OpName for all instructions"),
69#define GET_BuiltinGroup_DECL
70#include "SPIRVGenTables.inc"
75class GlobalVariableUsers {
76 template <
typename T1,
typename T2>
77 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
79 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
81 void collectGlobalUsers(
82 const GlobalVariable *GV,
83 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
84 &GlobalIsUsedByGlobal) {
86 while (!
Stack.empty()) {
90 GlobalIsUsedByFun[GV].insert(
I->getFunction());
95 GlobalIsUsedByGlobal[GV].insert(UserGV);
100 Stack.append(
C->user_begin(),
C->user_end());
104 bool propagateGlobalToGlobalUsers(
105 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
106 &GlobalIsUsedByGlobal) {
109 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
110 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
111 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
112 auto It = GlobalIsUsedByGlobal.find(UserGV);
113 if (It == GlobalIsUsedByGlobal.end())
121 void propagateGlobalToFunctionReferences(
122 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
123 &GlobalIsUsedByGlobal) {
124 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
125 auto &UserFunctions = GlobalIsUsedByFun[GV];
126 for (
const GlobalVariable *UserGV : UserGlobals) {
127 auto It = GlobalIsUsedByFun.find(UserGV);
128 if (It == GlobalIsUsedByFun.end())
139 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
140 GlobalIsUsedByGlobal;
141 GlobalIsUsedByFun.clear();
142 for (GlobalVariable &GV :
M.globals())
143 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
146 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
149 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
152 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
153 const FunctionSetType &
154 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
155 auto It = GlobalIsUsedByFun.find(&GV);
156 if (It != GlobalIsUsedByFun.end())
159 static const FunctionSetType
Empty{};
164static bool isaGEP(
const Value *V) {
170static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
176 return AT->getNumElements();
182class SPIRVEmitIntrinsicsImpl
183 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
184 const SPIRVTargetMachine &TM;
185 SPIRVGlobalRegistry *GR =
nullptr;
187 bool TrackConstants =
true;
188 bool HaveFunPtrs =
false;
189 DenseMap<Instruction *, Constant *> AggrConsts;
190 DenseMap<Instruction *, Type *> AggrConstTypes;
191 SmallPtrSet<Instruction *, 0> AggrStores;
192 GlobalVariableUsers GVUsers;
193 SmallPtrSet<Value *, 0> Named;
196 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
199 bool CanTodoType =
true;
200 unsigned TodoTypeSz = 0;
201 DenseMap<Value *, bool> TodoType;
202 void insertTodoType(
Value *
Op) {
204 if (CanTodoType && !isaGEP(
Op)) {
205 auto It = TodoType.try_emplace(
Op,
true);
210 void eraseTodoType(
Value *
Op) {
211 auto It = TodoType.find(
Op);
212 if (It != TodoType.end() && It->second) {
220 auto It = TodoType.find(
Op);
221 return It != TodoType.end() && It->second;
225 SmallPtrSet<Instruction *, 0> TypeValidated;
228 enum WellKnownTypes { Event };
231 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
232 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
233 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
234 bool UnknownElemTypeI8,
235 bool IgnoreKnownType =
false);
236 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
237 bool UnknownElemTypeI8);
238 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
239 SmallPtrSetImpl<Value *> &Visited,
240 bool UnknownElemTypeI8);
242 SmallPtrSetImpl<Value *> &Visited,
243 bool UnknownElemTypeI8);
245 bool UnknownElemTypeI8);
248 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
249 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
250 SmallPtrSetImpl<Value *> &Visited,
251 bool UnknownElemTypeI8);
255 deduceOperandElementType(Instruction *
I,
256 SmallPtrSetImpl<Instruction *> *IncompleteRets,
257 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
258 bool IsPostprocessing =
false);
263 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
264 void simplifyNullAddrSpaceCasts();
266 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
267 bool IsPostprocessing);
269 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
271 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
272 bool UnknownElemTypeI8);
274 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
276 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
277 Type *ExpectedElementType,
278 unsigned OperandToReplace,
280 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
281 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
283 void insertConstantsForFPFastMathDefault(
Module &M);
285 void reconstructAggregateReturns(Function &Func,
IRBuilder<> &
B);
286 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
288 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
289 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
290 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx,
291 SmallPtrSetImpl<Function *> &FVisited);
293 bool deduceOperandElementTypeCalledFunction(
295 Type *&KnownElemTy,
bool &Incomplete);
296 void deduceOperandElementTypeFunctionPointer(
298 Type *&KnownElemTy,
bool IsPostprocessing);
299 bool deduceOperandElementTypeFunctionRet(
300 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
301 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
304 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
305 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
306 DenseMap<Function *, CallInst *> Ptrcasts);
308 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
311 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
312 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
313 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
314 SmallPtrSetImpl<Value *> &Visited,
315 DenseMap<Function *, CallInst *> Ptrcasts);
318 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
319 Instruction *Dest,
bool DeleteOld =
true);
323 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
326 bool postprocessTypes(
Module &M);
327 bool processFunctionPointers(
Module &M);
328 void parseFunDeclarations(
Module &M);
329 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
330 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
331 bool convertMaskedMemIntrinsics(
Module &M);
332 void preprocessBoolVectorBitcasts(Function &
F);
334 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
351 bool walkLogicalAccessChain(
352 GetElementPtrInst &
GEP,
353 const std::function<
void(
Type *PointedType, uint64_t Index)>
356 uint64_t Multiplier)> &OnDynamicIndexing);
358 bool walkLogicalAccessChainDynamic(
359 Type *CurType,
Value *Operand, uint64_t Multiplier,
360 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
361 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing);
363 bool walkLogicalAccessChainConstant(
365 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing);
371 Type *getGEPType(GetElementPtrInst *
GEP);
378 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
380 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
383 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
386 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
389 Instruction *visitInsertElementInst(InsertElementInst &
I);
390 Instruction *visitExtractElementInst(ExtractElementInst &
I);
392 Instruction *visitExtractValueInst(ExtractValueInst &
I);
396 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
400 bool runOnModule(
Module &M);
403class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
404 const SPIRVTargetMachine &TM;
408 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
409 : ModulePass(ID), TM(TM) {}
411 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
413 bool runOnModule(
Module &M)
override {
414 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
420 Intrinsic::experimental_convergence_loop,
421 Intrinsic::experimental_convergence_anchor>());
424bool expectIgnoredInIRTranslation(
const Instruction *
I) {
426 Intrinsic::spv_resource_handlefrombinding,
427 Intrinsic::spv_resource_getbasepointer,
428 Intrinsic::spv_resource_getpointer>());
435 return getPointerRoot(V);
441char SPIRVEmitIntrinsicsLegacy::ID = 0;
444 "SPIRV emit intrinsics",
false,
false)
458 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
471 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
477 B.SetCurrentDebugLocation(
I->getDebugLoc());
478 if (
I->getType()->isVoidTy())
479 B.SetInsertPoint(
I->getNextNode());
481 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
491 if (
I->getType()->isTokenTy())
493 "does not support token type",
498 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
499 expectIgnoredInIRTranslation(
I))
510 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
521 std::vector<Value *> Args = {
524 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
527void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
531 if (isTodoType(Src)) {
534 insertTodoType(Dest);
538void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
543 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
544 Src->eraseFromParent();
547 if (Named.
insert(Dest).second)
562 V = V->stripPointerCasts();
583Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
584 bool UnknownElemTypeI8,
585 bool IsPostprocessing) {
589 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
603 if (UnknownElemTypeI8) {
604 if (!IsPostprocessing)
612CallInst *SPIRVEmitIntrinsicsImpl::buildSpvPtrcast(Function *
F,
Value *
Op,
620 B.SetInsertPointPastAllocas(OpA->getParent());
623 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
625 Type *OpTy =
Op->getType();
629 CallInst *PtrCasted =
630 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
635void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
637 DenseMap<Function *, CallInst *> Ptrcasts) {
639 CallInst *PtrCastedI =
nullptr;
640 auto It = Ptrcasts.
find(
F);
641 if (It == Ptrcasts.
end()) {
642 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
643 Ptrcasts[
F] = PtrCastedI;
645 PtrCastedI = It->second;
647 I->replaceUsesOfWith(
Op, PtrCastedI);
650void SPIRVEmitIntrinsicsImpl::propagateElemType(
652 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
653 DenseMap<Function *, CallInst *> Ptrcasts;
655 for (
auto *U :
Users) {
658 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
663 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
664 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
668void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
670 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
671 SmallPtrSet<Value *, 0> Visited;
672 DenseMap<Function *, CallInst *> Ptrcasts;
673 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
674 std::move(Ptrcasts));
677void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
679 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
680 SmallPtrSetImpl<Value *> &Visited,
681 DenseMap<Function *, CallInst *> Ptrcasts) {
685 for (
auto *U :
Users) {
688 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
693 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
694 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
701Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
702 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
703 SmallPtrSet<Value *, 0> Visited;
704 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
708Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
709 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
710 bool UnknownElemTypeI8) {
715 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
726Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
727 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
739 for (User *OpU :
Op->users()) {
741 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
754 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
763Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
764 bool UnknownElemTypeI8) {
765 SmallPtrSet<Value *, 0> Visited;
766 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
769void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
771 bool UnknownElemTypeI8) {
773 if (!UnknownElemTypeI8)
782bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
783 Type *CurType,
Value *Operand, uint64_t Multiplier,
784 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
785 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
791 if (
ST->getNumElements() == 0)
793 CurType =
ST->getElementType(0);
794 OnLiteralIndexing(CurType, 0);
802 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
803 return AT ==
nullptr;
806bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
808 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
813 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
817 CurType = AT->getElementType();
818 OnLiteralIndexing(CurType, Index);
820 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
823 const auto &STL =
DL.getStructLayout(ST);
824 unsigned Element = STL->getElementContainingOffset(
Offset);
825 Offset -= STL->getElementOffset(Element);
826 CurType =
ST->getElementType(Element);
827 OnLiteralIndexing(CurType, Element);
829 Type *EltTy = VT->getElementType();
830 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
831 assert(EltSizeBits % 8 == 0 &&
832 "Element type size in bits must be a multiple of 8.");
833 uint32_t EltTypeSize = EltSizeBits / 8;
838 OnLiteralIndexing(CurType, Index);
848bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
849 GetElementPtrInst &
GEP,
850 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
851 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
854 std::optional<uint64_t> MultiplierOpt =
855 getByteAddressingMultiplier(
GEP.getSourceElementType());
856 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
857 uint64_t Multiplier = *MultiplierOpt;
860 Value *Src = getPointerRoot(
GEP.getPointerOperand());
861 Type *CurType = deduceElementType(Src,
true);
865 return walkLogicalAccessChainConstant(
866 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
868 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
869 OnLiteralIndexing, OnDynamicIndexing);
872Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
873 GetElementPtrInst &
GEP) {
876 B.SetInsertPoint(&
GEP);
878 std::vector<Value *> Indices;
879 Indices.push_back(ConstantInt::get(
880 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
881 walkLogicalAccessChain(
883 [&Indices, &
B](
Type *EltType, uint64_t Index) {
885 ConstantInt::get(
B.getInt64Ty(), Index,
false));
888 uint64_t Multiplier) {
890 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
892 if (Multiplier == EltTypeSize) {
894 }
else if (EltTypeSize % Multiplier == 0) {
897 EltTypeSize / Multiplier,
901 ConstantInt::get(
Offset->getType(), Multiplier,
904 Index =
B.CreateUDiv(Index,
905 ConstantInt::get(
Offset->getType(), EltTypeSize,
909 Indices.push_back(Index);
913 SmallVector<Value *, 4>
Args;
914 Args.push_back(
B.getInt1(
GEP.isInBounds()));
915 Args.push_back(
GEP.getOperand(0));
918 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
919 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
923Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
925 Type *CurType =
GEP->getResultElementType();
927 bool Interrupted = walkLogicalAccessChain(
928 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
929 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
931 return Interrupted ?
GEP->getResultElementType() : CurType;
934Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
935 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
937 return getGEPTypeLogical(
Ref);
944 Ty =
Ref->getSourceElementType();
948 Ty =
Ref->getResultElementType();
953Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
954 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
955 bool IgnoreKnownType) {
961 if (!IgnoreKnownType)
973 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
975 Ty = getGEPType(
Ref);
977 Ty = SGEP->getResultElementType();
982 KnownTy =
Op->getType();
984 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
987 Ty = SPIRV::getOriginalFunctionType(*Fn);
990 Ty = deduceElementTypeByValueDeep(
992 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
996 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
998 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1000 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1002 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1004 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1009 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1013 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1015 Type *BestTy =
nullptr;
1017 DenseMap<Type *, unsigned> PhiTys;
1018 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1019 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1026 if (It.first->second > MaxN) {
1027 MaxN = It.first->second;
1035 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1036 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1041 static StringMap<unsigned> ResTypeByArg = {
1045 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1046 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1047 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1048 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1049 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1050 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1054 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1055 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1057 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1058 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1059 for (User *U :
II->users()) {
1064 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1066 Ty = HandleType->getTypeParameter(0);
1067 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1081 }
else if (
II &&
II->getIntrinsicID() ==
1082 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1086 std::string DemangledName =
1088 if (DemangledName.length() > 0)
1089 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1090 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1091 if (AsArgIt != ResTypeByArg.
end())
1092 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1093 Visited, UnknownElemTypeI8);
1100 if (Ty && !IgnoreKnownType) {
1111Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1112 bool UnknownElemTypeI8) {
1113 SmallPtrSet<Value *, 0> Visited;
1114 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1117Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1118 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1119 bool UnknownElemTypeI8) {
1128 if (!Visited.
insert(U).second)
1133 bool Change =
false;
1134 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1136 assert(
Op &&
"Operands should not be null.");
1137 Type *OpTy =
Op->getType();
1140 if (
Type *NestedTy =
1141 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1148 Change |= Ty != OpTy;
1156 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1157 Type *OpTy = ArrTy->getElementType();
1160 if (
Type *NestedTy =
1161 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1168 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1174 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1175 Type *OpTy = VecTy->getElementType();
1178 if (
Type *NestedTy =
1179 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1186 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1196Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1197 bool UnknownElemTypeI8) {
1198 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1200 if (!UnknownElemTypeI8)
1203 return IntegerType::getInt8Ty(
I->getContext());
1207 Value *PointerOperand) {
1213 return I->getType();
1221bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1223 Type *&KnownElemTy,
bool &Incomplete) {
1227 std::string DemangledName =
1229 if (DemangledName.length() > 0 &&
1231 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1232 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1233 DemangledName,
ST.getPreferredInstructionSet());
1234 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1235 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1241 KnownElemTy = ElemTy;
1242 Ops.push_back(std::make_pair(
Op, i));
1244 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1251 case SPIRV::OpAtomicFAddEXT:
1252 case SPIRV::OpAtomicFMinEXT:
1253 case SPIRV::OpAtomicFMaxEXT:
1254 case SPIRV::OpAtomicLoad:
1255 case SPIRV::OpAtomicCompareExchangeWeak:
1256 case SPIRV::OpAtomicCompareExchange:
1257 case SPIRV::OpAtomicExchange:
1258 case SPIRV::OpAtomicIAdd:
1259 case SPIRV::OpAtomicISub:
1260 case SPIRV::OpAtomicOr:
1261 case SPIRV::OpAtomicXor:
1262 case SPIRV::OpAtomicAnd:
1263 case SPIRV::OpAtomicUMin:
1264 case SPIRV::OpAtomicUMax:
1265 case SPIRV::OpAtomicSMin:
1266 case SPIRV::OpAtomicSMax: {
1271 Incomplete = isTodoType(
Op);
1272 Ops.push_back(std::make_pair(
Op, 0));
1274 case SPIRV::OpAtomicStore: {
1283 Incomplete = isTodoType(
Op);
1284 Ops.push_back(std::make_pair(
Op, 0));
1293void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1295 Type *&KnownElemTy,
bool IsPostprocessing) {
1299 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1300 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1301 bool IsNewFTy =
false, IsIncomplete =
false;
1304 Type *ArgTy = Arg->getType();
1309 if (isTodoType(Arg))
1310 IsIncomplete =
true;
1312 IsIncomplete =
true;
1315 ArgTy = FTy->getFunctionParamType(ParmIdx);
1319 Type *RetTy = FTy->getReturnType();
1326 IsIncomplete =
true;
1328 IsIncomplete =
true;
1331 if (!IsPostprocessing && IsIncomplete)
1334 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1337bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1338 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1339 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1351 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1352 for (User *U :
F->users()) {
1360 propagateElemType(CI, PrevElemTy, VisitedSubst);
1370 for (Instruction *IncompleteRetI : *IncompleteRets)
1371 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1373 }
else if (IncompleteRets) {
1384void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1385 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1386 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1388 Type *KnownElemTy =
nullptr;
1389 bool Incomplete =
false;
1395 Incomplete = isTodoType(
I);
1396 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1399 Ops.push_back(std::make_pair(
Op, i));
1405 Incomplete = isTodoType(
I);
1406 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1413 Incomplete = isTodoType(
I);
1414 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1418 KnownElemTy =
Ref->getSourceElementType();
1419 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1424 KnownElemTy =
Ref->getBaseType();
1425 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1428 KnownElemTy =
I->getType();
1435 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1444 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1448 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1453 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1461 Incomplete = isTodoType(
Ref->getPointerOperand());
1462 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1470 Incomplete = isTodoType(
Ref->getPointerOperand());
1471 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1477 Incomplete = isTodoType(
I);
1478 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1481 Ops.push_back(std::make_pair(
Op, i));
1489 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1490 IsPostprocessing, KnownElemTy,
Op,
1493 Incomplete = isTodoType(CurrF);
1494 Ops.push_back(std::make_pair(
Op, 0));
1500 bool Incomplete0 = isTodoType(Op0);
1501 bool Incomplete1 = isTodoType(Op1);
1503 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1505 : GR->findDeducedElementType(Op0);
1507 KnownElemTy = ElemTy0;
1508 Incomplete = Incomplete0;
1509 Ops.push_back(std::make_pair(Op1, 1));
1510 }
else if (ElemTy1) {
1511 KnownElemTy = ElemTy1;
1512 Incomplete = Incomplete1;
1513 Ops.push_back(std::make_pair(Op0, 0));
1517 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1518 else if (HaveFunPtrs)
1519 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1524 if (!KnownElemTy ||
Ops.size() == 0)
1529 for (
auto &OpIt :
Ops) {
1533 Type *AskTy =
nullptr;
1534 CallInst *AskCI =
nullptr;
1535 if (IsPostprocessing && AskOps) {
1541 if (Ty == KnownElemTy)
1544 Type *OpTy =
Op->getType();
1550 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1557 else if (!IsPostprocessing)
1561 if (AssignCI ==
nullptr) {
1570 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1571 std::make_pair(
I,
Op)};
1572 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1576 CallInst *PtrCastI =
1577 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1578 if (OpIt.second == std::numeric_limits<unsigned>::max())
1581 I->setOperand(OpIt.second, PtrCastI);
1587void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1592 if (isAssignTypeInstr(U)) {
1593 B.SetInsertPoint(U);
1594 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1595 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1596 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1598 U->eraseFromParent();
1601 U->replaceUsesOfWith(Old, New);
1609 Type *NewArgTy =
New->getType();
1611 if (NewArgTy != ExpectedArgTy) {
1614 M, Intrinsic::spv_abort, {NewArgTy});
1624 "aggregate PHI/select/freeze should have been mutated to value-id "
1626 U->replaceUsesOfWith(Old, New);
1631 New->copyMetadata(*Old);
1637 bool HasPoisonExt) {
1644 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1645 "lowered as undef\n");
1647 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1648 Type *Ty = UV->getType();
1654 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1655 :
B.CreateIntrinsicWithoutFolding(IID, {});
1656 AggrConsts[
Call] = UV;
1657 AggrConstTypes[
Call] = Ty;
1662 return B.CreateIntrinsic(IID, {Ty}, {});
1669void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1674 SmallVector<Instruction *, 16> Insts;
1678 for (Instruction *
I : Insts) {
1679 bool BPrepared =
false;
1681 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1685 bool IsScalar = !
Op->getType()->isAggregateType();
1688 if (IsScalar && !AsPoison)
1692 if (IsScalar && Phi)
1693 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1694 else if (!BPrepared) {
1698 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1699 I->setOperand(Idx, Repl);
1708void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1712 ASC->replaceAllUsesWith(
1714 ASC->eraseFromParent();
1722 if (!V->getType()->isAggregateType())
1731 I.getType()->isAggregateType();
1737void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1740 for (Use &U :
I->operands()) {
1747 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1752 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1754 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1760void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1764 std::queue<Instruction *> Worklist;
1768 while (!Worklist.empty()) {
1769 auto *
I = Worklist.front();
1772 bool KeepInst =
false;
1773 for (
const auto &
Op :
I->operands()) {
1775 Type *ResTy =
nullptr;
1778 ResTy = COp->getType();
1790 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1793 auto PrepareInsert = [&]() {
1796 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1797 :
B.SetInsertPoint(
I);
1802 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1803 Args.push_back(COp->getElementAsConstant(i));
1809 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1818 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1824 auto *CI =
B.CreateIntrinsicWithoutFolding(
1825 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1829 AggrConsts[CI] = AggrConst;
1830 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1842 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1847 unsigned RoundingModeDeco,
1854 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1863 MDNode *SaturatedConversionNode =
1865 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1885 MDString *ConstraintString =
1894 B.SetInsertPoint(&
Call);
1895 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1900void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1903 if (!
RM.has_value())
1905 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1906 switch (
RM.value()) {
1910 case RoundingMode::NearestTiesToEven:
1911 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1913 case RoundingMode::TowardNegative:
1914 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1916 case RoundingMode::TowardPositive:
1917 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1919 case RoundingMode::TowardZero:
1920 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1922 case RoundingMode::Dynamic:
1923 case RoundingMode::NearestTiesToAway:
1927 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1933Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1937 B.SetInsertPoint(&
I);
1938 SmallVector<Value *, 4>
Args;
1940 Args.push_back(
I.getCondition());
1943 for (
auto &Case :
I.cases()) {
1944 Args.push_back(Case.getCaseValue());
1945 BBCases.
push_back(Case.getCaseSuccessor());
1948 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1949 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1953 I.eraseFromParent();
1956 B.SetInsertPoint(ParentBB);
1957 IndirectBrInst *BrI =
B.CreateIndirectBr(
1960 for (BasicBlock *BBCase : BBCases)
1969Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
1975 B.SetInsertPoint(&
I);
1977 SmallVector<Value *, 4>
Args;
1978 Args.push_back(
B.getInt1(
true));
1979 Args.push_back(
I.getOperand(0));
1980 Args.push_back(
B.getInt32(0));
1981 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1982 Args.push_back(SGEP->getIndexOperand(J));
1985 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1986 replaceAllUsesWithAndErase(
B, &
I, NewI);
1991SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
1993 B.SetInsertPoint(&
I);
1998 unsigned N = RetVTy->getNumElements();
1999 Value *PtrOp =
I.getPointerOperand();
2001 Type *ResultPtrTy = RetVTy->getElementType();
2004 Value *InBounds =
B.getInt1(
I.isInBounds());
2005 Type *LanePointeeTy = getGEPType(&
I);
2006 Type *SrcElemTy =
I.getSourceElementType();
2015 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2016 Value *LaneIdx =
B.getInt32(Lane);
2017 Value *ScalarPtr = PtrOp;
2021 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2025 SmallVector<Value *, 4>
Args;
2026 Args.push_back(InBounds);
2027 Args.push_back(ScalarPtr);
2028 for (
Value *Idx :
I.indices()) {
2030 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
2032 Args.push_back(Idx);
2034 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2036 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2040 replaceAllUsesWithAndErase(
B, &
I, NewI);
2058 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2059 return buildLogicalAccessChainFromGEP(
I);
2064 Value *PtrOp =
I.getPointerOperand();
2065 Type *SrcElemTy =
I.getSourceElementType();
2066 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2069 if (ArrTy->getElementType() == SrcElemTy) {
2071 Type *FirstIdxType =
I.getOperand(1)->getType();
2072 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2073 for (
Value *Idx :
I.indices())
2077 SmallVector<Value *, 4>
Args;
2078 Args.push_back(
B.getInt1(
I.isInBounds()));
2079 Args.push_back(
I.getPointerOperand());
2082 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2084 replaceAllUsesWithAndErase(
B, &
I, NewI);
2091 SmallVector<Value *, 4>
Args;
2092 Args.push_back(
B.getInt1(
I.isInBounds()));
2095 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2096 replaceAllUsesWithAndErase(
B, &
I, NewI);
2100Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2102 B.SetInsertPoint(&
I);
2111 I.eraseFromParent();
2118 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2119 replaceAllUsesWithAndErase(
B, &
I, NewI);
2123void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2125 Type *VTy =
V->getType();
2130 if (ElemTy != AssignedType)
2143 if (CurrentType == AssignedType)
2150 " for value " +
V->getName(),
2158void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2159 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2164 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2165 if (PointerElemTy == ExpectedElementType ||
2171 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2173 bool FirstPtrCastOrAssignPtrType =
true;
2179 for (
auto User :
Pointer->users()) {
2182 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2183 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2184 II->getOperand(0) != Pointer)
2189 FirstPtrCastOrAssignPtrType =
false;
2190 if (
II->getOperand(1) != VMD ||
2197 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2202 if (
II->getParent() !=
I->getParent())
2205 I->setOperand(OperandToReplace,
II);
2220 if (FirstPtrCastOrAssignPtrType) {
2225 }
else if (isTodoType(Pointer)) {
2226 eraseTodoType(Pointer);
2234 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2235 std::make_pair(
I, Pointer)};
2237 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2249 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2255void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2260 replacePointerOperandWithPtrCast(
2261 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2267 Type *OpTy =
Op->getType();
2270 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2273 if (OpTy ==
Op->getType())
2274 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2275 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2280 Type *OpTy = LI->getType();
2285 Type *NewOpTy = OpTy;
2286 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2287 if (OpTy == NewOpTy)
2288 insertTodoType(Pointer);
2291 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2296 Type *OpTy =
nullptr;
2308 OpTy = GEPI->getSourceElementType();
2310 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2312 insertTodoType(Pointer);
2324 std::string DemangledName =
2328 bool HaveTypes =
false;
2346 for (User *U : CalledArg->
users()) {
2348 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2354 HaveTypes |= ElemTy !=
nullptr;
2359 if (DemangledName.empty() && !HaveTypes)
2377 Type *ExpectedType =
2379 if (!ExpectedType && !DemangledName.empty())
2380 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2381 DemangledName,
OpIdx,
I->getContext());
2382 if (!ExpectedType || ExpectedType->
isVoidTy())
2390 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2395SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2402 I.getOperand(1)->getType(),
2403 I.getOperand(2)->getType()};
2405 B.SetInsertPoint(&
I);
2407 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2409 replaceAllUsesWithAndErase(
B, &
I, NewI);
2414SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2421 B.SetInsertPoint(&
I);
2423 I.getIndexOperand()->getType()};
2424 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2425 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2427 replaceAllUsesWithAndErase(
B, &
I, NewI);
2431Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2433 B.SetInsertPoint(&
I);
2436 Value *AggregateOp =
I.getAggregateOperand();
2440 Args.push_back(AggregateOp);
2441 Args.push_back(
I.getInsertedValueOperand());
2442 for (
auto &
Op :
I.indices())
2443 Args.push_back(
B.getInt32(
Op));
2445 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2446 replaceMemInstrUses(&
I, NewI,
B);
2451SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2453 B.SetInsertPoint(&
I);
2454 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2463 for (
auto &
Op :
I.indices())
2464 Args.push_back(
B.getInt32(
Op));
2465 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2466 {
I.getType()}, {
Args});
2467 replaceAllUsesWithAndErase(
B, &
I, NewI);
2471 for (
const Use &U : NewI->
uses()) {
2472 User *Usr =
U.getUser();
2474 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2485 if (ArgNo < FT->getNumParams() &&
2486 !FT->getParamType(ArgNo)->isAggregateType()) {
2495Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2496 if (!
I.getType()->isAggregateType())
2499 B.SetInsertPoint(&
I);
2500 TrackConstants =
false;
2505 unsigned IntrinsicId;
2506 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2507 if (!
I.isAtomic()) {
2508 IntrinsicId = Intrinsic::spv_load;
2509 Args.push_back(
B.getInt32(
I.getAlign().value()));
2511 IntrinsicId = Intrinsic::spv_atomic_load;
2512 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2514 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2515 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2517 replaceMemInstrUses(&
I, NewI,
B);
2521Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2525 B.SetInsertPoint(&
I);
2526 TrackConstants =
false;
2530 auto *PtrOp =
I.getPointerOperand();
2532 if (
I.getValueOperand()->getType()->isAggregateType()) {
2540 "Unexpected argument of aggregate type, should be spv_extractv!");
2544 unsigned IntrinsicId;
2545 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2547 if (!
I.isAtomic()) {
2548 IntrinsicId = Intrinsic::spv_store;
2549 Args.push_back(
B.getInt32(
I.getAlign().value()));
2551 IntrinsicId = Intrinsic::spv_atomic_store;
2552 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2555 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2557 I.eraseFromParent();
2561Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2562 Value *ArraySize =
nullptr;
2563 if (
I.isArrayAllocation()) {
2566 SPIRV::Extension::SPV_INTEL_variable_length_array))
2568 "array allocation: this instruction requires the following "
2569 "SPIR-V extension: SPV_INTEL_variable_length_array",
2571 ArraySize =
I.getArraySize();
2574 B.SetInsertPoint(&
I);
2575 TrackConstants =
false;
2576 Type *PtrTy =
I.getType();
2579 ?
B.CreateIntrinsicWithoutFolding(
2580 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2581 {ArraySize,
B.getInt32(
I.getAlign().value())})
2582 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2583 {
B.getInt32(
I.getAlign().value())});
2584 replaceAllUsesWithAndErase(
B, &
I, NewI);
2589SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2590 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2592 B.SetInsertPoint(&
I);
2594 Args.push_back(
B.getInt32(
2595 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2598 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2599 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2600 uint32_t ScSem =
static_cast<uint32_t
>(
2602 Args.push_back(
B.getInt32(
2604 Args.push_back(
B.getInt32(
2607 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2608 replaceMemInstrUses(&
I, NewI,
B);
2617 case Intrinsic::spv_abort:
2619 case Intrinsic::trap:
2620 case Intrinsic::ubsantrap:
2622 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2642 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2643 "abort-like call must be the last non-debug instruction before its "
2644 "block's terminator");
2648Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2649 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2653 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2660 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2674 while (!Stack.empty()) {
2675 const Value *V = Stack.pop_back_val();
2676 if (!Visited.
insert(V).second)
2684 Stack.append(
C->user_begin(),
C->user_end());
2700 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2701 if (UserFunctions.contains(
F))
2706 if (!UserFunctions.empty())
2711 const Module &M = *
F->getParent();
2712 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2713 return F == &FirstDefinition;
2716Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2718 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2719 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2721 AggrConstTypes[Leaf] = ElemTy;
2724 SmallVector<Value *, 4> Elems;
2726 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2729 DenseMap<Type *, Instruction *> LeafByType;
2730 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2732 auto &
Entry = LeafByType[ElemTy];
2734 Entry = MakeLeaf(ElemTy);
2738 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2739 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2741 AggrConstTypes[Composite] = AggrTy;
2750void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(Function &Func,
2755 for (BasicBlock &BB : Func) {
2759 Value *RetVal = RI->getReturnValue();
2766 B.SetInsertPoint(RI);
2768 for (uint64_t
I = 0;
I < NumElts; ++
I) {
2769 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2770 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2772 RI->setOperand(0, Rebuilt);
2776void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2786 deduceElementTypeHelper(&GV,
false);
2791 Value *InitOp = Init;
2798 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2799 {
B.getInt32Ty()}, {});
2804 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2809 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2810 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2816 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2822bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2824 bool UnknownElemTypeI8) {
2830 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2837void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2840 static StringMap<unsigned> ResTypeWellKnown = {
2841 {
"async_work_group_copy", WellKnownTypes::Event},
2842 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2843 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2847 bool IsKnown =
false;
2852 std::string DemangledName =
2855 if (DemangledName.length() > 0)
2857 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2858 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2859 if (ResIt != ResTypeWellKnown.
end()) {
2862 switch (ResIt->second) {
2863 case WellKnownTypes::Event:
2870 switch (DecorationId) {
2873 case FPDecorationId::SAT:
2876 case FPDecorationId::RTE:
2878 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2880 case FPDecorationId::RTZ:
2882 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2884 case FPDecorationId::RTP:
2886 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2888 case FPDecorationId::RTN:
2890 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2896 Type *Ty =
I->getType();
2899 Type *TypeToAssign = Ty;
2902 auto It = AggrConstTypes.
find(
II);
2903 if (It == AggrConstTypes.
end())
2905 TypeToAssign = It->second;
2906 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2907 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2908 TypeToAssign = It->second;
2910 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2911 TypeToAssign = It->second;
2915 for (
const auto &
Op :
I->operands()) {
2922 Type *OpTy =
Op->getType();
2924 CallInst *AssignCI =
2929 Type *OpTy =
Op->getType();
2944 CallInst *AssignCI =
2954bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
2955 Instruction *Inst) {
2957 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2967void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
2969 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2971 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2976 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2977 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2978 if (shouldTryToAddMemAliasingDecoration(
I)) {
2979 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2980 ? SPIRV::Decoration::AliasScopeINTEL
2981 : SPIRV::Decoration::NoAliasINTEL;
2983 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2986 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2987 {
I->getType()}, {
Args});
2991 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2992 processMemAliasingDecoration(LLVMContext::MD_noalias);
2995 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2997 bool AllowFPMaxError =
2999 if (!AllowFPMaxError)
3003 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3007 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
3011 auto &Ctx =
B.getContext();
3013 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
3016 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3018 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3019 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3022 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
3024 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
3026 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3034 &FPFastMathDefaultInfoMap,
3036 auto it = FPFastMathDefaultInfoMap.
find(
F);
3037 if (it != FPFastMathDefaultInfoMap.
end())
3045 SPIRV::FPFastMathMode::None);
3047 SPIRV::FPFastMathMode::None);
3049 SPIRV::FPFastMathMode::None);
3050 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3056 size_t BitWidth = Ty->getScalarSizeInBits();
3060 assert(Index >= 0 && Index < 3 &&
3061 "Expected FPFastMathDefaultInfo for half, float, or double");
3062 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3063 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3064 return FPFastMathDefaultInfoVec[Index];
3067void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3069 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3078 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3080 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3088 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3091 [[maybe_unused]] GlobalVariable *GV =
3092 new GlobalVariable(M,
3093 Type::getInt32Ty(
M.getContext()),
3107 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3108 FPFastMathDefaultInfoMap;
3110 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3119 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3121 "Expected 4 operands for FPFastMathDefault");
3127 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3129 SPIRV::FPFastMathDefaultInfo &
Info =
3132 Info.FPFastMathDefault =
true;
3133 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3135 "Expected no operands for ContractionOff");
3139 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3141 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3142 Info.ContractionOff =
true;
3144 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3146 "Expected 1 operand for SignedZeroInfNanPreserve");
3147 unsigned TargetWidth =
3152 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3156 assert(Index >= 0 && Index < 3 &&
3157 "Expected FPFastMathDefaultInfo for half, float, or double");
3158 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3159 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3160 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3164 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3165 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3166 if (FPFastMathDefaultInfoVec.
empty())
3169 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3170 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3173 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3174 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3178 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3180 "and AllowContract");
3182 if (
Info.SignedZeroInfNanPreserve &&
3184 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3185 SPIRV::FPFastMathMode::NSZ))) {
3186 if (
Info.FPFastMathDefault)
3188 "SignedZeroInfNanPreserve but at least one of "
3189 "NotNaN/NotInf/NSZ is enabled.");
3192 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3193 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3194 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3196 "AllowTransform requires AllowReassoc and "
3197 "AllowContract to be set.");
3200 auto it = GlobalVars.
find(Flags);
3201 GlobalVariable *GV =
nullptr;
3202 if (it != GlobalVars.
end()) {
3208 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3211 GV =
new GlobalVariable(M,
3212 Type::getInt32Ty(
M.getContext()),
3217 GlobalVars[
Flags] = GV;
3223void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3226 bool IsConstComposite =
3227 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3228 if (IsConstComposite && TrackConstants) {
3230 auto t = AggrConsts.
find(
I);
3234 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3236 NewOp->setArgOperand(0,
I);
3239 for (
const auto &
Op :
I->operands()) {
3243 unsigned OpNo =
Op.getOperandNo();
3244 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3245 (!
II->isBundleOperand(OpNo) &&
3246 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3250 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3251 :
B.SetInsertPoint(
I);
3254 Type *OpTy =
Op->getType();
3262 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3264 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3265 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3267 SmallVector<Value *, 2>
Args = {
3270 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3276 I->setOperand(OpNo, NewOp);
3282Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(Function *
F,
3284 SmallPtrSet<Function *, 0> FVisited;
3285 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3288Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3289 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3291 if (!FVisited.
insert(
F).second)
3294 SmallPtrSet<Value *, 0> Visited;
3297 for (User *U :
F->users()) {
3309 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3312 for (User *OpU : OpArg->
users()) {
3314 if (!Inst || Inst == CI)
3317 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3324 if (FVisited.
find(OuterF) != FVisited.
end())
3326 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3327 if (OuterF->
getArg(i) == OpArg) {
3328 Lookup.push_back(std::make_pair(OuterF, i));
3335 for (
auto &Pair :
Lookup) {
3336 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3343void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(Function *
F,
3345 B.SetInsertPointPastAllocas(
F);
3352 for (User *U : Arg->
users()) {
3354 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3372 for (User *U :
F->users()) {
3388 for (User *U : Arg->
users()) {
3392 CI->
getParent()->getParent() == CurrF) {
3394 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3405void SPIRVEmitIntrinsicsImpl::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3406 B.SetInsertPointPastAllocas(
F);
3412 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3414 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3416 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3428 bool IsNewFTy =
false;
3444bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3447 if (
F.isIntrinsic())
3449 if (
F.isDeclaration()) {
3450 for (User *U :
F.users()) {
3463 for (User *U :
F.users()) {
3465 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3467 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3468 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3475 if (Worklist.
empty())
3478 LLVMContext &Ctx =
M.getContext();
3483 for (Function *
F : Worklist) {
3485 for (
const auto &Arg :
F->args())
3487 IRB.CreateCall(
F, Args);
3489 IRB.CreateRetVoid();
3495void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3496 DenseMap<Function *, CallInst *> Ptrcasts;
3497 for (
auto It : FDeclPtrTys) {
3499 for (
auto *U :
F->users()) {
3504 for (
auto [Idx, ElemTy] : It.second) {
3512 B.SetInsertPointPastAllocas(Arg->
getParent());
3516 }
else if (isaGEP(Param)) {
3517 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3526 .getFirstNonPHIOrDbgOrAlloca());
3546GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3547 GetElementPtrInst *
GEP) {
3554 Type *SrcTy =
GEP->getSourceElementType();
3555 SmallVector<Value *, 8> Indices(
GEP->indices());
3557 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3558 Indices.erase(Indices.begin());
3559 SrcTy = ArrTy->getElementType();
3561 GEP->getNoWrapFlags(),
"",
3562 GEP->getIterator());
3567void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(Function &
F,
3574 if (
ST->canUseExtension(
3575 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3576 for (BasicBlock &BB :
F) {
3578 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3582 SmallVector<unsigned, 1>
Ops =
3584 unsigned LC =
Ops[0];
3585 if (LC == SPIRV::LoopControl::None)
3589 B.SetInsertPoint(Term);
3590 SmallVector<Value *, 4> IntrArgs;
3591 for (
unsigned Op :
Ops)
3593 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3614 SmallVector<unsigned, 1> LoopControlOps =
3616 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3620 B.SetInsertPoint(Header->getTerminator());
3623 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3624 for (
unsigned Imm : LoopControlOps)
3625 Args.emplace_back(
B.getInt32(Imm));
3626 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3630bool SPIRVEmitIntrinsicsImpl::runOnFunction(Function &Func) {
3631 if (
Func.isDeclaration())
3635 GR =
ST.getSPIRVGlobalRegistry();
3639 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3644 AggrConstTypes.
clear();
3647 processParamTypesByFunHeader(CurrF,
B);
3651 SmallPtrSet<Instruction *, 4> DeadInsts;
3656 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3660 GR->addDeducedElementType(SGEP,
3665 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3667 GEP->replaceAllUsesWith(NewGEP);
3671 if (
Type *GepTy = getGEPType(
GEP))
3675 for (
auto *
I : DeadInsts) {
3676 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3677 I->eraseFromParent();
3687 Type *ElTy =
SI->getValueOperand()->getType();
3692 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3693 for (
auto &GV :
Func.getParent()->globals())
3694 processGlobalValue(GV,
B);
3696 reconstructAggregateReturns(Func,
B);
3697 preprocessUndefsAndPoisons(
B);
3698 simplifyNullAddrSpaceCasts();
3699 preprocessCompositeConstants(
B);
3707 Type *I32Ty =
B.getInt32Ty();
3712 insertCompositeAggregateArms(&
I,
B);
3713 AggrConstTypes[&
I] =
I.getType();
3714 I.mutateType(I32Ty);
3717 preprocessBoolVectorBitcasts(Func);
3718 SmallVector<Instruction *> Worklist(
3721 applyDemangledPtrArgTypes(
B);
3724 for (
auto &
I : Worklist) {
3726 if (isConvergenceIntrinsic(
I))
3729 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3731 insertAssignTypeIntrs(
I,
B);
3732 insertPtrCastOrAssignTypeInstr(
I,
B);
3736 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3737 insertAssignPtrTypeIntrs(
I,
B,
true);
3740 useRoundingMode(FPI,
B);
3745 SmallPtrSet<Instruction *, 4> IncompleteRets;
3747 deduceOperandElementType(&
I, &IncompleteRets);
3751 for (BasicBlock &BB : Func)
3752 for (PHINode &Phi : BB.
phis())
3754 deduceOperandElementType(&Phi,
nullptr);
3756 for (
auto *
I : Worklist) {
3757 TrackConstants =
true;
3767 if (isConvergenceIntrinsic(
I))
3771 processInstrAfterVisit(
I,
B);
3774 emitUnstructuredLoopControls(Func,
B);
3780bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3781 if (!GR || TodoTypeSz == 0)
3784 unsigned SzTodo = TodoTypeSz;
3785 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3790 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3791 Type *KnownTy = GR->findDeducedElementType(
Op);
3792 if (!KnownTy || !AssignCI)
3798 SmallPtrSet<Value *, 0> Visited;
3799 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3800 if (ElemTy != KnownTy) {
3801 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3802 propagateElemType(CI, ElemTy, VisitedSubst);
3809 if (
Op->hasUseList()) {
3810 for (User *U :
Op->users()) {
3817 if (TodoTypeSz == 0)
3822 SmallPtrSet<Instruction *, 4> IncompleteRets;
3824 auto It = ToProcess.
find(&
I);
3825 if (It == ToProcess.
end())
3827 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3828 if (It->second.size() == 0)
3830 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3831 if (TodoTypeSz == 0)
3836 return SzTodo > TodoTypeSz;
3840void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
3842 if (!
F.isDeclaration() ||
F.isIntrinsic())
3846 if (DemangledName.empty())
3850 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3851 DemangledName,
ST.getPreferredInstructionSet());
3852 if (Opcode != SPIRV::OpGroupAsyncCopy)
3855 SmallVector<unsigned> Idxs;
3864 LLVMContext &Ctx =
F.getContext();
3866 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3867 if (!TypeStrs.
size())
3870 for (
unsigned Idx : Idxs) {
3871 if (Idx >= TypeStrs.
size())
3874 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3877 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3882bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3883 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3885 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3886 if (!
ST.canUseExtension(
3887 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3888 I.getContext().emitError(
3889 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3893 I.eraseFromParent();
3899 Value *Ptrs =
I.getArgOperand(0);
3901 Value *Passthru =
I.getArgOperand(2);
3904 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3906 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3911 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3913 I.eraseFromParent();
3917 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3918 if (!
ST.canUseExtension(
3919 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3920 I.getContext().emitError(
3921 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3924 I.eraseFromParent();
3931 Value *Ptrs =
I.getArgOperand(1);
3936 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3938 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
3942 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3943 I.eraseFromParent();
3954void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(Function &
F) {
3955 struct BoolVecBitcast {
3957 FixedVectorType *BoolVecTy;
3961 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3963 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3971 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3973 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3977 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3979 Value *Src = BC->getOperand(0);
3980 unsigned BoolVecN = BoolVecTy->getNumElements();
3982 Type *IntTy =
B.getIntNTy(BoolVecN);
3988 IntVal = ConstantInt::get(IntTy, 0);
3989 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3990 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3991 Value *Ext =
B.CreateZExt(Elem, IntTy);
3993 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3994 IntVal =
B.CreateOr(IntVal, Ext);
4000 if (!Src->getType()->isIntegerTy())
4001 IntVal =
B.CreateBitCast(Src, IntTy);
4006 if (!SrcIsBoolVec) {
4009 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4012 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
4013 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4019 if (!BC->getDestTy()->isIntegerTy())
4020 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4023 BC->replaceAllUsesWith(Result);
4024 BC->eraseFromParent();
4028bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4032 if (!
F.isIntrinsic())
4035 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4040 Changed |= processMaskedMemIntrinsic(*
II);
4044 F.eraseFromParent();
4050bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4053 Changed |= convertMaskedMemIntrinsics(M);
4055 parseFunDeclarations(M);
4056 insertConstantsForFPFastMathDefault(M);
4067 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4069 processParamTypes(&
F,
B);
4073 CanTodoType =
false;
4074 Changed |= postprocessTypes(M);
4077 Changed |= processFunctionPointers(M);
4084 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4090 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
MachineInstr unsigned OpIdx
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.
StringSet - A set-like wrapper for the StringMap.
static SymbolRef::Type getType(const Symbol *Sym)
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
This class represents an incoming formal argument to a Function.
const Function * getParent() const
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
static LLVM_ABI BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
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()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
static unsigned getPointerOperandIndex()
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 addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg)
Type * findDeducedCompositeType(const Value *Val)
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld=true)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
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 STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getArrayElementType() const
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
bool isStructTy() const
True if this is an instance of StructType.
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
This function has undefined behavior.
void setOperand(unsigned i, Value *Val)
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
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)
@ 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)
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
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
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::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)
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
auto reverse(ContainerTy &&C)
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
@ Ref
The access may reference the value stored in memory.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
bool hasInitializer(const GlobalVariable *GV)
Type * normalizeType(Type *Ty)
bool isPointerTyOrWrapper(const Type *Ty)
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
PoisonValue * getNormalizedPoisonValue(Type *Ty)
bool isUntypedPointerTy(const Type *T)
Type * reconstitutePeeledArrayType(Type *Ty)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)