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()}) {
1039 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1040 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1045 static StringMap<unsigned> ResTypeByArg = {
1049 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1050 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1051 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1052 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1053 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1054 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1058 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1059 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1061 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1062 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1063 for (User *U :
II->users()) {
1068 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1070 Ty = HandleType->getTypeParameter(0);
1071 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1085 }
else if (
II &&
II->getIntrinsicID() ==
1086 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1090 std::string DemangledName =
1092 if (DemangledName.length() > 0)
1093 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1094 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1095 if (AsArgIt != ResTypeByArg.
end())
1096 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1097 Visited, UnknownElemTypeI8);
1104 if (Ty && !IgnoreKnownType) {
1115Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1116 bool UnknownElemTypeI8) {
1117 SmallPtrSet<Value *, 0> Visited;
1118 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1121Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1122 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1123 bool UnknownElemTypeI8) {
1132 if (!Visited.
insert(U).second)
1137 bool Change =
false;
1138 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1140 assert(
Op &&
"Operands should not be null.");
1141 Type *OpTy =
Op->getType();
1144 if (
Type *NestedTy =
1145 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1152 Change |= Ty != OpTy;
1160 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1161 Type *OpTy = ArrTy->getElementType();
1164 if (
Type *NestedTy =
1165 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1172 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1178 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1179 Type *OpTy = VecTy->getElementType();
1182 if (
Type *NestedTy =
1183 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1190 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1200Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1201 bool UnknownElemTypeI8) {
1202 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1204 if (!UnknownElemTypeI8)
1207 return IntegerType::getInt8Ty(
I->getContext());
1211 Value *PointerOperand) {
1217 return I->getType();
1225bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1227 Type *&KnownElemTy,
bool &Incomplete) {
1231 std::string DemangledName =
1233 if (DemangledName.length() > 0 &&
1235 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1236 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1237 DemangledName,
ST.getPreferredInstructionSet());
1238 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1239 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1245 KnownElemTy = ElemTy;
1246 Ops.push_back(std::make_pair(
Op, i));
1248 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1255 case SPIRV::OpAtomicFAddEXT:
1256 case SPIRV::OpAtomicFMinEXT:
1257 case SPIRV::OpAtomicFMaxEXT:
1258 case SPIRV::OpAtomicLoad:
1259 case SPIRV::OpAtomicCompareExchangeWeak:
1260 case SPIRV::OpAtomicCompareExchange:
1261 case SPIRV::OpAtomicExchange:
1262 case SPIRV::OpAtomicIAdd:
1263 case SPIRV::OpAtomicISub:
1264 case SPIRV::OpAtomicOr:
1265 case SPIRV::OpAtomicXor:
1266 case SPIRV::OpAtomicAnd:
1267 case SPIRV::OpAtomicUMin:
1268 case SPIRV::OpAtomicUMax:
1269 case SPIRV::OpAtomicSMin:
1270 case SPIRV::OpAtomicSMax: {
1275 Incomplete = isTodoType(
Op);
1276 Ops.push_back(std::make_pair(
Op, 0));
1278 case SPIRV::OpAtomicStore: {
1287 Incomplete = isTodoType(
Op);
1288 Ops.push_back(std::make_pair(
Op, 0));
1297void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1299 Type *&KnownElemTy,
bool IsPostprocessing) {
1303 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1304 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1305 bool IsNewFTy =
false, IsIncomplete =
false;
1308 Type *ArgTy = Arg->getType();
1313 if (isTodoType(Arg))
1314 IsIncomplete =
true;
1316 IsIncomplete =
true;
1319 ArgTy = FTy->getFunctionParamType(ParmIdx);
1323 Type *RetTy = FTy->getReturnType();
1330 IsIncomplete =
true;
1332 IsIncomplete =
true;
1335 if (!IsPostprocessing && IsIncomplete)
1338 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1341bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1342 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1343 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1355 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1356 for (User *U :
F->users()) {
1364 propagateElemType(CI, PrevElemTy, VisitedSubst);
1374 for (Instruction *IncompleteRetI : *IncompleteRets)
1375 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1377 }
else if (IncompleteRets) {
1388void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1389 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1390 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1392 Type *KnownElemTy =
nullptr;
1393 bool Incomplete =
false;
1399 Incomplete = isTodoType(
I);
1400 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1403 Ops.push_back(std::make_pair(
Op, i));
1409 Incomplete = isTodoType(
I);
1410 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1417 Incomplete = isTodoType(
I);
1418 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1422 KnownElemTy =
Ref->getSourceElementType();
1423 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1428 KnownElemTy =
Ref->getBaseType();
1429 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1432 KnownElemTy =
I->getType();
1439 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1448 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1452 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1457 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1465 Incomplete = isTodoType(
Ref->getPointerOperand());
1466 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1474 Incomplete = isTodoType(
Ref->getPointerOperand());
1475 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1481 Incomplete = isTodoType(
I);
1482 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1485 Ops.push_back(std::make_pair(
Op, i));
1493 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1494 IsPostprocessing, KnownElemTy,
Op,
1497 Incomplete = isTodoType(CurrF);
1498 Ops.push_back(std::make_pair(
Op, 0));
1504 bool Incomplete0 = isTodoType(Op0);
1505 bool Incomplete1 = isTodoType(Op1);
1507 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1509 : GR->findDeducedElementType(Op0);
1511 KnownElemTy = ElemTy0;
1512 Incomplete = Incomplete0;
1513 Ops.push_back(std::make_pair(Op1, 1));
1514 }
else if (ElemTy1) {
1515 KnownElemTy = ElemTy1;
1516 Incomplete = Incomplete1;
1517 Ops.push_back(std::make_pair(Op0, 0));
1521 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1522 else if (HaveFunPtrs)
1523 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1528 if (!KnownElemTy ||
Ops.size() == 0)
1533 for (
auto &OpIt :
Ops) {
1537 Type *AskTy =
nullptr;
1538 CallInst *AskCI =
nullptr;
1539 if (IsPostprocessing && AskOps) {
1545 if (Ty == KnownElemTy)
1548 Type *OpTy =
Op->getType();
1554 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1561 else if (!IsPostprocessing)
1565 if (AssignCI ==
nullptr) {
1574 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1575 std::make_pair(
I,
Op)};
1576 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1580 CallInst *PtrCastI =
1581 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1582 if (OpIt.second == std::numeric_limits<unsigned>::max())
1585 I->setOperand(OpIt.second, PtrCastI);
1591void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1596 if (isAssignTypeInstr(U)) {
1597 B.SetInsertPoint(U);
1598 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1599 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1600 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1602 U->eraseFromParent();
1605 U->replaceUsesOfWith(Old, New);
1613 Type *NewArgTy =
New->getType();
1615 if (NewArgTy != ExpectedArgTy) {
1618 M, Intrinsic::spv_abort, {NewArgTy});
1628 "aggregate PHI/select/freeze should have been mutated to value-id "
1630 U->replaceUsesOfWith(Old, New);
1635 New->copyMetadata(*Old);
1641 bool HasPoisonExt) {
1648 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1649 "lowered as undef\n");
1651 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1652 Type *Ty = UV->getType();
1658 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1659 :
B.CreateIntrinsicWithoutFolding(IID, {});
1660 AggrConsts[
Call] = UV;
1661 AggrConstTypes[
Call] = Ty;
1666 return B.CreateIntrinsic(IID, {Ty}, {});
1673void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1678 SmallVector<Instruction *, 16> Insts;
1682 for (Instruction *
I : Insts) {
1683 bool BPrepared =
false;
1685 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1689 bool IsScalar = !
Op->getType()->isAggregateType();
1692 if (IsScalar && !AsPoison)
1696 if (IsScalar && Phi)
1697 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1698 else if (!BPrepared) {
1702 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1703 I->setOperand(Idx, Repl);
1712void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1716 ASC->replaceAllUsesWith(
1718 ASC->eraseFromParent();
1726 if (!V->getType()->isAggregateType())
1735 I.getType()->isAggregateType();
1741void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1744 for (Use &U :
I->operands()) {
1751 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1756 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1758 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1764void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1768 std::queue<Instruction *> Worklist;
1772 while (!Worklist.empty()) {
1773 auto *
I = Worklist.front();
1776 bool KeepInst =
false;
1777 for (
const auto &
Op :
I->operands()) {
1779 Type *ResTy =
nullptr;
1782 ResTy = COp->getType();
1794 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1797 auto PrepareInsert = [&]() {
1800 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1801 :
B.SetInsertPoint(
I);
1806 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1807 Args.push_back(COp->getElementAsConstant(i));
1813 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1822 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1828 auto *CI =
B.CreateIntrinsicWithoutFolding(
1829 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1833 AggrConsts[CI] = AggrConst;
1834 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1846 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1851 unsigned RoundingModeDeco,
1858 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1867 MDNode *SaturatedConversionNode =
1869 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1889 MDString *ConstraintString =
1898 B.SetInsertPoint(&
Call);
1899 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1904void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1907 if (!
RM.has_value())
1909 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1910 switch (
RM.value()) {
1914 case RoundingMode::NearestTiesToEven:
1915 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1917 case RoundingMode::TowardNegative:
1918 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1920 case RoundingMode::TowardPositive:
1921 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1923 case RoundingMode::TowardZero:
1924 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1926 case RoundingMode::Dynamic:
1927 case RoundingMode::NearestTiesToAway:
1931 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1937Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
1941 B.SetInsertPoint(&
I);
1942 SmallVector<Value *, 4>
Args;
1944 Args.push_back(
I.getCondition());
1947 for (
auto &Case :
I.cases()) {
1948 Args.push_back(Case.getCaseValue());
1949 BBCases.
push_back(Case.getCaseSuccessor());
1952 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1953 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1957 I.eraseFromParent();
1960 B.SetInsertPoint(ParentBB);
1961 IndirectBrInst *BrI =
B.CreateIndirectBr(
1964 for (BasicBlock *BBCase : BBCases)
1973Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
1979 B.SetInsertPoint(&
I);
1981 SmallVector<Value *, 4>
Args;
1982 Args.push_back(
B.getInt1(
true));
1983 Args.push_back(
I.getOperand(0));
1984 Args.push_back(
B.getInt32(0));
1985 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1986 Args.push_back(SGEP->getIndexOperand(J));
1989 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1990 replaceAllUsesWithAndErase(
B, &
I, NewI);
1995SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
1997 B.SetInsertPoint(&
I);
2002 unsigned N = RetVTy->getNumElements();
2003 Value *PtrOp =
I.getPointerOperand();
2005 Type *ResultPtrTy = RetVTy->getElementType();
2008 Value *InBounds =
B.getInt1(
I.isInBounds());
2009 Type *LanePointeeTy = getGEPType(&
I);
2010 Type *SrcElemTy =
I.getSourceElementType();
2019 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2020 Value *LaneIdx =
B.getInt32(Lane);
2021 Value *ScalarPtr = PtrOp;
2025 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2029 SmallVector<Value *, 4>
Args;
2030 Args.push_back(InBounds);
2031 Args.push_back(ScalarPtr);
2032 for (
Value *Idx :
I.indices()) {
2034 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
2036 Args.push_back(Idx);
2038 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2040 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2044 replaceAllUsesWithAndErase(
B, &
I, NewI);
2062 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2063 return buildLogicalAccessChainFromGEP(
I);
2068 Value *PtrOp =
I.getPointerOperand();
2069 Type *SrcElemTy =
I.getSourceElementType();
2070 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2073 if (ArrTy->getElementType() == SrcElemTy) {
2075 Type *FirstIdxType =
I.getOperand(1)->getType();
2076 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2077 for (
Value *Idx :
I.indices())
2081 SmallVector<Value *, 4>
Args;
2082 Args.push_back(
B.getInt1(
I.isInBounds()));
2083 Args.push_back(
I.getPointerOperand());
2086 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2088 replaceAllUsesWithAndErase(
B, &
I, NewI);
2095 SmallVector<Value *, 4>
Args;
2096 Args.push_back(
B.getInt1(
I.isInBounds()));
2099 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2100 replaceAllUsesWithAndErase(
B, &
I, NewI);
2104Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2106 B.SetInsertPoint(&
I);
2115 I.eraseFromParent();
2122 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2123 replaceAllUsesWithAndErase(
B, &
I, NewI);
2127void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2129 Type *VTy =
V->getType();
2134 if (ElemTy != AssignedType)
2147 if (CurrentType == AssignedType)
2154 " for value " +
V->getName(),
2162void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2163 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2168 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2169 if (PointerElemTy == ExpectedElementType ||
2175 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2177 bool FirstPtrCastOrAssignPtrType =
true;
2183 for (
auto User :
Pointer->users()) {
2186 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2187 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2188 II->getOperand(0) != Pointer)
2193 FirstPtrCastOrAssignPtrType =
false;
2194 if (
II->getOperand(1) != VMD ||
2201 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2206 if (
II->getParent() !=
I->getParent())
2209 I->setOperand(OperandToReplace,
II);
2224 if (FirstPtrCastOrAssignPtrType) {
2229 }
else if (isTodoType(Pointer)) {
2230 eraseTodoType(Pointer);
2238 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2239 std::make_pair(
I, Pointer)};
2241 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2253 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2259void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2264 replacePointerOperandWithPtrCast(
2265 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2271 Type *OpTy =
Op->getType();
2274 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2277 if (OpTy ==
Op->getType())
2278 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2279 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2284 Type *OpTy = LI->getType();
2289 Type *NewOpTy = OpTy;
2290 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2291 if (OpTy == NewOpTy)
2292 insertTodoType(Pointer);
2295 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2300 Type *OpTy =
nullptr;
2312 OpTy = GEPI->getSourceElementType();
2314 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2316 insertTodoType(Pointer);
2328 std::string DemangledName =
2332 bool HaveTypes =
false;
2350 for (User *U : CalledArg->
users()) {
2352 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2358 HaveTypes |= ElemTy !=
nullptr;
2363 if (DemangledName.empty() && !HaveTypes)
2381 Type *ExpectedType =
2383 if (!ExpectedType && !DemangledName.empty())
2384 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2385 DemangledName,
OpIdx,
I->getContext());
2386 if (!ExpectedType || ExpectedType->
isVoidTy())
2394 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2399SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2406 I.getOperand(1)->getType(),
2407 I.getOperand(2)->getType()};
2409 B.SetInsertPoint(&
I);
2411 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2413 replaceAllUsesWithAndErase(
B, &
I, NewI);
2418SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2425 B.SetInsertPoint(&
I);
2427 I.getIndexOperand()->getType()};
2428 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2429 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2431 replaceAllUsesWithAndErase(
B, &
I, NewI);
2435Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2437 B.SetInsertPoint(&
I);
2440 Value *AggregateOp =
I.getAggregateOperand();
2444 Args.push_back(AggregateOp);
2445 Args.push_back(
I.getInsertedValueOperand());
2446 for (
auto &
Op :
I.indices())
2447 Args.push_back(
B.getInt32(
Op));
2449 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2450 replaceMemInstrUses(&
I, NewI,
B);
2455SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2457 B.SetInsertPoint(&
I);
2458 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2467 for (
auto &
Op :
I.indices())
2468 Args.push_back(
B.getInt32(
Op));
2469 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2470 {
I.getType()}, {
Args});
2476 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2477 AggrConstTypes[NewI] =
I.getType();
2479 replaceMemInstrUses(&
I, NewI,
B);
2482 replaceAllUsesWithAndErase(
B, &
I, NewI);
2486 for (
const Use &U : NewI->
uses()) {
2487 User *Usr =
U.getUser();
2489 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2500 if (ArgNo < FT->getNumParams() &&
2501 !FT->getParamType(ArgNo)->isAggregateType()) {
2510Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2511 if (!
I.getType()->isAggregateType())
2514 B.SetInsertPoint(&
I);
2515 TrackConstants =
false;
2520 unsigned IntrinsicId;
2521 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2522 if (!
I.isAtomic()) {
2523 IntrinsicId = Intrinsic::spv_load;
2524 Args.push_back(
B.getInt32(
I.getAlign().value()));
2526 IntrinsicId = Intrinsic::spv_atomic_load;
2527 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2529 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2530 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2532 replaceMemInstrUses(&
I, NewI,
B);
2536Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2540 B.SetInsertPoint(&
I);
2541 TrackConstants =
false;
2545 auto *PtrOp =
I.getPointerOperand();
2547 if (
I.getValueOperand()->getType()->isAggregateType()) {
2555 "Unexpected argument of aggregate type, should be spv_extractv!");
2559 unsigned IntrinsicId;
2560 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2562 if (!
I.isAtomic()) {
2563 IntrinsicId = Intrinsic::spv_store;
2564 Args.push_back(
B.getInt32(
I.getAlign().value()));
2566 IntrinsicId = Intrinsic::spv_atomic_store;
2567 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2570 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2572 I.eraseFromParent();
2576Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2577 Value *ArraySize =
nullptr;
2578 if (
I.isArrayAllocation()) {
2581 SPIRV::Extension::SPV_INTEL_variable_length_array))
2583 "array allocation: this instruction requires the following "
2584 "SPIR-V extension: SPV_INTEL_variable_length_array",
2586 ArraySize =
I.getArraySize();
2589 B.SetInsertPoint(&
I);
2590 TrackConstants =
false;
2591 Type *PtrTy =
I.getType();
2594 ?
B.CreateIntrinsicWithoutFolding(
2595 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2596 {ArraySize,
B.getInt32(
I.getAlign().value())})
2597 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2598 {
B.getInt32(
I.getAlign().value())});
2599 replaceAllUsesWithAndErase(
B, &
I, NewI);
2604SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2605 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2607 B.SetInsertPoint(&
I);
2609 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2613 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2614 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2615 uint32_t ScSem =
static_cast<uint32_t
>(
2617 Args.push_back(
B.getInt32(
2619 Args.push_back(
B.getInt32(
2622 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2623 replaceMemInstrUses(&
I, NewI,
B);
2632 case Intrinsic::spv_abort:
2634 case Intrinsic::trap:
2635 case Intrinsic::ubsantrap:
2637 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2657 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2658 "abort-like call must be the last non-debug instruction before its "
2659 "block's terminator");
2663Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2664 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2668 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2675 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2689 while (!Stack.empty()) {
2690 const Value *V = Stack.pop_back_val();
2691 if (!Visited.
insert(V).second)
2699 Stack.append(
C->user_begin(),
C->user_end());
2715 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2716 if (UserFunctions.contains(
F))
2721 if (!UserFunctions.empty())
2726 const Module &M = *
F->getParent();
2727 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2728 return F == &FirstDefinition;
2731Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2733 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2734 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2736 AggrConstTypes[Leaf] = ElemTy;
2739 SmallVector<Value *, 4> Elems;
2741 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2744 DenseMap<Type *, Instruction *> LeafByType;
2745 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2747 auto &
Entry = LeafByType[ElemTy];
2749 Entry = MakeLeaf(ElemTy);
2753 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2754 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2756 AggrConstTypes[Composite] = AggrTy;
2765void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(Function &Func,
2770 for (BasicBlock &BB : Func) {
2774 Value *RetVal = RI->getReturnValue();
2781 B.SetInsertPoint(RI);
2783 for (uint64_t
I = 0;
I < NumElts; ++
I) {
2784 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2785 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2787 RI->setOperand(0, Rebuilt);
2791void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2801 deduceElementTypeHelper(&GV,
false);
2806 Value *InitOp = Init;
2813 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2814 {
B.getInt32Ty()}, {});
2819 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2824 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2825 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2831 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2837bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
2839 bool UnknownElemTypeI8) {
2845 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2852void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
2855 static StringMap<unsigned> ResTypeWellKnown = {
2856 {
"async_work_group_copy", WellKnownTypes::Event},
2857 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2858 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2862 bool IsKnown =
false;
2867 std::string DemangledName =
2870 if (DemangledName.length() > 0)
2872 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2873 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2874 if (ResIt != ResTypeWellKnown.
end()) {
2877 switch (ResIt->second) {
2878 case WellKnownTypes::Event:
2885 switch (DecorationId) {
2888 case FPDecorationId::SAT:
2891 case FPDecorationId::RTE:
2893 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2895 case FPDecorationId::RTZ:
2897 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2899 case FPDecorationId::RTP:
2901 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2903 case FPDecorationId::RTN:
2905 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2911 Type *Ty =
I->getType();
2914 Type *TypeToAssign = Ty;
2917 auto It = AggrConstTypes.
find(
II);
2918 if (It == AggrConstTypes.
end())
2920 TypeToAssign = It->second;
2921 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2922 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2923 TypeToAssign = It->second;
2925 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2926 TypeToAssign = It->second;
2930 for (
const auto &
Op :
I->operands()) {
2937 Type *OpTy =
Op->getType();
2939 CallInst *AssignCI =
2944 Type *OpTy =
Op->getType();
2959 CallInst *AssignCI =
2969bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
2970 Instruction *Inst) {
2972 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2982void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
2984 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2986 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2991 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2992 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2993 if (shouldTryToAddMemAliasingDecoration(
I)) {
2994 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2995 ? SPIRV::Decoration::AliasScopeINTEL
2996 : SPIRV::Decoration::NoAliasINTEL;
2998 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3001 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3002 {
I->getType()}, {
Args});
3006 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3007 processMemAliasingDecoration(LLVMContext::MD_noalias);
3010 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3012 bool AllowFPMaxError =
3014 if (!AllowFPMaxError)
3018 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3022 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
3026 auto &Ctx =
B.getContext();
3028 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
3031 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3033 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3034 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3037 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
3039 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
3041 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3049 &FPFastMathDefaultInfoMap,
3051 auto it = FPFastMathDefaultInfoMap.
find(
F);
3052 if (it != FPFastMathDefaultInfoMap.
end())
3060 SPIRV::FPFastMathMode::None);
3062 SPIRV::FPFastMathMode::None);
3064 SPIRV::FPFastMathMode::None);
3065 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3071 size_t BitWidth = Ty->getScalarSizeInBits();
3075 assert(Index >= 0 && Index < 3 &&
3076 "Expected FPFastMathDefaultInfo for half, float, or double");
3077 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3078 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3079 return FPFastMathDefaultInfoVec[Index];
3082void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3084 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3093 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3095 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3103 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3106 [[maybe_unused]] GlobalVariable *GV =
3107 new GlobalVariable(M,
3108 Type::getInt32Ty(
M.getContext()),
3122 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3123 FPFastMathDefaultInfoMap;
3125 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3134 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3136 "Expected 4 operands for FPFastMathDefault");
3142 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3144 SPIRV::FPFastMathDefaultInfo &
Info =
3147 Info.FPFastMathDefault =
true;
3148 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3150 "Expected no operands for ContractionOff");
3154 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3156 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3157 Info.ContractionOff =
true;
3159 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3161 "Expected 1 operand for SignedZeroInfNanPreserve");
3162 unsigned TargetWidth =
3167 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3171 assert(Index >= 0 && Index < 3 &&
3172 "Expected FPFastMathDefaultInfo for half, float, or double");
3173 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3174 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3175 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3179 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3180 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3181 if (FPFastMathDefaultInfoVec.
empty())
3184 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3185 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3188 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3189 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3193 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3195 "and AllowContract");
3197 if (
Info.SignedZeroInfNanPreserve &&
3199 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3200 SPIRV::FPFastMathMode::NSZ))) {
3201 if (
Info.FPFastMathDefault)
3203 "SignedZeroInfNanPreserve but at least one of "
3204 "NotNaN/NotInf/NSZ is enabled.");
3207 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3208 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3209 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3211 "AllowTransform requires AllowReassoc and "
3212 "AllowContract to be set.");
3215 auto it = GlobalVars.
find(Flags);
3216 GlobalVariable *GV =
nullptr;
3217 if (it != GlobalVars.
end()) {
3223 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3226 GV =
new GlobalVariable(M,
3227 Type::getInt32Ty(
M.getContext()),
3232 GlobalVars[
Flags] = GV;
3238void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3241 bool IsConstComposite =
3242 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3243 if (IsConstComposite && TrackConstants) {
3245 auto t = AggrConsts.
find(
I);
3249 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3251 NewOp->setArgOperand(0,
I);
3254 for (
const auto &
Op :
I->operands()) {
3258 unsigned OpNo =
Op.getOperandNo();
3259 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3260 (!
II->isBundleOperand(OpNo) &&
3261 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3265 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3266 :
B.SetInsertPoint(
I);
3269 Type *OpTy =
Op->getType();
3277 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3279 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3280 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3282 SmallVector<Value *, 2>
Args = {
3285 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3291 I->setOperand(OpNo, NewOp);
3297Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(Function *
F,
3299 SmallPtrSet<Function *, 0> FVisited;
3300 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3303Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3304 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3306 if (!FVisited.
insert(
F).second)
3309 SmallPtrSet<Value *, 0> Visited;
3312 for (User *U :
F->users()) {
3324 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3327 for (User *OpU : OpArg->
users()) {
3329 if (!Inst || Inst == CI)
3332 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3339 if (FVisited.
find(OuterF) != FVisited.
end())
3341 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3342 if (OuterF->
getArg(i) == OpArg) {
3343 Lookup.push_back(std::make_pair(OuterF, i));
3350 for (
auto &Pair :
Lookup) {
3351 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3358void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(Function *
F,
3360 B.SetInsertPointPastAllocas(
F);
3367 for (User *U : Arg->
users()) {
3369 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3387 for (User *U :
F->users()) {
3403 for (User *U : Arg->
users()) {
3407 CI->
getParent()->getParent() == CurrF) {
3409 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3420void SPIRVEmitIntrinsicsImpl::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3421 B.SetInsertPointPastAllocas(
F);
3427 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3429 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3431 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3443 bool IsNewFTy =
false;
3459bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3462 if (
F.isIntrinsic())
3464 if (
F.isDeclaration()) {
3465 for (User *U :
F.users()) {
3478 for (User *U :
F.users()) {
3480 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3482 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3483 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3490 if (Worklist.
empty())
3493 LLVMContext &Ctx =
M.getContext();
3498 for (Function *
F : Worklist) {
3500 for (
const auto &Arg :
F->args())
3502 IRB.CreateCall(
F, Args);
3504 IRB.CreateRetVoid();
3510void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3511 DenseMap<Function *, CallInst *> Ptrcasts;
3512 for (
auto It : FDeclPtrTys) {
3514 for (
auto *U :
F->users()) {
3519 for (
auto [Idx, ElemTy] : It.second) {
3527 B.SetInsertPointPastAllocas(Arg->
getParent());
3531 }
else if (isaGEP(Param)) {
3532 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3541 .getFirstNonPHIOrDbgOrAlloca());
3561GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3562 GetElementPtrInst *
GEP) {
3569 Type *SrcTy =
GEP->getSourceElementType();
3570 SmallVector<Value *, 8> Indices(
GEP->indices());
3572 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3573 Indices.erase(Indices.begin());
3574 SrcTy = ArrTy->getElementType();
3576 GEP->getNoWrapFlags(),
"",
3577 GEP->getIterator());
3582void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(Function &
F,
3589 if (
ST->canUseExtension(
3590 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3591 for (BasicBlock &BB :
F) {
3593 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3597 SmallVector<unsigned, 1>
Ops =
3599 unsigned LC =
Ops[0];
3600 if (LC == SPIRV::LoopControl::None)
3604 B.SetInsertPoint(Term);
3605 SmallVector<Value *, 4> IntrArgs;
3606 for (
unsigned Op :
Ops)
3608 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3629 SmallVector<unsigned, 1> LoopControlOps =
3631 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3635 B.SetInsertPoint(Header->getTerminator());
3638 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3639 for (
unsigned Imm : LoopControlOps)
3640 Args.emplace_back(
B.getInt32(Imm));
3641 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3645bool SPIRVEmitIntrinsicsImpl::runOnFunction(Function &Func) {
3646 if (
Func.isDeclaration())
3650 GR =
ST.getSPIRVGlobalRegistry();
3654 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3659 AggrConstTypes.
clear();
3662 processParamTypesByFunHeader(CurrF,
B);
3666 SmallPtrSet<Instruction *, 4> DeadInsts;
3669 Type *ElTy =
SI->getValueOperand()->getType();
3678 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3682 GR->addDeducedElementType(SGEP,
3687 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3689 GEP->replaceAllUsesWith(NewGEP);
3693 if (
Type *GepTy = getGEPType(
GEP))
3697 for (
auto *
I : DeadInsts) {
3698 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3699 I->eraseFromParent();
3702 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3703 for (
auto &GV :
Func.getParent()->globals())
3704 processGlobalValue(GV,
B);
3706 reconstructAggregateReturns(Func,
B);
3707 preprocessUndefsAndPoisons(
B);
3708 simplifyNullAddrSpaceCasts();
3709 preprocessCompositeConstants(
B);
3717 Type *I32Ty =
B.getInt32Ty();
3722 insertCompositeAggregateArms(&
I,
B);
3723 AggrConstTypes[&
I] =
I.getType();
3724 I.mutateType(I32Ty);
3727 preprocessBoolVectorBitcasts(Func);
3728 SmallVector<Instruction *> Worklist(
3731 applyDemangledPtrArgTypes(
B);
3734 for (
auto &
I : Worklist) {
3736 if (isConvergenceIntrinsic(
I))
3739 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3741 insertAssignTypeIntrs(
I,
B);
3742 insertPtrCastOrAssignTypeInstr(
I,
B);
3746 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3747 insertAssignPtrTypeIntrs(
I,
B,
true);
3750 useRoundingMode(FPI,
B);
3755 SmallPtrSet<Instruction *, 4> IncompleteRets;
3757 deduceOperandElementType(&
I, &IncompleteRets);
3761 for (BasicBlock &BB : Func)
3762 for (PHINode &Phi : BB.
phis())
3764 deduceOperandElementType(&Phi,
nullptr);
3766 for (
auto *
I : Worklist) {
3767 TrackConstants =
true;
3777 if (isConvergenceIntrinsic(
I))
3781 processInstrAfterVisit(
I,
B);
3784 emitUnstructuredLoopControls(Func,
B);
3790bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3791 if (!GR || TodoTypeSz == 0)
3794 unsigned SzTodo = TodoTypeSz;
3795 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3800 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3801 Type *KnownTy = GR->findDeducedElementType(
Op);
3802 if (!KnownTy || !AssignCI)
3808 SmallPtrSet<Value *, 0> Visited;
3809 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3810 if (ElemTy != KnownTy) {
3811 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3812 propagateElemType(CI, ElemTy, VisitedSubst);
3819 if (
Op->hasUseList()) {
3820 for (User *U :
Op->users()) {
3827 if (TodoTypeSz == 0)
3832 SmallPtrSet<Instruction *, 4> IncompleteRets;
3834 auto It = ToProcess.
find(&
I);
3835 if (It == ToProcess.
end())
3837 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3838 if (It->second.size() == 0)
3840 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3841 if (TodoTypeSz == 0)
3846 return SzTodo > TodoTypeSz;
3850void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
3852 if (!
F.isDeclaration() ||
F.isIntrinsic())
3856 if (DemangledName.empty())
3860 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3861 DemangledName,
ST.getPreferredInstructionSet());
3862 if (Opcode != SPIRV::OpGroupAsyncCopy)
3865 SmallVector<unsigned> Idxs;
3874 LLVMContext &Ctx =
F.getContext();
3876 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3877 if (!TypeStrs.
size())
3880 for (
unsigned Idx : Idxs) {
3881 if (Idx >= TypeStrs.
size())
3884 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3887 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3892bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3893 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3895 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3896 if (!
ST.canUseExtension(
3897 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3898 I.getContext().emitError(
3899 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3903 I.eraseFromParent();
3909 Value *Ptrs =
I.getArgOperand(0);
3911 Value *Passthru =
I.getArgOperand(2);
3914 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3916 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3921 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3923 I.eraseFromParent();
3927 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3928 if (!
ST.canUseExtension(
3929 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3930 I.getContext().emitError(
3931 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3934 I.eraseFromParent();
3941 Value *Ptrs =
I.getArgOperand(1);
3946 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3948 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
3952 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3953 I.eraseFromParent();
3964void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(Function &
F) {
3965 struct BoolVecBitcast {
3967 FixedVectorType *BoolVecTy;
3971 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3973 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3981 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3983 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3987 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3989 Value *Src = BC->getOperand(0);
3990 unsigned BoolVecN = BoolVecTy->getNumElements();
3992 Type *IntTy =
B.getIntNTy(BoolVecN);
3998 IntVal = ConstantInt::get(IntTy, 0);
3999 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4000 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
4001 Value *Ext =
B.CreateZExt(Elem, IntTy);
4003 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
4004 IntVal =
B.CreateOr(IntVal, Ext);
4010 if (!Src->getType()->isIntegerTy())
4011 IntVal =
B.CreateBitCast(Src, IntTy);
4016 if (!SrcIsBoolVec) {
4019 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
4022 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
4023 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4029 if (!BC->getDestTy()->isIntegerTy())
4030 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4033 BC->replaceAllUsesWith(Result);
4034 BC->eraseFromParent();
4038bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4042 if (!
F.isIntrinsic())
4045 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4050 Changed |= processMaskedMemIntrinsic(*
II);
4054 F.eraseFromParent();
4060bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4063 Changed |= convertMaskedMemIntrinsics(M);
4065 parseFunDeclarations(M);
4066 insertConstantsForFPFastMathDefault(M);
4077 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4079 processParamTypes(&
F,
B);
4083 CanTodoType =
false;
4084 Changed |= postprocessTypes(M);
4087 Changed |= processFunctionPointers(M);
4094 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4100 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 Triple & getTargetTriple() const
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::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)
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)
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)