29#include "llvm/IR/IntrinsicsSPIRV.h"
62#define DEBUG_TYPE "spirv-emit-intrinsics"
66 cl::desc(
"Emit OpName for all instructions"),
70#define GET_BuiltinGroup_DECL
71#include "SPIRVGenTables.inc"
76class GlobalVariableUsers {
77 template <
typename T1,
typename T2>
78 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
80 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
82 void collectGlobalUsers(
83 const GlobalVariable *GV,
84 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
85 &GlobalIsUsedByGlobal) {
87 while (!
Stack.empty()) {
91 GlobalIsUsedByFun[GV].insert(
I->getFunction());
96 GlobalIsUsedByGlobal[GV].insert(UserGV);
101 Stack.append(
C->user_begin(),
C->user_end());
105 bool propagateGlobalToGlobalUsers(
106 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
107 &GlobalIsUsedByGlobal) {
110 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
111 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
112 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
113 auto It = GlobalIsUsedByGlobal.find(UserGV);
114 if (It == GlobalIsUsedByGlobal.end())
122 void propagateGlobalToFunctionReferences(
123 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
124 &GlobalIsUsedByGlobal) {
125 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
126 auto &UserFunctions = GlobalIsUsedByFun[GV];
127 for (
const GlobalVariable *UserGV : UserGlobals) {
128 auto It = GlobalIsUsedByFun.find(UserGV);
129 if (It == GlobalIsUsedByFun.end())
140 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
141 GlobalIsUsedByGlobal;
142 GlobalIsUsedByFun.clear();
143 for (GlobalVariable &GV :
M.globals())
144 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
147 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
150 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
153 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
154 const FunctionSetType &
155 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
156 auto It = GlobalIsUsedByFun.find(&GV);
157 if (It != GlobalIsUsedByFun.end())
160 static const FunctionSetType
Empty{};
165static bool isaGEP(
const Value *V) {
171static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
177 return AT->getNumElements();
183class SPIRVEmitIntrinsics
185 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
186 const SPIRVTargetMachine &TM;
187 SPIRVGlobalRegistry *GR =
nullptr;
189 bool TrackConstants =
true;
190 bool HaveFunPtrs =
false;
191 DenseMap<Instruction *, Constant *> AggrConsts;
192 DenseMap<Instruction *, Type *> AggrConstTypes;
193 SmallPtrSet<Instruction *, 0> AggrStores;
194 GlobalVariableUsers GVUsers;
195 SmallPtrSet<Value *, 0> Named;
198 DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
201 bool CanTodoType =
true;
202 unsigned TodoTypeSz = 0;
203 DenseMap<Value *, bool> TodoType;
204 void insertTodoType(
Value *
Op) {
206 if (CanTodoType && !isaGEP(
Op)) {
207 auto It = TodoType.try_emplace(
Op,
true);
212 void eraseTodoType(
Value *
Op) {
213 auto It = TodoType.find(
Op);
214 if (It != TodoType.end() && It->second) {
222 auto It = TodoType.find(
Op);
223 return It != TodoType.end() && It->second;
227 SmallPtrSet<Instruction *, 0> TypeValidated;
230 enum WellKnownTypes { Event };
233 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
234 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
235 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
236 bool UnknownElemTypeI8,
237 bool IgnoreKnownType =
false);
238 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
239 bool UnknownElemTypeI8);
240 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
241 SmallPtrSetImpl<Value *> &Visited,
242 bool UnknownElemTypeI8);
244 SmallPtrSetImpl<Value *> &Visited,
245 bool UnknownElemTypeI8);
247 bool UnknownElemTypeI8);
250 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
251 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
252 SmallPtrSetImpl<Value *> &Visited,
253 bool UnknownElemTypeI8);
257 deduceOperandElementType(Instruction *
I,
258 SmallPtrSetImpl<Instruction *> *IncompleteRets,
259 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
260 bool IsPostprocessing =
false);
265 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
266 void simplifyNullAddrSpaceCasts();
268 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
269 bool IsPostprocessing);
271 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
273 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
274 bool UnknownElemTypeI8);
276 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *V,
278 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
279 Type *ExpectedElementType,
280 unsigned OperandToReplace,
282 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
283 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
285 void insertConstantsForFPFastMathDefault(
Module &M);
287 void reconstructAggregateReturns(Function &Func,
IRBuilder<> &
B);
288 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
290 void processParamTypesByFunHeader(Function *
F,
IRBuilder<> &
B);
291 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx);
292 Type *deduceFunParamElementType(Function *
F,
unsigned OpIdx,
293 SmallPtrSetImpl<Function *> &FVisited);
295 bool deduceOperandElementTypeCalledFunction(
297 Type *&KnownElemTy,
bool &Incomplete);
298 void deduceOperandElementTypeFunctionPointer(
300 Type *&KnownElemTy,
bool IsPostprocessing);
301 bool deduceOperandElementTypeFunctionRet(
302 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
303 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
306 CallInst *buildSpvPtrcast(Function *
F,
Value *
Op,
Type *ElemTy);
307 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
308 DenseMap<Function *, CallInst *> Ptrcasts);
310 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
313 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
314 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
315 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
316 SmallPtrSetImpl<Value *> &Visited,
317 DenseMap<Function *, CallInst *> Ptrcasts);
320 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
321 Instruction *Dest,
bool DeleteOld =
true);
325 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
328 bool postprocessTypes(
Module &M);
329 bool processFunctionPointers(
Module &M);
330 void parseFunDeclarations(
Module &M);
331 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
332 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
333 bool convertMaskedMemIntrinsics(
Module &M);
334 void preprocessBoolVectorBitcasts(Function &
F);
336 void emitUnstructuredLoopControls(Function &
F,
IRBuilder<> &
B);
353 bool walkLogicalAccessChain(
354 GetElementPtrInst &
GEP,
355 const std::function<
void(
Type *PointedType, uint64_t Index)>
358 uint64_t Multiplier)> &OnDynamicIndexing);
360 bool walkLogicalAccessChainDynamic(
361 Type *CurType,
Value *Operand, uint64_t Multiplier,
362 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
363 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing);
365 bool walkLogicalAccessChainConstant(
367 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing);
373 Type *getGEPType(GetElementPtrInst *
GEP);
380 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
382 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
386 SPIRVEmitIntrinsics(
const SPIRVTargetMachine &TM) : ModulePass(ID), TM(TM) {}
389 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
392 Instruction *visitInsertElementInst(InsertElementInst &
I);
393 Instruction *visitExtractElementInst(ExtractElementInst &
I);
395 Instruction *visitExtractValueInst(ExtractValueInst &
I);
399 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
403 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
405 bool runOnModule(
Module &M)
override;
407 void getAnalysisUsage(AnalysisUsage &AU)
const override {
408 ModulePass::getAnalysisUsage(AU);
414 Intrinsic::experimental_convergence_loop,
415 Intrinsic::experimental_convergence_anchor>());
418bool expectIgnoredInIRTranslation(
const Instruction *
I) {
420 Intrinsic::spv_resource_handlefrombinding,
421 Intrinsic::spv_resource_getbasepointer,
422 Intrinsic::spv_resource_getpointer>());
429 return getPointerRoot(V);
435char SPIRVEmitIntrinsics::ID = 0;
438 "SPIRV emit intrinsics",
false,
false)
452 bool IsUndefAggregate =
isa<UndefValue>(V) && V->getType()->isAggregateType();
465 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrDbgOrAlloca());
471 B.SetCurrentDebugLocation(
I->getDebugLoc());
472 if (
I->getType()->isVoidTy())
473 B.SetInsertPoint(
I->getNextNode());
475 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
485 if (
I->getType()->isTokenTy())
487 "does not support token type",
492 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
493 expectIgnoredInIRTranslation(
I))
504 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
515 std::vector<Value *> Args = {
518 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
521void SPIRVEmitIntrinsics::replaceAllUsesWith(
Value *Src,
Value *Dest,
525 if (isTodoType(Src)) {
528 insertTodoType(Dest);
532void SPIRVEmitIntrinsics::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
537 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
538 Src->eraseFromParent();
541 if (Named.
insert(Dest).second)
556 V = V->stripPointerCasts();
577Type *SPIRVEmitIntrinsics::reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
578 bool IsPostprocessing) {
582 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
596 if (UnknownElemTypeI8) {
597 if (!IsPostprocessing)
605CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *
F,
Value *
Op,
613 B.SetInsertPointPastAllocas(OpA->getParent());
616 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrDbgOrAlloca());
618 Type *OpTy =
Op->getType();
622 CallInst *PtrCasted =
623 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
628void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast(
630 DenseMap<Function *, CallInst *> Ptrcasts) {
632 CallInst *PtrCastedI =
nullptr;
633 auto It = Ptrcasts.
find(
F);
634 if (It == Ptrcasts.
end()) {
635 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
636 Ptrcasts[
F] = PtrCastedI;
638 PtrCastedI = It->second;
640 I->replaceUsesOfWith(
Op, PtrCastedI);
643void SPIRVEmitIntrinsics::propagateElemType(
645 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
646 DenseMap<Function *, CallInst *> Ptrcasts;
648 for (
auto *U :
Users) {
651 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
656 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
657 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
661void SPIRVEmitIntrinsics::propagateElemTypeRec(
663 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
664 SmallPtrSet<Value *, 0> Visited;
665 DenseMap<Function *, CallInst *> Ptrcasts;
666 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
667 std::move(Ptrcasts));
670void SPIRVEmitIntrinsics::propagateElemTypeRec(
672 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
673 SmallPtrSetImpl<Value *> &Visited,
674 DenseMap<Function *, CallInst *> Ptrcasts) {
678 for (
auto *U :
Users) {
681 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
686 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
687 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
695SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
696 bool UnknownElemTypeI8) {
697 SmallPtrSet<Value *, 0> Visited;
698 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
702Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
703 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
704 bool UnknownElemTypeI8) {
709 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
720Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
721 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
733 for (User *OpU :
Op->users()) {
735 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
748 if ((DemangledName.
starts_with(
"__spirv_ocl_printf(") ||
757Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
Value *
I,
758 bool UnknownElemTypeI8) {
759 SmallPtrSet<Value *, 0> Visited;
760 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
763void SPIRVEmitIntrinsics::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
Type *RefTy,
764 bool UnknownElemTypeI8) {
766 if (!UnknownElemTypeI8)
775bool SPIRVEmitIntrinsics::walkLogicalAccessChainDynamic(
776 Type *CurType,
Value *Operand, uint64_t Multiplier,
777 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
778 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
784 if (
ST->getNumElements() == 0)
786 CurType =
ST->getElementType(0);
787 OnLiteralIndexing(CurType, 0);
795 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
796 return AT ==
nullptr;
799bool SPIRVEmitIntrinsics::walkLogicalAccessChainConstant(
801 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing) {
806 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
810 CurType = AT->getElementType();
811 OnLiteralIndexing(CurType, Index);
813 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
816 const auto &STL =
DL.getStructLayout(ST);
817 unsigned Element = STL->getElementContainingOffset(
Offset);
818 Offset -= STL->getElementOffset(Element);
819 CurType =
ST->getElementType(Element);
820 OnLiteralIndexing(CurType, Element);
822 Type *EltTy = VT->getElementType();
823 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
824 assert(EltSizeBits % 8 == 0 &&
825 "Element type size in bits must be a multiple of 8.");
826 uint32_t EltTypeSize = EltSizeBits / 8;
831 OnLiteralIndexing(CurType, Index);
841bool SPIRVEmitIntrinsics::walkLogicalAccessChain(
842 GetElementPtrInst &
GEP,
843 const std::function<
void(
Type *, uint64_t)> &OnLiteralIndexing,
844 const std::function<
void(
Type *,
Value *, uint64_t)> &OnDynamicIndexing) {
847 std::optional<uint64_t> MultiplierOpt =
848 getByteAddressingMultiplier(
GEP.getSourceElementType());
849 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
850 uint64_t Multiplier = *MultiplierOpt;
853 Value *Src = getPointerRoot(
GEP.getPointerOperand());
854 Type *CurType = deduceElementType(Src,
true);
858 return walkLogicalAccessChainConstant(
859 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
861 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
862 OnLiteralIndexing, OnDynamicIndexing);
866SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP) {
869 B.SetInsertPoint(&
GEP);
871 std::vector<Value *> Indices;
872 Indices.push_back(ConstantInt::get(
873 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
874 walkLogicalAccessChain(
876 [&Indices, &
B](
Type *EltType, uint64_t Index) {
878 ConstantInt::get(
B.getInt64Ty(), Index,
false));
881 uint64_t Multiplier) {
883 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
885 if (Multiplier == EltTypeSize) {
887 }
else if (EltTypeSize % Multiplier == 0) {
890 EltTypeSize / Multiplier,
894 ConstantInt::get(
Offset->getType(), Multiplier,
897 Index =
B.CreateUDiv(Index,
898 ConstantInt::get(
Offset->getType(), EltTypeSize,
902 Indices.push_back(Index);
906 SmallVector<Value *, 4>
Args;
907 Args.push_back(
B.getInt1(
GEP.isInBounds()));
908 Args.push_back(
GEP.getOperand(0));
911 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
912 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
916Type *SPIRVEmitIntrinsics::getGEPTypeLogical(GetElementPtrInst *
GEP) {
918 Type *CurType =
GEP->getResultElementType();
920 bool Interrupted = walkLogicalAccessChain(
921 *
GEP, [&CurType](
Type *EltType, uint64_t Index) { CurType = EltType; },
922 [&CurType](
Type *EltType,
Value *
Index, uint64_t) { CurType = EltType; });
924 return Interrupted ?
GEP->getResultElementType() : CurType;
927Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *
Ref) {
928 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
930 return getGEPTypeLogical(
Ref);
937 Ty =
Ref->getSourceElementType();
941 Ty =
Ref->getResultElementType();
946Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
947 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
948 bool IgnoreKnownType) {
954 if (!IgnoreKnownType)
966 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
968 Ty = getGEPType(
Ref);
970 Ty = SGEP->getResultElementType();
975 KnownTy =
Op->getType();
977 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
980 Ty = SPIRV::getOriginalFunctionType(*Fn);
983 Ty = deduceElementTypeByValueDeep(
985 Ref->getNumOperands() > 0 ?
Ref->getOperand(0) :
nullptr, Visited,
989 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
991 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
993 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
995 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
997 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1002 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1006 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1008 Type *BestTy =
nullptr;
1010 DenseMap<Type *, unsigned> PhiTys;
1011 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1012 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1019 if (It.first->second > MaxN) {
1020 MaxN = It.first->second;
1028 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1029 Ty = deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1034 static StringMap<unsigned> ResTypeByArg = {
1038 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1039 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1040 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1041 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1042 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1043 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1047 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1048 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1050 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1051 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1052 for (User *U :
II->users()) {
1057 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1059 Ty = HandleType->getTypeParameter(0);
1060 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1074 }
else if (
II &&
II->getIntrinsicID() ==
1075 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1079 std::string DemangledName =
1081 if (DemangledName.length() > 0)
1082 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1083 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1084 if (AsArgIt != ResTypeByArg.
end())
1085 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1086 Visited, UnknownElemTypeI8);
1093 if (Ty && !IgnoreKnownType) {
1104Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
1105 bool UnknownElemTypeI8) {
1106 SmallPtrSet<Value *, 0> Visited;
1107 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1111SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
Type *OrigTy,
1112 SmallPtrSetImpl<Value *> &Visited,
1113 bool UnknownElemTypeI8) {
1122 if (!Visited.
insert(U).second)
1127 bool Change =
false;
1128 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1130 assert(
Op &&
"Operands should not be null.");
1131 Type *OpTy =
Op->getType();
1134 if (
Type *NestedTy =
1135 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1142 Change |= Ty != OpTy;
1150 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1151 Type *OpTy = ArrTy->getElementType();
1154 if (
Type *NestedTy =
1155 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1162 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1168 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1169 Type *OpTy = VecTy->getElementType();
1172 if (
Type *NestedTy =
1173 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1180 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1190Type *SPIRVEmitIntrinsics::deduceElementType(
Value *
I,
bool UnknownElemTypeI8) {
1191 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1193 if (!UnknownElemTypeI8)
1196 return IntegerType::getInt8Ty(
I->getContext());
1200 Value *PointerOperand) {
1206 return I->getType();
1214bool SPIRVEmitIntrinsics::deduceOperandElementTypeCalledFunction(
1216 Type *&KnownElemTy,
bool &Incomplete) {
1220 std::string DemangledName =
1222 if (DemangledName.length() > 0 &&
1224 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1225 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1226 DemangledName,
ST.getPreferredInstructionSet());
1227 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1228 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1234 KnownElemTy = ElemTy;
1235 Ops.push_back(std::make_pair(
Op, i));
1237 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1244 case SPIRV::OpAtomicFAddEXT:
1245 case SPIRV::OpAtomicFMinEXT:
1246 case SPIRV::OpAtomicFMaxEXT:
1247 case SPIRV::OpAtomicLoad:
1248 case SPIRV::OpAtomicCompareExchangeWeak:
1249 case SPIRV::OpAtomicCompareExchange:
1250 case SPIRV::OpAtomicExchange:
1251 case SPIRV::OpAtomicIAdd:
1252 case SPIRV::OpAtomicISub:
1253 case SPIRV::OpAtomicOr:
1254 case SPIRV::OpAtomicXor:
1255 case SPIRV::OpAtomicAnd:
1256 case SPIRV::OpAtomicUMin:
1257 case SPIRV::OpAtomicUMax:
1258 case SPIRV::OpAtomicSMin:
1259 case SPIRV::OpAtomicSMax: {
1264 Incomplete = isTodoType(
Op);
1265 Ops.push_back(std::make_pair(
Op, 0));
1267 case SPIRV::OpAtomicStore: {
1276 Incomplete = isTodoType(
Op);
1277 Ops.push_back(std::make_pair(
Op, 0));
1286void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
1288 Type *&KnownElemTy,
bool IsPostprocessing) {
1292 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1293 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1294 bool IsNewFTy =
false, IsIncomplete =
false;
1297 Type *ArgTy = Arg->getType();
1302 if (isTodoType(Arg))
1303 IsIncomplete =
true;
1305 IsIncomplete =
true;
1308 ArgTy = FTy->getFunctionParamType(ParmIdx);
1312 Type *RetTy = FTy->getReturnType();
1319 IsIncomplete =
true;
1321 IsIncomplete =
true;
1324 if (!IsPostprocessing && IsIncomplete)
1327 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1330bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1331 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1332 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1344 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1345 for (User *U :
F->users()) {
1353 propagateElemType(CI, PrevElemTy, VisitedSubst);
1363 for (Instruction *IncompleteRetI : *IncompleteRets)
1364 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1366 }
else if (IncompleteRets) {
1377void SPIRVEmitIntrinsics::deduceOperandElementType(
1378 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1379 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1381 Type *KnownElemTy =
nullptr;
1382 bool Incomplete =
false;
1388 Incomplete = isTodoType(
I);
1389 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1392 Ops.push_back(std::make_pair(
Op, i));
1398 Incomplete = isTodoType(
I);
1399 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1406 Incomplete = isTodoType(
I);
1407 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1411 KnownElemTy =
Ref->getSourceElementType();
1412 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1417 KnownElemTy =
Ref->getBaseType();
1418 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1421 KnownElemTy =
I->getType();
1428 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1437 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1441 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1446 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1454 Incomplete = isTodoType(
Ref->getPointerOperand());
1455 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1463 Incomplete = isTodoType(
Ref->getPointerOperand());
1464 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1470 Incomplete = isTodoType(
I);
1471 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1474 Ops.push_back(std::make_pair(
Op, i));
1482 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1483 IsPostprocessing, KnownElemTy,
Op,
1486 Incomplete = isTodoType(CurrF);
1487 Ops.push_back(std::make_pair(
Op, 0));
1493 bool Incomplete0 = isTodoType(Op0);
1494 bool Incomplete1 = isTodoType(Op1);
1496 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1498 : GR->findDeducedElementType(Op0);
1500 KnownElemTy = ElemTy0;
1501 Incomplete = Incomplete0;
1502 Ops.push_back(std::make_pair(Op1, 1));
1503 }
else if (ElemTy1) {
1504 KnownElemTy = ElemTy1;
1505 Incomplete = Incomplete1;
1506 Ops.push_back(std::make_pair(Op0, 0));
1510 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1511 else if (HaveFunPtrs)
1512 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1517 if (!KnownElemTy ||
Ops.size() == 0)
1522 for (
auto &OpIt :
Ops) {
1526 Type *AskTy =
nullptr;
1527 CallInst *AskCI =
nullptr;
1528 if (IsPostprocessing && AskOps) {
1534 if (Ty == KnownElemTy)
1537 Type *OpTy =
Op->getType();
1543 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1550 else if (!IsPostprocessing)
1554 if (AssignCI ==
nullptr) {
1563 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1564 std::make_pair(
I,
Op)};
1565 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1569 CallInst *PtrCastI =
1570 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1571 if (OpIt.second == std::numeric_limits<unsigned>::max())
1574 I->setOperand(OpIt.second, PtrCastI);
1580void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
1585 if (isAssignTypeInstr(U)) {
1586 B.SetInsertPoint(U);
1587 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1588 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1589 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1591 U->eraseFromParent();
1594 U->replaceUsesOfWith(Old, New);
1602 Type *NewArgTy =
New->getType();
1604 if (NewArgTy != ExpectedArgTy) {
1607 M, Intrinsic::spv_abort, {NewArgTy});
1617 "aggregate PHI/select/freeze should have been mutated to value-id "
1619 U->replaceUsesOfWith(Old, New);
1624 New->copyMetadata(*Old);
1630 bool HasPoisonExt) {
1637 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1638 "lowered as undef\n");
1640 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1641 Type *Ty = UV->getType();
1647 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1648 :
B.CreateIntrinsicWithoutFolding(IID, {});
1649 AggrConsts[
Call] = UV;
1650 AggrConstTypes[
Call] = Ty;
1655 return B.CreateIntrinsic(IID, {Ty}, {});
1662void SPIRVEmitIntrinsics::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1667 SmallVector<Instruction *, 16> Insts;
1671 for (Instruction *
I : Insts) {
1672 bool BPrepared =
false;
1674 for (
unsigned Idx = 0; Idx <
I->getNumOperands(); ++Idx) {
1678 bool IsScalar = !
Op->getType()->isAggregateType();
1681 if (IsScalar && !AsPoison)
1685 if (IsScalar && Phi)
1686 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1687 else if (!BPrepared) {
1691 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1692 I->setOperand(Idx, Repl);
1701void SPIRVEmitIntrinsics::simplifyNullAddrSpaceCasts() {
1705 ASC->replaceAllUsesWith(
1707 ASC->eraseFromParent();
1715 if (!V->getType()->isAggregateType())
1724 I.getType()->isAggregateType();
1730void SPIRVEmitIntrinsics::insertCompositeAggregateArms(Instruction *
I,
1733 for (Use &U :
I->operands()) {
1740 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1745 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1747 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1753void SPIRVEmitIntrinsics::preprocessCompositeConstants(
IRBuilder<> &
B) {
1757 std::queue<Instruction *> Worklist;
1761 while (!Worklist.empty()) {
1762 auto *
I = Worklist.front();
1765 bool KeepInst =
false;
1766 for (
const auto &
Op :
I->operands()) {
1768 Type *ResTy =
nullptr;
1771 ResTy = COp->getType();
1783 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1786 auto PrepareInsert = [&]() {
1789 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1790 :
B.SetInsertPoint(
I);
1795 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1796 Args.push_back(COp->getElementAsConstant(i));
1802 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1811 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1817 auto *CI =
B.CreateIntrinsicWithoutFolding(
1818 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1822 AggrConsts[CI] = AggrConst;
1823 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1835 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1840 unsigned RoundingModeDeco,
1847 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1856 MDNode *SaturatedConversionNode =
1858 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1878 MDString *ConstraintString =
1887 B.SetInsertPoint(&
Call);
1888 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1893void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1896 if (!
RM.has_value())
1898 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1899 switch (
RM.value()) {
1903 case RoundingMode::NearestTiesToEven:
1904 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1906 case RoundingMode::TowardNegative:
1907 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1909 case RoundingMode::TowardPositive:
1910 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1912 case RoundingMode::TowardZero:
1913 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1915 case RoundingMode::Dynamic:
1916 case RoundingMode::NearestTiesToAway:
1920 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1926Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &
I) {
1930 B.SetInsertPoint(&
I);
1931 SmallVector<Value *, 4>
Args;
1933 Args.push_back(
I.getCondition());
1936 for (
auto &Case :
I.cases()) {
1937 Args.push_back(Case.getCaseValue());
1938 BBCases.
push_back(Case.getCaseSuccessor());
1941 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
1942 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
1946 I.eraseFromParent();
1949 B.SetInsertPoint(ParentBB);
1950 IndirectBrInst *BrI =
B.CreateIndirectBr(
1953 for (BasicBlock *BBCase : BBCases)
1962Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &
I) {
1968 B.SetInsertPoint(&
I);
1970 SmallVector<Value *, 4>
Args;
1971 Args.push_back(
B.getInt1(
true));
1972 Args.push_back(
I.getOperand(0));
1973 Args.push_back(
B.getInt32(0));
1974 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
1975 Args.push_back(SGEP->getIndexOperand(J));
1978 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
1979 replaceAllUsesWithAndErase(
B, &
I, NewI);
1983Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &
I) {
1985 B.SetInsertPoint(&
I);
1990 unsigned N = RetVTy->getNumElements();
1991 Value *PtrOp =
I.getPointerOperand();
1993 Type *ResultPtrTy = RetVTy->getElementType();
1996 Value *InBounds =
B.getInt1(
I.isInBounds());
1997 Type *LanePointeeTy = getGEPType(&
I);
1998 Type *SrcElemTy =
I.getSourceElementType();
2007 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2008 Value *LaneIdx =
B.getInt32(Lane);
2009 Value *ScalarPtr = PtrOp;
2013 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2017 SmallVector<Value *, 4>
Args;
2018 Args.push_back(InBounds);
2019 Args.push_back(ScalarPtr);
2020 for (
Value *Idx :
I.indices()) {
2022 Args.push_back(
B.CreateExtractElement(Idx, LaneIdx));
2024 Args.push_back(Idx);
2026 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2028 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2032 replaceAllUsesWithAndErase(
B, &
I, NewI);
2050 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2051 return buildLogicalAccessChainFromGEP(
I);
2056 Value *PtrOp =
I.getPointerOperand();
2057 Type *SrcElemTy =
I.getSourceElementType();
2058 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2061 if (ArrTy->getElementType() == SrcElemTy) {
2063 Type *FirstIdxType =
I.getOperand(1)->getType();
2064 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2065 for (
Value *Idx :
I.indices())
2069 SmallVector<Value *, 4>
Args;
2070 Args.push_back(
B.getInt1(
I.isInBounds()));
2071 Args.push_back(
I.getPointerOperand());
2074 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2076 replaceAllUsesWithAndErase(
B, &
I, NewI);
2083 SmallVector<Value *, 4>
Args;
2084 Args.push_back(
B.getInt1(
I.isInBounds()));
2087 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2088 replaceAllUsesWithAndErase(
B, &
I, NewI);
2092Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &
I) {
2094 B.SetInsertPoint(&
I);
2103 I.eraseFromParent();
2110 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2111 replaceAllUsesWithAndErase(
B, &
I, NewI);
2115void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
2117 Type *VTy =
V->getType();
2122 if (ElemTy != AssignedType)
2135 if (CurrentType == AssignedType)
2142 " for value " +
V->getName(),
2150void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
2151 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2156 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2157 if (PointerElemTy == ExpectedElementType ||
2163 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2165 bool FirstPtrCastOrAssignPtrType =
true;
2171 for (
auto User :
Pointer->users()) {
2174 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2175 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2176 II->getOperand(0) != Pointer)
2181 FirstPtrCastOrAssignPtrType =
false;
2182 if (
II->getOperand(1) != VMD ||
2189 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2194 if (
II->getParent() !=
I->getParent())
2197 I->setOperand(OperandToReplace,
II);
2212 if (FirstPtrCastOrAssignPtrType) {
2217 }
else if (isTodoType(Pointer)) {
2218 eraseTodoType(Pointer);
2226 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2227 std::make_pair(
I, Pointer)};
2229 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2241 auto *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {
Types},
Args);
2247void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2252 replacePointerOperandWithPtrCast(
2253 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2259 Type *OpTy =
Op->getType();
2262 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2265 if (OpTy ==
Op->getType())
2266 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2267 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2272 Type *OpTy = LI->getType();
2277 Type *NewOpTy = OpTy;
2278 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2279 if (OpTy == NewOpTy)
2280 insertTodoType(Pointer);
2283 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2288 Type *OpTy =
nullptr;
2300 OpTy = GEPI->getSourceElementType();
2302 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2304 insertTodoType(Pointer);
2316 std::string DemangledName =
2320 bool HaveTypes =
false;
2338 for (User *U : CalledArg->
users()) {
2340 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2346 HaveTypes |= ElemTy !=
nullptr;
2351 if (DemangledName.empty() && !HaveTypes)
2369 Type *ExpectedType =
2371 if (!ExpectedType && !DemangledName.empty())
2372 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2373 DemangledName,
OpIdx,
I->getContext());
2374 if (!ExpectedType || ExpectedType->
isVoidTy())
2382 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType,
OpIdx,
B);
2386Instruction *SPIRVEmitIntrinsics::visitInsertElementInst(InsertElementInst &
I) {
2393 I.getOperand(1)->getType(),
2394 I.getOperand(2)->getType()};
2396 B.SetInsertPoint(&
I);
2398 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2400 replaceAllUsesWithAndErase(
B, &
I, NewI);
2405SPIRVEmitIntrinsics::visitExtractElementInst(ExtractElementInst &
I) {
2412 B.SetInsertPoint(&
I);
2414 I.getIndexOperand()->getType()};
2415 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2416 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2418 replaceAllUsesWithAndErase(
B, &
I, NewI);
2422Instruction *SPIRVEmitIntrinsics::visitInsertValueInst(InsertValueInst &
I) {
2424 B.SetInsertPoint(&
I);
2427 Value *AggregateOp =
I.getAggregateOperand();
2431 Args.push_back(AggregateOp);
2432 Args.push_back(
I.getInsertedValueOperand());
2433 for (
auto &
Op :
I.indices())
2434 Args.push_back(
B.getInt32(
Op));
2436 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2437 replaceMemInstrUses(&
I, NewI,
B);
2441Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &
I) {
2443 B.SetInsertPoint(&
I);
2444 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2453 for (
auto &
Op :
I.indices())
2454 Args.push_back(
B.getInt32(
Op));
2455 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2456 {
I.getType()}, {
Args});
2457 replaceAllUsesWithAndErase(
B, &
I, NewI);
2461 for (
const Use &U : NewI->
uses()) {
2467 if (ArgNo < FT->getNumParams() &&
2468 !FT->getParamType(ArgNo)->isAggregateType()) {
2477Instruction *SPIRVEmitIntrinsics::visitLoadInst(LoadInst &
I) {
2478 if (!
I.getType()->isAggregateType())
2481 B.SetInsertPoint(&
I);
2482 TrackConstants =
false;
2487 unsigned IntrinsicId;
2488 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2489 if (!
I.isAtomic()) {
2490 IntrinsicId = Intrinsic::spv_load;
2491 Args.push_back(
B.getInt32(
I.getAlign().value()));
2493 IntrinsicId = Intrinsic::spv_atomic_load;
2494 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2496 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2497 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2499 replaceMemInstrUses(&
I, NewI,
B);
2503Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &
I) {
2507 B.SetInsertPoint(&
I);
2508 TrackConstants =
false;
2512 auto *PtrOp =
I.getPointerOperand();
2514 if (
I.getValueOperand()->getType()->isAggregateType()) {
2522 "Unexpected argument of aggregate type, should be spv_extractv!");
2526 unsigned IntrinsicId;
2527 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2529 if (!
I.isAtomic()) {
2530 IntrinsicId = Intrinsic::spv_store;
2531 Args.push_back(
B.getInt32(
I.getAlign().value()));
2533 IntrinsicId = Intrinsic::spv_atomic_store;
2534 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2537 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2539 I.eraseFromParent();
2543Instruction *SPIRVEmitIntrinsics::visitAllocaInst(AllocaInst &
I) {
2544 Value *ArraySize =
nullptr;
2545 if (
I.isArrayAllocation()) {
2548 SPIRV::Extension::SPV_INTEL_variable_length_array))
2550 "array allocation: this instruction requires the following "
2551 "SPIR-V extension: SPV_INTEL_variable_length_array",
2553 ArraySize =
I.getArraySize();
2556 B.SetInsertPoint(&
I);
2557 TrackConstants =
false;
2558 Type *PtrTy =
I.getType();
2561 ?
B.CreateIntrinsicWithoutFolding(
2562 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2563 {ArraySize,
B.getInt32(
I.getAlign().value())})
2564 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2565 {
B.getInt32(
I.getAlign().value())});
2566 replaceAllUsesWithAndErase(
B, &
I, NewI);
2570Instruction *SPIRVEmitIntrinsics::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2571 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2573 B.SetInsertPoint(&
I);
2575 Args.push_back(
B.getInt32(
2576 static_cast<uint32_t
>(
getMemScope(
I.getContext(),
I.getSyncScopeID()))));
2579 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2580 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2581 uint32_t ScSem =
static_cast<uint32_t
>(
2583 Args.push_back(
B.getInt32(
2585 Args.push_back(
B.getInt32(
2588 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2589 replaceMemInstrUses(&
I, NewI,
B);
2598 case Intrinsic::spv_abort:
2600 case Intrinsic::trap:
2601 case Intrinsic::ubsantrap:
2603 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2623 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2624 "abort-like call must be the last non-debug instruction before its "
2625 "block's terminator");
2629Instruction *SPIRVEmitIntrinsics::visitUnreachableInst(UnreachableInst &
I) {
2630 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2634 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2641 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2655 while (!Stack.empty()) {
2656 const Value *V = Stack.pop_back_val();
2657 if (!Visited.
insert(V).second)
2665 Stack.append(
C->user_begin(),
C->user_end());
2681 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2682 if (UserFunctions.contains(
F))
2687 if (!UserFunctions.empty())
2692 const Module &M = *
F->getParent();
2693 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2694 return F == &FirstDefinition;
2697Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(
Type *AggrTy,
2699 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2700 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2702 AggrConstTypes[Leaf] = ElemTy;
2705 SmallVector<Value *, 4> Elems;
2707 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2710 DenseMap<Type *, Instruction *> LeafByType;
2711 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2713 auto &
Entry = LeafByType[ElemTy];
2715 Entry = MakeLeaf(ElemTy);
2719 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2720 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2722 AggrConstTypes[Composite] = AggrTy;
2731void SPIRVEmitIntrinsics::reconstructAggregateReturns(Function &Func,
2736 for (BasicBlock &BB : Func) {
2740 Value *RetVal = RI->getReturnValue();
2747 B.SetInsertPoint(RI);
2749 for (uint64_t
I = 0;
I < NumElts; ++
I) {
2750 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2751 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2753 RI->setOperand(0, Rebuilt);
2757void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
2767 deduceElementTypeHelper(&GV,
false);
2772 Value *InitOp = Init;
2779 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2780 {
B.getInt32Ty()}, {});
2785 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2790 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2791 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2797 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
2803bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *
I,
2805 bool UnknownElemTypeI8) {
2811 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
2818void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *
I,
2821 static StringMap<unsigned> ResTypeWellKnown = {
2822 {
"async_work_group_copy", WellKnownTypes::Event},
2823 {
"async_work_group_strided_copy", WellKnownTypes::Event},
2824 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
2828 bool IsKnown =
false;
2833 std::string DemangledName =
2836 if (DemangledName.length() > 0)
2838 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
2839 auto ResIt = ResTypeWellKnown.
find(DemangledName);
2840 if (ResIt != ResTypeWellKnown.
end()) {
2843 switch (ResIt->second) {
2844 case WellKnownTypes::Event:
2851 switch (DecorationId) {
2854 case FPDecorationId::SAT:
2857 case FPDecorationId::RTE:
2859 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
2861 case FPDecorationId::RTZ:
2863 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
2865 case FPDecorationId::RTP:
2867 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
2869 case FPDecorationId::RTN:
2871 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
2877 Type *Ty =
I->getType();
2880 Type *TypeToAssign = Ty;
2883 auto It = AggrConstTypes.
find(
II);
2884 if (It == AggrConstTypes.
end())
2886 TypeToAssign = It->second;
2887 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
2888 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
2889 TypeToAssign = It->second;
2891 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
2892 TypeToAssign = It->second;
2896 for (
const auto &
Op :
I->operands()) {
2903 Type *OpTy =
Op->getType();
2905 CallInst *AssignCI =
2910 Type *OpTy =
Op->getType();
2925 CallInst *AssignCI =
2935bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
2936 Instruction *Inst) {
2938 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
2948void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *
I,
2950 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
2952 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
2957 auto processMemAliasingDecoration = [&](
unsigned Kind) {
2958 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
2959 if (shouldTryToAddMemAliasingDecoration(
I)) {
2960 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
2961 ? SPIRV::Decoration::AliasScopeINTEL
2962 : SPIRV::Decoration::NoAliasINTEL;
2964 I, ConstantInt::get(
B.getInt32Ty(), Dec),
2967 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2968 {
I->getType()}, {
Args});
2972 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2973 processMemAliasingDecoration(LLVMContext::MD_noalias);
2976 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
2978 bool AllowFPMaxError =
2980 if (!AllowFPMaxError)
2984 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
2988 if (
I->getModule()->getTargetTriple().getVendor() ==
Triple::AMD &&
2992 auto &Ctx =
B.getContext();
2994 ConstantInt::get(
B.getInt32Ty(), SPIRV::Decoration::UserSemantic));
2997 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
2999 Ctx, {US,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3000 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3003 if (
I->hasMetadata(
"amdgpu.ignore.denormal.mode"))
3005 Ctx, {US,
MDString::get(Ctx,
"amdgpu.ignore.denormal.mode")}));
3007 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3015 &FPFastMathDefaultInfoMap,
3017 auto it = FPFastMathDefaultInfoMap.
find(
F);
3018 if (it != FPFastMathDefaultInfoMap.
end())
3026 SPIRV::FPFastMathMode::None);
3028 SPIRV::FPFastMathMode::None);
3030 SPIRV::FPFastMathMode::None);
3031 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3037 size_t BitWidth = Ty->getScalarSizeInBits();
3041 assert(Index >= 0 && Index < 3 &&
3042 "Expected FPFastMathDefaultInfo for half, float, or double");
3043 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3044 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3045 return FPFastMathDefaultInfoVec[Index];
3048void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(
Module &M) {
3050 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3059 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3061 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3069 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3072 [[maybe_unused]] GlobalVariable *GV =
3073 new GlobalVariable(M,
3074 Type::getInt32Ty(
M.getContext()),
3088 DenseMap<Function *, SPIRV::FPFastMathDefaultInfoVector>
3089 FPFastMathDefaultInfoMap;
3091 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3100 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3102 "Expected 4 operands for FPFastMathDefault");
3108 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3110 SPIRV::FPFastMathDefaultInfo &
Info =
3113 Info.FPFastMathDefault =
true;
3114 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3116 "Expected no operands for ContractionOff");
3120 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3122 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3123 Info.ContractionOff =
true;
3125 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3127 "Expected 1 operand for SignedZeroInfNanPreserve");
3128 unsigned TargetWidth =
3133 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3137 assert(Index >= 0 && Index < 3 &&
3138 "Expected FPFastMathDefaultInfo for half, float, or double");
3139 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3140 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3141 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3145 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3146 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3147 if (FPFastMathDefaultInfoVec.
empty())
3150 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3151 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3154 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3155 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3159 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3161 "and AllowContract");
3163 if (
Info.SignedZeroInfNanPreserve &&
3165 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3166 SPIRV::FPFastMathMode::NSZ))) {
3167 if (
Info.FPFastMathDefault)
3169 "SignedZeroInfNanPreserve but at least one of "
3170 "NotNaN/NotInf/NSZ is enabled.");
3173 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3174 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3175 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3177 "AllowTransform requires AllowReassoc and "
3178 "AllowContract to be set.");
3181 auto it = GlobalVars.
find(Flags);
3182 GlobalVariable *GV =
nullptr;
3183 if (it != GlobalVars.
end()) {
3189 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3192 GV =
new GlobalVariable(M,
3193 Type::getInt32Ty(
M.getContext()),
3198 GlobalVars[
Flags] = GV;
3204void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *
I,
3207 bool IsConstComposite =
3208 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3209 if (IsConstComposite && TrackConstants) {
3211 auto t = AggrConsts.
find(
I);
3215 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3217 NewOp->setArgOperand(0,
I);
3220 for (
const auto &
Op :
I->operands()) {
3224 unsigned OpNo =
Op.getOperandNo();
3225 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3226 (!
II->isBundleOperand(OpNo) &&
3227 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3231 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3232 :
B.SetInsertPoint(
I);
3235 Type *OpTy =
Op->getType();
3243 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3245 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3246 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3248 SmallVector<Value *, 2>
Args = {
3251 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3257 I->setOperand(OpNo, NewOp);
3263Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *
F,
3265 SmallPtrSet<Function *, 0> FVisited;
3266 return deduceFunParamElementType(
F,
OpIdx, FVisited);
3269Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
3270 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3272 if (!FVisited.
insert(
F).second)
3275 SmallPtrSet<Value *, 0> Visited;
3278 for (User *U :
F->users()) {
3290 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3293 for (User *OpU : OpArg->
users()) {
3295 if (!Inst || Inst == CI)
3298 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3305 if (FVisited.
find(OuterF) != FVisited.
end())
3307 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3308 if (OuterF->
getArg(i) == OpArg) {
3309 Lookup.push_back(std::make_pair(OuterF, i));
3316 for (
auto &Pair :
Lookup) {
3317 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3324void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *
F,
3326 B.SetInsertPointPastAllocas(
F);
3333 for (User *U : Arg->
users()) {
3335 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3353 for (User *U :
F->users()) {
3369 for (User *U : Arg->
users()) {
3373 CI->
getParent()->getParent() == CurrF) {
3375 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3386void SPIRVEmitIntrinsics::processParamTypes(Function *
F,
IRBuilder<> &
B) {
3387 B.SetInsertPointPastAllocas(
F);
3393 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F,
OpIdx)) !=
nullptr) {
3395 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3397 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3409 bool IsNewFTy =
false;
3425bool SPIRVEmitIntrinsics::processFunctionPointers(
Module &M) {
3428 if (
F.isIntrinsic())
3430 if (
F.isDeclaration()) {
3431 for (User *U :
F.users()) {
3444 for (User *U :
F.users()) {
3446 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3448 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3449 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3456 if (Worklist.
empty())
3459 LLVMContext &Ctx =
M.getContext();
3464 for (Function *
F : Worklist) {
3466 for (
const auto &Arg :
F->args())
3468 IRB.CreateCall(
F, Args);
3470 IRB.CreateRetVoid();
3476void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3477 DenseMap<Function *, CallInst *> Ptrcasts;
3478 for (
auto It : FDeclPtrTys) {
3480 for (
auto *U :
F->users()) {
3485 for (
auto [Idx, ElemTy] : It.second) {
3493 B.SetInsertPointPastAllocas(Arg->
getParent());
3497 }
else if (isaGEP(Param)) {
3498 replaceUsesOfWithSpvPtrcast(Param,
normalizeType(ElemTy), CI,
3507 .getFirstNonPHIOrDbgOrAlloca());
3528SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP) {
3535 Type *SrcTy =
GEP->getSourceElementType();
3536 SmallVector<Value *, 8> Indices(
GEP->indices());
3538 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3539 Indices.erase(Indices.begin());
3540 SrcTy = ArrTy->getElementType();
3542 GEP->getNoWrapFlags(),
"",
3543 GEP->getIterator());
3548void SPIRVEmitIntrinsics::emitUnstructuredLoopControls(Function &
F,
3555 if (
ST->canUseExtension(
3556 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3557 for (BasicBlock &BB :
F) {
3559 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3563 SmallVector<unsigned, 1>
Ops =
3565 unsigned LC =
Ops[0];
3566 if (LC == SPIRV::LoopControl::None)
3570 B.SetInsertPoint(Term);
3571 SmallVector<Value *, 4> IntrArgs;
3572 for (
unsigned Op :
Ops)
3574 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3581 DominatorTree DT(
F);
3586 for (Loop *L : LI.getLoopsInPreorder()) {
3595 SmallVector<unsigned, 1> LoopControlOps =
3597 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3601 B.SetInsertPoint(Header->getTerminator());
3604 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3605 for (
unsigned Imm : LoopControlOps)
3606 Args.emplace_back(
B.getInt32(Imm));
3607 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3611bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
3612 if (
Func.isDeclaration())
3616 GR =
ST.getSPIRVGlobalRegistry();
3620 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3625 AggrConstTypes.
clear();
3628 processParamTypesByFunHeader(CurrF,
B);
3632 SmallPtrSet<Instruction *, 4> DeadInsts;
3637 if ((!
GEP && !SGEP) || GR->findDeducedElementType(&
I))
3641 GR->addDeducedElementType(SGEP,
3646 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3648 GEP->replaceAllUsesWith(NewGEP);
3652 if (
Type *GepTy = getGEPType(
GEP))
3656 for (
auto *
I : DeadInsts) {
3657 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3658 I->eraseFromParent();
3668 Type *ElTy =
SI->getValueOperand()->getType();
3673 B.SetInsertPoint(&
Func.getEntryBlock(),
Func.getEntryBlock().begin());
3674 for (
auto &GV :
Func.getParent()->globals())
3675 processGlobalValue(GV,
B);
3677 reconstructAggregateReturns(Func,
B);
3678 preprocessUndefsAndPoisons(
B);
3679 simplifyNullAddrSpaceCasts();
3680 preprocessCompositeConstants(
B);
3688 Type *I32Ty =
B.getInt32Ty();
3693 insertCompositeAggregateArms(&
I,
B);
3694 AggrConstTypes[&
I] =
I.getType();
3695 I.mutateType(I32Ty);
3698 preprocessBoolVectorBitcasts(Func);
3702 applyDemangledPtrArgTypes(
B);
3705 for (
auto &
I : Worklist) {
3707 if (isConvergenceIntrinsic(
I))
3710 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3712 insertAssignTypeIntrs(
I,
B);
3713 insertPtrCastOrAssignTypeInstr(
I,
B);
3717 if (Postpone && !GR->findAssignPtrTypeInstr(
I))
3718 insertAssignPtrTypeIntrs(
I,
B,
true);
3721 useRoundingMode(FPI,
B);
3726 SmallPtrSet<Instruction *, 4> IncompleteRets;
3728 deduceOperandElementType(&
I, &IncompleteRets);
3732 for (BasicBlock &BB : Func)
3733 for (PHINode &Phi : BB.
phis())
3735 deduceOperandElementType(&Phi,
nullptr);
3737 for (
auto *
I : Worklist) {
3738 TrackConstants =
true;
3748 if (isConvergenceIntrinsic(
I))
3752 processInstrAfterVisit(
I,
B);
3755 emitUnstructuredLoopControls(Func,
B);
3761bool SPIRVEmitIntrinsics::postprocessTypes(
Module &M) {
3762 if (!GR || TodoTypeSz == 0)
3765 unsigned SzTodo = TodoTypeSz;
3766 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
3771 CallInst *AssignCI = GR->findAssignPtrTypeInstr(
Op);
3772 Type *KnownTy = GR->findDeducedElementType(
Op);
3773 if (!KnownTy || !AssignCI)
3779 SmallPtrSet<Value *, 0> Visited;
3780 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
3781 if (ElemTy != KnownTy) {
3782 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3783 propagateElemType(CI, ElemTy, VisitedSubst);
3790 if (
Op->hasUseList()) {
3791 for (User *U :
Op->users()) {
3798 if (TodoTypeSz == 0)
3803 SmallPtrSet<Instruction *, 4> IncompleteRets;
3805 auto It = ToProcess.
find(&
I);
3806 if (It == ToProcess.
end())
3808 It->second.remove_if([
this](
Value *V) {
return !isTodoType(V); });
3809 if (It->second.size() == 0)
3811 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
3812 if (TodoTypeSz == 0)
3817 return SzTodo > TodoTypeSz;
3821void SPIRVEmitIntrinsics::parseFunDeclarations(
Module &M) {
3823 if (!
F.isDeclaration() ||
F.isIntrinsic())
3827 if (DemangledName.empty())
3831 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
3832 DemangledName,
ST.getPreferredInstructionSet());
3833 if (Opcode != SPIRV::OpGroupAsyncCopy)
3836 SmallVector<unsigned> Idxs;
3845 LLVMContext &Ctx =
F.getContext();
3847 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
3848 if (!TypeStrs.
size())
3851 for (
unsigned Idx : Idxs) {
3852 if (Idx >= TypeStrs.
size())
3855 SPIRV::parseBuiltinCallArgumentType(TypeStrs[Idx].trim(), Ctx))
3858 FDeclPtrTys[&
F].push_back(std::make_pair(Idx, ElemTy));
3863bool SPIRVEmitIntrinsics::processMaskedMemIntrinsic(IntrinsicInst &
I) {
3864 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
3866 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
3867 if (!
ST.canUseExtension(
3868 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3869 I.getContext().emitError(
3870 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
3874 I.eraseFromParent();
3880 Value *Ptrs =
I.getArgOperand(0);
3882 Value *Passthru =
I.getArgOperand(2);
3885 uint32_t Alignment =
I.getParamAlign(0).valueOrOne().value();
3887 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
3892 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
3894 I.eraseFromParent();
3898 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
3899 if (!
ST.canUseExtension(
3900 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
3901 I.getContext().emitError(
3902 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
3905 I.eraseFromParent();
3912 Value *Ptrs =
I.getArgOperand(1);
3917 uint32_t Alignment =
I.getParamAlign(1).valueOrOne().value();
3919 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
3923 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
3924 I.eraseFromParent();
3935void SPIRVEmitIntrinsics::preprocessBoolVectorBitcasts(Function &
F) {
3936 struct BoolVecBitcast {
3938 FixedVectorType *BoolVecTy;
3942 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
3944 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
3952 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
3954 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
3958 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
3960 Value *Src = BC->getOperand(0);
3961 unsigned BoolVecN = BoolVecTy->getNumElements();
3963 Type *IntTy =
B.getIntNTy(BoolVecN);
3969 IntVal = ConstantInt::get(IntTy, 0);
3970 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3971 Value *Elem =
B.CreateExtractElement(Src,
B.getInt32(
I));
3972 Value *Ext =
B.CreateZExt(Elem, IntTy);
3974 Ext =
B.CreateShl(Ext, ConstantInt::get(IntTy,
I));
3975 IntVal =
B.CreateOr(IntVal, Ext);
3981 if (!Src->getType()->isIntegerTy())
3982 IntVal =
B.CreateBitCast(Src, IntTy);
3987 if (!SrcIsBoolVec) {
3990 for (
unsigned I = 0;
I < BoolVecN; ++
I) {
3993 Value *
Cmp =
B.CreateICmpNE(
And, ConstantInt::get(IntTy, 0));
3994 Result =
B.CreateInsertElement(Result, Cmp,
B.getInt32(
I));
4000 if (!BC->getDestTy()->isIntegerTy())
4001 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4004 BC->replaceAllUsesWith(Result);
4005 BC->eraseFromParent();
4009bool SPIRVEmitIntrinsics::convertMaskedMemIntrinsics(
Module &M) {
4013 if (!
F.isIntrinsic())
4016 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4021 Changed |= processMaskedMemIntrinsic(*
II);
4025 F.eraseFromParent();
4031bool SPIRVEmitIntrinsics::runOnModule(
Module &M) {
4034 Changed |= convertMaskedMemIntrinsics(M);
4036 parseFunDeclarations(M);
4037 insertConstantsForFPFastMathDefault(M);
4048 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4050 processParamTypes(&
F,
B);
4054 CanTodoType =
false;
4055 Changed |= postprocessTypes(M);
4058 Changed |= processFunctionPointers(M);
4065 SPIRVEmitIntrinsics
Legacy(TM);
4066 if (
Legacy.runOnModule(M))
4072 return new SPIRVEmitIntrinsics(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
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()
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.
@ C
The default llvm calling convention, compatible with C.
@ 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)
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)