30#include "llvm/IR/IntrinsicsSPIRV.h"
65#define DEBUG_TYPE "spirv-emit-intrinsics"
69 cl::desc(
"Emit OpName for all instructions"),
73#define GET_BuiltinGroup_DECL
74#include "SPIRVGenTables.inc"
79class GlobalVariableUsers {
80 template <
typename T1,
typename T2>
81 using OneToManyMapTy = DenseMap<T1, SmallPtrSet<T2, 4>>;
83 OneToManyMapTy<const GlobalVariable *, const Function *> GlobalIsUsedByFun;
85 void collectGlobalUsers(
86 const GlobalVariable *GV,
87 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
88 &GlobalIsUsedByGlobal) {
90 while (!
Stack.empty()) {
94 GlobalIsUsedByFun[GV].insert(
I->getFunction());
99 GlobalIsUsedByGlobal[GV].insert(UserGV);
104 Stack.append(
C->user_begin(),
C->user_end());
108 bool propagateGlobalToGlobalUsers(
109 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
110 &GlobalIsUsedByGlobal) {
113 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
114 OldUsersGlobals.
assign(UserGlobals.begin(), UserGlobals.end());
115 for (
const GlobalVariable *UserGV : OldUsersGlobals) {
116 auto It = GlobalIsUsedByGlobal.find(UserGV);
117 if (It == GlobalIsUsedByGlobal.end())
125 void propagateGlobalToFunctionReferences(
126 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
127 &GlobalIsUsedByGlobal) {
128 for (
auto &[GV, UserGlobals] : GlobalIsUsedByGlobal) {
129 auto &UserFunctions = GlobalIsUsedByFun[GV];
130 for (
const GlobalVariable *UserGV : UserGlobals) {
131 auto It = GlobalIsUsedByFun.find(UserGV);
132 if (It == GlobalIsUsedByFun.end())
143 OneToManyMapTy<const GlobalVariable *, const GlobalVariable *>
144 GlobalIsUsedByGlobal;
145 GlobalIsUsedByFun.clear();
146 for (GlobalVariable &GV :
M.globals())
147 collectGlobalUsers(&GV, GlobalIsUsedByGlobal);
150 while (propagateGlobalToGlobalUsers(GlobalIsUsedByGlobal))
153 propagateGlobalToFunctionReferences(GlobalIsUsedByGlobal);
156 using FunctionSetType =
typename decltype(GlobalIsUsedByFun)::mapped_type;
157 const FunctionSetType &
158 getTransitiveUserFunctions(
const GlobalVariable &GV)
const {
159 auto It = GlobalIsUsedByFun.find(&GV);
160 if (It != GlobalIsUsedByFun.end())
163 static const FunctionSetType
Empty{};
168static bool isaGEP(
const Value *
V) {
174static std::optional<uint64_t> getByteAddressingMultiplier(
Type *Ty) {
180 return AT->getNumElements();
186class SPIRVEmitIntrinsicsImpl
187 :
public InstVisitor<SPIRVEmitIntrinsicsImpl, Instruction *> {
188 const SPIRVTargetMachine &TM;
189 SPIRVGlobalRegistry *GR =
nullptr;
191 bool TrackConstants =
true;
192 bool HaveFunPtrs =
false;
193 bool CanUseAnyVectorRank =
false;
194 DenseMap<Instruction *, Constant *> AggrConsts;
195 DenseMap<Instruction *, Type *> AggrConstTypes;
196 SmallPtrSet<Instruction *, 0> AggrStores;
197 GlobalVariableUsers GVUsers;
198 SmallPtrSet<Value *, 0> Named;
201 MapVector<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
204 bool CanTodoType =
true;
205 unsigned TodoTypeSz = 0;
206 DenseMap<Value *, bool> TodoType;
207 void insertTodoType(
Value *
Op) {
209 if (CanTodoType && !isaGEP(
Op)) {
210 auto It = TodoType.try_emplace(
Op,
true);
215 void eraseTodoType(
Value *
Op) {
216 auto It = TodoType.find(
Op);
217 if (It != TodoType.end() && It->second) {
225 auto It = TodoType.find(
Op);
226 return It != TodoType.end() && It->second;
230 SmallPtrSet<Instruction *, 0> TypeValidated;
233 SmallVector<Instruction *> RetypedToRevalidate;
234 bool RevalidatingRetyped =
false;
237 enum WellKnownTypes { Event };
240 Type *deduceElementType(
Value *
I,
bool UnknownElemTypeI8);
241 Type *deduceElementTypeHelper(
Value *
I,
bool UnknownElemTypeI8);
242 Type *deduceElementTypeHelper(
Value *
I, SmallPtrSetImpl<Value *> &Visited,
243 bool UnknownElemTypeI8,
244 bool IgnoreKnownType =
false);
245 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
246 bool UnknownElemTypeI8);
247 Type *deduceElementTypeByValueDeep(
Type *ValueTy,
Value *Operand,
248 SmallPtrSetImpl<Value *> &Visited,
249 bool UnknownElemTypeI8,
250 std::optional<unsigned> AddrSpace = {});
252 SmallPtrSetImpl<Value *> &Visited,
253 bool UnknownElemTypeI8);
255 bool UnknownElemTypeI8);
258 Type *deduceNestedTypeHelper(User *U,
bool UnknownElemTypeI8);
259 Type *deduceNestedTypeHelper(User *U,
Type *Ty,
260 SmallPtrSetImpl<Value *> &Visited,
261 bool UnknownElemTypeI8);
265 deduceOperandElementType(Instruction *
I,
266 SmallPtrSetImpl<Instruction *> *IncompleteRets,
267 const SmallPtrSetImpl<Value *> *AskOps =
nullptr,
268 bool IsPostprocessing =
false);
273 void insertCompositeAggregateArms(Instruction *
I,
IRBuilder<> &
B);
274 void simplifyNullAddrSpaceCasts();
276 Type *reconstructType(
Value *
Op,
bool UnknownElemTypeI8,
277 bool IsPostprocessing);
279 void replaceMemInstrUses(Instruction *Old, Instruction *New,
IRBuilder<> &
B);
281 bool insertAssignPtrTypeIntrs(Instruction *
I,
IRBuilder<> &
B,
282 bool UnknownElemTypeI8);
284 void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType,
Value *
V,
286 void replacePointerOperandWithPtrCast(Instruction *
I,
Value *Pointer,
287 Type *ExpectedElementType,
288 unsigned OperandToReplace,
290 void insertPtrCastOrAssignTypeInstr(Instruction *
I,
IRBuilder<> &
B);
291 bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
293 void insertConstantsForFPFastMathDefault(
Module &M);
296 void processGlobalValue(GlobalVariable &GV,
IRBuilder<> &
B);
299 Type *deduceFunParamElementType(
Function *
F,
unsigned OpIdx);
301 SmallPtrSetImpl<Function *> &FVisited);
303 bool deduceOperandElementTypeCalledFunction(
305 Type *&KnownElemTy,
bool &Incomplete);
306 void deduceOperandElementTypeFunctionPointer(
308 Type *&KnownElemTy,
bool IsPostprocessing);
309 bool deduceOperandElementTypeFunctionRet(
310 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
311 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
315 void replaceUsesOfWithSpvPtrcast(
Value *
Op,
Type *ElemTy, Instruction *
I,
316 DenseMap<Function *, CallInst *> Ptrcasts);
318 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
321 DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
322 void propagateElemTypeRec(
Value *
Op,
Type *PtrElemTy,
Type *CastElemTy,
323 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
324 SmallPtrSetImpl<Value *> &Visited,
325 DenseMap<Function *, CallInst *> Ptrcasts);
328 void replaceAllUsesWithAndErase(
IRBuilder<> &
B, Instruction *Src,
329 Instruction *Dest,
bool DeleteOld =
true);
333 GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *
GEP);
336 bool postprocessTypes(
Module &M);
337 bool processFunctionPointers(
Module &M);
338 void parseFunDeclarations(
Module &M);
339 void useRoundingMode(ConstrainedFPIntrinsic *FPI,
IRBuilder<> &
B);
340 bool processMaskedMemIntrinsic(IntrinsicInst &
I);
341 bool convertMaskedMemIntrinsics(
Module &M);
342 bool foldStaticArrayAllocas(
Module &M);
343 void preprocessBoolVectorBitcasts(
Function &
F);
362 bool walkLogicalAccessChain(
363 GetElementPtrInst &
GEP,
364 const std::function<
void(
Type *PointedType,
uint64_t Index)>
367 uint64_t Multiplier)> &OnDynamicIndexing);
369 bool walkLogicalAccessChainDynamic(
371 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
374 bool walkLogicalAccessChainConstant(
376 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing);
382 Type *getGEPType(GetElementPtrInst *
GEP);
389 Type *getGEPTypeLogical(GetElementPtrInst *
GEP);
391 Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &
GEP);
394 SPIRVEmitIntrinsicsImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
397 Instruction *visitGetElementPtrInst(GetElementPtrInst &
I);
400 Instruction *visitInsertElementInst(InsertElementInst &
I);
401 Instruction *visitExtractElementInst(ExtractElementInst &
I);
403 Instruction *visitExtractValueInst(ExtractValueInst &
I);
407 Instruction *visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I);
412 bool runOnModule(
Module &M);
415class SPIRVEmitIntrinsicsLegacy :
public ModulePass {
416 const SPIRVTargetMachine &TM;
420 SPIRVEmitIntrinsicsLegacy(
const SPIRVTargetMachine &TM)
421 : ModulePass(ID), TM(TM) {}
423 StringRef getPassName()
const override {
return "SPIRV emit intrinsics"; }
425 bool runOnModule(
Module &M)
override {
426 return SPIRVEmitIntrinsicsImpl(TM).runOnModule(M);
432 Intrinsic::experimental_convergence_loop,
433 Intrinsic::experimental_convergence_anchor>());
436bool expectIgnoredInIRTranslation(
const Instruction *
I) {
438 Intrinsic::spv_resource_handlefrombinding,
439 Intrinsic::spv_resource_getbasepointer,
440 Intrinsic::spv_resource_getpointer>());
447 return getPointerRoot(
V);
453char SPIRVEmitIntrinsicsLegacy::ID = 0;
456 "SPIRV emit intrinsics",
false,
false)
483 B.SetInsertPoint(
I->getParent()->getFirstNonPHIOrAlloca());
489 B.SetCurrentDebugLocation(
I->getDebugLoc());
490 if (
I->getType()->isVoidTy())
491 B.SetInsertPoint(
I->getNextNode());
493 B.SetInsertPoint(*
I->getInsertionPointAfterDef());
503 if (
I->getType()->isTokenTy())
505 "does not support token type",
510 if (!
I->hasName() ||
I->getType()->isAggregateType() ||
511 expectIgnoredInIRTranslation(
I))
522 if (
F &&
F->getName().starts_with(
"llvm.spv.alloca"))
533 std::vector<Value *> Args = {
536 B.CreateIntrinsic(Intrinsic::spv_assign_name, {
I->getType()}, Args);
539void SPIRVEmitIntrinsicsImpl::replaceAllUsesWith(
Value *Src,
Value *Dest,
543 if (isTodoType(Src)) {
546 insertTodoType(Dest);
550void SPIRVEmitIntrinsicsImpl::replaceAllUsesWithAndErase(
IRBuilder<> &
B,
555 std::string
Name = Src->hasName() ? Src->getName().str() :
"";
556 Src->eraseFromParent();
559 if (Named.
insert(Dest).second)
574 V =
V->stripPointerCasts();
604Type *SPIRVEmitIntrinsicsImpl::reconstructType(
Value *
Op,
605 bool UnknownElemTypeI8,
606 bool IsPostprocessing) {
610 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
624 if (UnknownElemTypeI8) {
625 if (!IsPostprocessing)
641 B.SetInsertPointPastAllocas(OpA->getParent());
644 B.SetInsertPoint(
F->getEntryBlock().getFirstNonPHIOrAlloca());
646 Type *OpTy =
Op->getType();
648 SmallVector<Value *, 2>
Args = {
651 CallInst *PtrCasted =
652 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
657void SPIRVEmitIntrinsicsImpl::replaceUsesOfWithSpvPtrcast(
659 DenseMap<Function *, CallInst *> Ptrcasts) {
661 CallInst *PtrCastedI =
nullptr;
662 auto It = Ptrcasts.
find(
F);
663 if (It == Ptrcasts.
end()) {
664 PtrCastedI = buildSpvPtrcast(
F,
Op, ElemTy);
665 Ptrcasts[
F] = PtrCastedI;
667 PtrCastedI = It->second;
669 I->replaceUsesOfWith(
Op, PtrCastedI);
672void SPIRVEmitIntrinsicsImpl::propagateElemType(
674 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
675 DenseMap<Function *, CallInst *> Ptrcasts;
677 for (
auto *U :
Users) {
680 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
685 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
686 replaceUsesOfWithSpvPtrcast(
Op, ElemTy, UI, Ptrcasts);
690void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
692 DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
693 SmallPtrSet<Value *, 0> Visited;
694 DenseMap<Function *, CallInst *> Ptrcasts;
695 propagateElemTypeRec(
Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
696 std::move(Ptrcasts));
699void SPIRVEmitIntrinsicsImpl::propagateElemTypeRec(
701 DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
702 SmallPtrSetImpl<Value *> &Visited,
703 DenseMap<Function *, CallInst *> Ptrcasts) {
707 for (
auto *U :
Users) {
710 if (!VisitedSubst.insert(std::make_pair(U,
Op)).second)
715 if (isaGEP(UI) || TypeValidated.
find(UI) != TypeValidated.
end())
716 replaceUsesOfWithSpvPtrcast(
Op, CastElemTy, UI, Ptrcasts);
723Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
724 Type *ValueTy,
Value *Operand,
bool UnknownElemTypeI8) {
725 SmallPtrSet<Value *, 0> Visited;
726 return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
730Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByValueDeep(
731 Type *ValueTy,
Value *Operand, SmallPtrSetImpl<Value *> &Visited,
732 bool UnknownElemTypeI8, std::optional<unsigned> AddrSpace) {
737 deduceElementTypeHelper(Operand, Visited, UnknownElemTypeI8))
739 NestedTy, AddrSpace.value_or(PtrTy->getAddressSpace()));
749Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeByUsersDeep(
750 Value *
Op, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8) {
762 for (User *OpU :
Op->users()) {
764 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited, UnknownElemTypeI8))
776 Function *CalledF,
unsigned OpIdx) {
782 if (Name ==
"printf" || Name ==
"get_fence")
790Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
Value *
I,
791 bool UnknownElemTypeI8) {
792 SmallPtrSet<Value *, 0> Visited;
793 return deduceElementTypeHelper(
I, Visited, UnknownElemTypeI8);
796void SPIRVEmitIntrinsicsImpl::maybeAssignPtrType(
Type *&Ty,
Value *
Op,
798 bool UnknownElemTypeI8) {
800 if (!UnknownElemTypeI8)
809bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainDynamic(
811 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
818 if (
ST->getNumElements() == 0)
820 CurType =
ST->getElementType(0);
821 OnLiteralIndexing(CurType, 0);
829 OnDynamicIndexing(AT->getElementType(), Operand, Multiplier);
830 return AT ==
nullptr;
833bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChainConstant(
835 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing) {
840 uint64_t EltTypeSize =
DL.getTypeAllocSize(AT->getElementType());
844 CurType = AT->getElementType();
845 OnLiteralIndexing(CurType, Index);
847 uint32_t StructSize =
DL.getTypeSizeInBits(ST) / 8;
850 const auto &STL =
DL.getStructLayout(ST);
851 unsigned Element = STL->getElementContainingOffset(
Offset);
852 Offset -= STL->getElementOffset(Element);
853 CurType =
ST->getElementType(Element);
854 OnLiteralIndexing(CurType, Element);
856 Type *EltTy = VT->getElementType();
857 TypeSize EltSizeBits =
DL.getTypeSizeInBits(EltTy);
858 assert(EltSizeBits % 8 == 0 &&
859 "Element type size in bits must be a multiple of 8.");
860 uint32_t EltTypeSize = EltSizeBits / 8;
865 OnLiteralIndexing(CurType, Index);
875bool SPIRVEmitIntrinsicsImpl::walkLogicalAccessChain(
876 GetElementPtrInst &
GEP,
877 const std::function<
void(
Type *,
uint64_t)> &OnLiteralIndexing,
881 std::optional<uint64_t> MultiplierOpt =
882 getByteAddressingMultiplier(
GEP.getSourceElementType());
883 assert(MultiplierOpt &&
"We only rewrite byte-addressing GEP");
884 uint64_t Multiplier = *MultiplierOpt;
887 Value *Src = getPointerRoot(
GEP.getPointerOperand());
888 Type *CurType = deduceElementType(Src,
true);
892 return walkLogicalAccessChainConstant(
893 CurType, CI->getZExtValue() * Multiplier, OnLiteralIndexing);
895 return walkLogicalAccessChainDynamic(CurType, Operand, Multiplier,
896 OnLiteralIndexing, OnDynamicIndexing);
899Instruction *SPIRVEmitIntrinsicsImpl::buildLogicalAccessChainFromGEP(
900 GetElementPtrInst &
GEP) {
903 B.SetInsertPoint(&
GEP);
905 std::vector<Value *> Indices;
906 Indices.push_back(ConstantInt::get(
907 IntegerType::getInt32Ty(CurrF->
getContext()), 0,
false));
908 walkLogicalAccessChain(
912 ConstantInt::get(
B.getInt64Ty(), Index,
false));
917 uint32_t EltTypeSize =
DL.getTypeSizeInBits(EltType) / 8;
919 if (Multiplier == EltTypeSize) {
921 }
else if (EltTypeSize % Multiplier == 0) {
924 EltTypeSize / Multiplier,
928 ConstantInt::get(
Offset->getType(), Multiplier,
931 Index =
B.CreateUDiv(Index,
932 ConstantInt::get(
Offset->getType(), EltTypeSize,
936 Indices.push_back(Index);
940 SmallVector<Value *, 4>
Args;
941 Args.push_back(
B.getInt1(
GEP.isInBounds()));
942 Args.push_back(
GEP.getOperand(0));
945 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
946 replaceAllUsesWithAndErase(
B, &
GEP, NewI);
950Type *SPIRVEmitIntrinsicsImpl::getGEPTypeLogical(GetElementPtrInst *
GEP) {
952 Type *CurType =
GEP->getResultElementType();
954 bool Interrupted = walkLogicalAccessChain(
955 *
GEP, [&CurType](
Type *EltType,
uint64_t Index) { CurType = EltType; },
958 return Interrupted ?
GEP->getResultElementType() : CurType;
961Type *SPIRVEmitIntrinsicsImpl::getGEPType(GetElementPtrInst *
Ref) {
962 if (getByteAddressingMultiplier(
Ref->getSourceElementType()) &&
964 return getGEPTypeLogical(
Ref);
971 Ty =
Ref->getSourceElementType();
975 Ty =
Ref->getResultElementType();
980Type *SPIRVEmitIntrinsicsImpl::deduceElementTypeHelper(
981 Value *
I, SmallPtrSetImpl<Value *> &Visited,
bool UnknownElemTypeI8,
982 bool IgnoreKnownType) {
988 if (!IgnoreKnownType)
1000 maybeAssignPtrType(Ty,
I,
Ref->getAllocatedType(), UnknownElemTypeI8);
1002 Ty = getGEPType(
Ref);
1004 Ty = SGEP->getResultElementType();
1009 KnownTy =
Op->getType();
1011 maybeAssignPtrType(Ty,
I, ElemTy, UnknownElemTypeI8);
1014 Ty = SPIRV::getOriginalFunctionType(*Fn);
1021 std::optional<unsigned> ProgramAS;
1026 SPIRV::Extension::SPV_INTEL_function_pointers))
1030 Ty = deduceElementTypeByValueDeep(
Ref->getValueType(),
Op, Visited,
1031 UnknownElemTypeI8, ProgramAS);
1034 Type *RefTy = deduceElementTypeHelper(
Ref->getPointerOperand(), Visited,
1036 maybeAssignPtrType(Ty,
I, RefTy, UnknownElemTypeI8);
1038 maybeAssignPtrType(Ty,
I,
Ref->getDestTy(), UnknownElemTypeI8);
1040 if (
Type *Src =
Ref->getSrcTy(), *Dest =
Ref->getDestTy();
1042 Ty = deduceElementTypeHelper(
Ref->getOperand(0), Visited,
1048 reconstructType(
Ref->getAggregateOperand(),
false,
false),
1053 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1057 Ty = deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8);
1059 Type *BestTy =
nullptr;
1061 DenseMap<Type *, unsigned> PhiTys;
1062 for (
int i =
Ref->getNumIncomingValues() - 1; i >= 0; --i) {
1063 Ty = deduceElementTypeByUsersDeep(
Ref->getIncomingValue(i), Visited,
1070 if (It.first->second > MaxN) {
1071 MaxN = It.first->second;
1079 for (
Value *
Op : {
Ref->getTrueValue(),
Ref->getFalseValue()}) {
1083 ? deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8)
1084 : deduceElementTypeByUsersDeep(
Op, Visited, UnknownElemTypeI8);
1089 static StringMap<unsigned> ResTypeByArg = {
1095 {
"__to_private", 0},
1096 {
"__spirv_GenericCastToPtr_ToGlobal", 0},
1097 {
"__spirv_GenericCastToPtr_ToLocal", 0},
1098 {
"__spirv_GenericCastToPtr_ToPrivate", 0},
1099 {
"__spirv_GenericCastToPtrExplicit_ToGlobal", 0},
1100 {
"__spirv_GenericCastToPtrExplicit_ToLocal", 0},
1101 {
"__spirv_GenericCastToPtrExplicit_ToPrivate", 0}};
1105 if (
II && (
II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
1106 II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
1108 if (HandleType->getTargetExtName() ==
"spirv.Image" ||
1109 HandleType->getTargetExtName() ==
"spirv.SignedImage") {
1110 for (User *U :
II->users()) {
1115 }
else if (HandleType->getTargetExtName() ==
"spirv.VulkanBuffer") {
1117 Ty = HandleType->getTypeParameter(0);
1118 if (
II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1132 }
else if (
II &&
II->getIntrinsicID() ==
1133 Intrinsic::spv_generic_cast_to_ptr_explicit) {
1137 std::string DemangledName =
1139 if (DemangledName.length() > 0)
1140 DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1141 auto AsArgIt = ResTypeByArg.
find(DemangledName);
1142 if (AsArgIt != ResTypeByArg.
end())
1143 Ty = deduceElementTypeHelper(CI->
getArgOperand(AsArgIt->second),
1144 Visited, UnknownElemTypeI8);
1151 if (Ty && !IgnoreKnownType) {
1162Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(User *U,
1163 bool UnknownElemTypeI8) {
1164 SmallPtrSet<Value *, 0> Visited;
1165 return deduceNestedTypeHelper(U,
U->getType(), Visited, UnknownElemTypeI8);
1168Type *SPIRVEmitIntrinsicsImpl::deduceNestedTypeHelper(
1169 User *U,
Type *OrigTy, SmallPtrSetImpl<Value *> &Visited,
1170 bool UnknownElemTypeI8) {
1180 if (!Visited.
insert(U).second)
1185 bool Change =
false;
1186 for (
unsigned i = 0; i <
U->getNumOperands(); ++i) {
1188 assert(
Op &&
"Operands should not be null.");
1189 Type *OpTy =
Op->getType();
1192 if (
Type *NestedTy =
1193 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1200 Change |= Ty != OpTy;
1204 Tys, OrigStructTy->isLiteral() ?
"" : OrigStructTy->getName(),
1205 OrigStructTy->isPacked());
1210 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1211 Type *OpTy = ArrTy->getElementType();
1214 if (
Type *NestedTy =
1215 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1222 Type *NewTy = ArrayType::get(Ty, ArrTy->getNumElements());
1228 if (
Value *
Op =
U->getNumOperands() > 0 ?
U->getOperand(0) :
nullptr) {
1229 Type *OpTy = VecTy->getElementType();
1232 if (
Type *NestedTy =
1233 deduceElementTypeHelper(
Op, Visited, UnknownElemTypeI8))
1240 Type *NewTy = VectorType::get(Ty, VecTy->getElementCount());
1251Type *SPIRVEmitIntrinsicsImpl::deduceElementType(
Value *
I,
1252 bool UnknownElemTypeI8) {
1253 if (
Type *Ty = deduceElementTypeHelper(
I, UnknownElemTypeI8))
1255 if (!UnknownElemTypeI8)
1258 return IntegerType::getInt8Ty(
I->getContext());
1262 Value *PointerOperand) {
1268 return I->getType();
1276bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeCalledFunction(
1278 Type *&KnownElemTy,
bool &Incomplete) {
1282 std::string DemangledName =
1284 if (DemangledName.length() > 0 &&
1286 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*CalledF);
1287 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(
1288 DemangledName,
ST.getPreferredInstructionSet());
1289 if (Opcode == SPIRV::OpGroupAsyncCopy) {
1290 for (
unsigned i = 0, PtrCnt = 0; i < CI->
arg_size() && PtrCnt < 2; ++i) {
1296 KnownElemTy = ElemTy;
1297 Ops.push_back(std::make_pair(
Op, i));
1299 }
else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
1306 case SPIRV::OpAtomicFAddEXT:
1307 case SPIRV::OpAtomicFMinEXT:
1308 case SPIRV::OpAtomicFMaxEXT:
1309 case SPIRV::OpAtomicLoad:
1310 case SPIRV::OpAtomicCompareExchangeWeak:
1311 case SPIRV::OpAtomicCompareExchange:
1312 case SPIRV::OpAtomicExchange:
1313 case SPIRV::OpAtomicIAdd:
1314 case SPIRV::OpAtomicISub:
1315 case SPIRV::OpAtomicOr:
1316 case SPIRV::OpAtomicXor:
1317 case SPIRV::OpAtomicAnd:
1318 case SPIRV::OpAtomicUMin:
1319 case SPIRV::OpAtomicUMax:
1320 case SPIRV::OpAtomicSMin:
1321 case SPIRV::OpAtomicSMax: {
1326 Incomplete = isTodoType(
Op);
1327 Ops.push_back(std::make_pair(
Op, 0));
1329 case SPIRV::OpAtomicStore: {
1338 Incomplete = isTodoType(
Op);
1339 Ops.push_back(std::make_pair(
Op, 0));
1348void SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionPointer(
1350 Type *&KnownElemTy,
bool IsPostprocessing) {
1354 Ops.push_back(std::make_pair(
Op, std::numeric_limits<unsigned>::max()));
1355 FunctionType *FTy = SPIRV::getOriginalFunctionType(*CI);
1356 bool IsNewFTy =
false, IsIncomplete =
false;
1359 Type *ArgTy = Arg->getType();
1364 if (isTodoType(Arg))
1365 IsIncomplete =
true;
1367 IsIncomplete =
true;
1370 ArgTy = FTy->getFunctionParamType(ParmIdx);
1374 Type *RetTy = FTy->getReturnType();
1381 IsIncomplete =
true;
1383 IsIncomplete =
true;
1386 if (!IsPostprocessing && IsIncomplete)
1389 IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
1392bool SPIRVEmitIntrinsicsImpl::deduceOperandElementTypeFunctionRet(
1393 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1394 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing,
1406 DenseSet<std::pair<Value *, Value *>> VisitedSubst{std::make_pair(
I,
Op)};
1407 for (User *U :
F->users()) {
1416 propagateElemType(CI, PrevElemTy, VisitedSubst);
1426 for (Instruction *IncompleteRetI : *IncompleteRets)
1427 deduceOperandElementType(IncompleteRetI,
nullptr, AskOps,
1429 }
else if (IncompleteRets) {
1440void SPIRVEmitIntrinsicsImpl::deduceOperandElementType(
1441 Instruction *
I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
1442 const SmallPtrSetImpl<Value *> *AskOps,
bool IsPostprocessing) {
1444 Type *KnownElemTy =
nullptr;
1445 bool Incomplete =
false;
1451 Incomplete = isTodoType(
I);
1452 for (
unsigned i = 0; i <
Ref->getNumIncomingValues(); i++) {
1455 Ops.push_back(std::make_pair(
Op, i));
1461 Incomplete = isTodoType(
I);
1462 Ops.push_back(std::make_pair(
Ref->getPointerOperand(), 0));
1469 Incomplete = isTodoType(
I);
1470 Ops.push_back(std::make_pair(
Ref->getOperand(0), 0));
1474 KnownElemTy =
Ref->getSourceElementType();
1475 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1480 KnownElemTy =
Ref->getBaseType();
1481 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1484 KnownElemTy =
I->getType();
1491 Value *Root =
Ref->getPointerOperand()->stripPointerCasts();
1500 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1504 reconstructType(
Ref->getValueOperand(),
false, IsPostprocessing)))
1509 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1517 Incomplete = isTodoType(
Ref->getPointerOperand());
1518 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1526 Incomplete = isTodoType(
Ref->getPointerOperand());
1527 Ops.push_back(std::make_pair(
Ref->getPointerOperand(),
1533 Incomplete = isTodoType(
I);
1534 for (
unsigned i = 0; i <
Ref->getNumOperands(); i++) {
1537 Ops.push_back(std::make_pair(
Op, i));
1545 if (deduceOperandElementTypeFunctionRet(
I, IncompleteRets, AskOps,
1546 IsPostprocessing, KnownElemTy,
Op,
1549 Incomplete = isTodoType(CurrF);
1550 Ops.push_back(std::make_pair(
Op, 0));
1556 bool Incomplete0 = isTodoType(Op0);
1557 bool Incomplete1 = isTodoType(Op1);
1559 Type *ElemTy0 = (Incomplete0 && !Incomplete1 && ElemTy1)
1561 : GR->findDeducedElementType(Op0);
1563 KnownElemTy = ElemTy0;
1564 Incomplete = Incomplete0;
1565 Ops.push_back(std::make_pair(Op1, 1));
1566 }
else if (ElemTy1) {
1567 KnownElemTy = ElemTy1;
1568 Incomplete = Incomplete1;
1569 Ops.push_back(std::make_pair(Op0, 0));
1573 deduceOperandElementTypeCalledFunction(CI,
Ops, KnownElemTy, Incomplete);
1574 else if (HaveFunPtrs)
1575 deduceOperandElementTypeFunctionPointer(CI,
Ops, KnownElemTy,
1580 if (!KnownElemTy ||
Ops.size() == 0)
1584 for (
auto &OpIt :
Ops) {
1588 Type *AskTy =
nullptr;
1589 CallInst *AskCI =
nullptr;
1590 if (IsPostprocessing && AskOps) {
1596 if (Ty == KnownElemTy)
1599 Type *OpTy =
Op->getType();
1605 if (
Op->hasUseList() && !WouldClobberPtrWithNonPtr &&
1613 else if (!IsPostprocessing)
1617 if (AssignCI ==
nullptr) {
1626 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1627 std::make_pair(
I,
Op)};
1628 propagateElemTypeRec(
Op, KnownElemTy, PrevElemTy, VisitedSubst);
1639 CallInst *PtrCastI =
1640 buildSpvPtrcast(
I->getParent()->getParent(),
Op, KnownElemTy);
1641 if (OpIt.second == std::numeric_limits<unsigned>::max())
1644 I->setOperand(OpIt.second, PtrCastI);
1651 if (RevalidatingRetyped)
1653 RevalidatingRetyped =
true;
1654 while (!RetypedToRevalidate.
empty())
1655 deduceOperandElementType(RetypedToRevalidate.
pop_back_val(),
nullptr,
1656 nullptr, IsPostprocessing);
1657 RevalidatingRetyped =
false;
1660void SPIRVEmitIntrinsicsImpl::replaceMemInstrUses(Instruction *Old,
1665 if (isAssignTypeInstr(U)) {
1666 B.SetInsertPoint(U);
1667 SmallVector<Value *, 2>
Args = {
New,
U->getOperand(1)};
1668 CallInst *AssignCI =
B.CreateIntrinsicWithoutFolding(
1669 Intrinsic::spv_assign_type, {
New->getType()},
Args);
1671 U->eraseFromParent();
1674 U->replaceUsesOfWith(Old, New);
1682 Type *NewArgTy =
New->getType();
1684 if (NewArgTy != ExpectedArgTy) {
1687 M, Intrinsic::spv_abort, {NewArgTy});
1697 "aggregate PHI/select/freeze should have been mutated to value-id "
1699 U->replaceUsesOfWith(Old, New);
1704 New->copyMetadata(*Old);
1710 bool HasPoisonExt) {
1717 LLVM_DEBUG(
dbgs() <<
"SPV_KHR_poison_freeze is not enabled. Poison is "
1718 "lowered as undef\n");
1720 Intrinsic::ID IID = AsPoison ? Intrinsic::spv_poison : Intrinsic::spv_undef;
1721 Type *Ty = UV->getType();
1727 AsPoison ?
B.CreateIntrinsicWithoutFolding(IID, {
B.getInt32Ty()}, {})
1728 :
B.CreateIntrinsicWithoutFolding(IID, {});
1729 AggrConsts[
Call] = UV;
1730 AggrConstTypes[
Call] = Ty;
1735 return B.CreateIntrinsic(IID, {Ty}, {});
1742void SPIRVEmitIntrinsicsImpl::preprocessUndefsAndPoisons(
IRBuilder<> &
B) {
1747 SmallVector<Instruction *, 16> Insts;
1751 for (Instruction *
I : Insts) {
1752 bool BPrepared =
false;
1754 for (
unsigned Idx = 0;
Idx <
I->getNumOperands(); ++
Idx) {
1758 bool IsScalar = !
Op->getType()->isAggregateType();
1761 if (IsScalar && !AsPoison)
1765 if (IsScalar && Phi)
1766 B.SetInsertPoint(
Phi->getIncomingBlock(Idx)->getTerminator());
1767 else if (!BPrepared) {
1771 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1772 I->setOperand(Idx, Repl);
1781void SPIRVEmitIntrinsicsImpl::simplifyNullAddrSpaceCasts() {
1785 ASC->replaceAllUsesWith(
1787 ASC->eraseFromParent();
1795 if (!
V->getType()->isAggregateType())
1804 I.getType()->isAggregateType();
1810void SPIRVEmitIntrinsicsImpl::insertCompositeAggregateArms(Instruction *
I,
1813 for (Use &U :
I->operands()) {
1820 B.SetInsertPoint(
Phi->getIncomingBlock(U)->getTerminator());
1825 for (
unsigned Idx = 0,
E = AggrTy->getNumElements(); Idx !=
E; ++Idx) {
1827 Composite =
B.CreateInsertValue(Composite,
Field, Idx);
1833void SPIRVEmitIntrinsicsImpl::preprocessCompositeConstants(
IRBuilder<> &
B) {
1837 std::queue<Instruction *> Worklist;
1841 while (!Worklist.empty()) {
1842 auto *
I = Worklist.front();
1845 bool KeepInst =
false;
1846 for (
const auto &
Op :
I->operands()) {
1848 Type *ResTy =
nullptr;
1851 ResTy = COp->getType();
1863 ResTy =
Op->getType()->isVectorTy() ? COp->getType() :
B.getInt32Ty();
1866 auto PrepareInsert = [&]() {
1869 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
1870 :
B.SetInsertPoint(
I);
1875 for (
unsigned i = 0; i < COp->getNumElements(); ++i)
1876 Args.push_back(COp->getElementAsConstant(i));
1882 CE &&
CE->getOpcode() == Instruction::AddrSpaceCast &&
1891 if (
Value *Repl = lowerUndefOrPoison(
Op,
B, HasPoisonExt))
1897 auto *CI =
B.CreateIntrinsicWithoutFolding(
1898 Intrinsic::spv_const_composite, {ResTy}, {
Args});
1902 AggrConsts[CI] = AggrConst;
1903 AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst,
false);
1915 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
1920 unsigned RoundingModeDeco,
1927 ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1936 MDNode *SaturatedConversionNode =
1938 Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1958 MDString *ConstraintString =
1963 for (
unsigned OpIdx = 0; OpIdx <
Call.
arg_size(); OpIdx++)
1967 B.SetInsertPoint(&
Call);
1968 B.CreateIntrinsic(Intrinsic::spv_inline_asm, {
Args});
1973void SPIRVEmitIntrinsicsImpl::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1976 if (!
RM.has_value())
1978 unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1979 switch (
RM.value()) {
1983 case RoundingMode::NearestTiesToEven:
1984 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1986 case RoundingMode::TowardNegative:
1987 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1989 case RoundingMode::TowardPositive:
1990 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1992 case RoundingMode::TowardZero:
1993 RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1995 case RoundingMode::Dynamic:
1996 case RoundingMode::NearestTiesToAway:
2000 if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
2006Instruction *SPIRVEmitIntrinsicsImpl::visitSwitchInst(SwitchInst &
I) {
2010 B.SetInsertPoint(&
I);
2011 SmallVector<Value *, 4>
Args;
2013 Args.push_back(
I.getCondition());
2016 for (
auto &Case :
I.cases()) {
2017 Args.push_back(Case.getCaseValue());
2018 BBCases.
push_back(Case.getCaseSuccessor());
2021 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2022 Intrinsic::spv_switch, {
I.getOperand(0)->getType()}, {
Args});
2026 I.eraseFromParent();
2029 B.SetInsertPoint(ParentBB);
2030 IndirectBrInst *BrI =
B.CreateIndirectBr(
2033 for (BasicBlock *BBCase : BBCases)
2042Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &
I) {
2048 B.SetInsertPoint(&
I);
2050 SmallVector<Value *, 4>
Args;
2051 Args.push_back(
B.getInt1(
true));
2052 Args.push_back(
I.getOperand(0));
2053 Args.push_back(
B.getInt32(0));
2054 for (
unsigned J = 0; J < SGEP->getNumIndices(); ++J)
2055 Args.push_back(SGEP->getIndexOperand(J));
2058 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, Types, Args);
2059 replaceAllUsesWithAndErase(
B, &
I, NewI);
2064SPIRVEmitIntrinsicsImpl::visitGetElementPtrInst(GetElementPtrInst &
I) {
2066 B.SetInsertPoint(&
I);
2071 unsigned N = RetVTy->getNumElements();
2072 Value *PtrOp =
I.getPointerOperand();
2074 Type *ResultPtrTy = RetVTy->getElementType();
2077 Value *InBounds =
B.getInt1(
I.isInBounds());
2078 Type *LanePointeeTy = getGEPType(&
I);
2079 Type *SrcElemTy =
I.getSourceElementType();
2088 for (
unsigned Lane = 0; Lane <
N; ++Lane) {
2089 Value *LaneIdx =
B.getInt32(Lane);
2090 Value *ScalarPtr = PtrOp;
2094 ScalarPtr =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {ExtractTypes},
2098 SmallVector<Value *, 4>
Args;
2099 Args.push_back(InBounds);
2100 Args.push_back(ScalarPtr);
2101 for (
Value *Idx :
I.indices()) {
2109 Args.push_back(visitExtractElementInst(*EI));
2113 Args.push_back(Idx);
2116 Value *ScalarGep =
B.CreateIntrinsic(Intrinsic::spv_gep, GepTypes, Args);
2118 VecResult =
B.CreateInsertElement(VecResult, ScalarGep, LaneIdx);
2122 replaceAllUsesWithAndErase(
B, &
I, NewI);
2140 if (getByteAddressingMultiplier(
I.getSourceElementType())) {
2141 return buildLogicalAccessChainFromGEP(
I);
2146 Value *PtrOp =
I.getPointerOperand();
2147 Type *SrcElemTy =
I.getSourceElementType();
2148 Type *DeducedPointeeTy = deduceElementType(PtrOp,
true);
2151 if (ArrTy->getElementType() == SrcElemTy) {
2153 Type *FirstIdxType =
I.getOperand(1)->getType();
2154 NewIndices.
push_back(ConstantInt::get(FirstIdxType, 0));
2155 for (
Value *Idx :
I.indices())
2159 SmallVector<Value *, 4>
Args;
2160 Args.push_back(
B.getInt1(
I.isInBounds()));
2161 Args.push_back(
I.getPointerOperand());
2164 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep,
2166 replaceAllUsesWithAndErase(
B, &
I, NewI);
2173 SmallVector<Value *, 4>
Args;
2174 Args.push_back(
B.getInt1(
I.isInBounds()));
2177 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_gep, {
Types}, {
Args});
2178 replaceAllUsesWithAndErase(
B, &
I, NewI);
2182Instruction *SPIRVEmitIntrinsicsImpl::visitBitCastInst(BitCastInst &
I) {
2184 B.SetInsertPoint(&
I);
2193 I.eraseFromParent();
2200 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_bitcast, {
Types}, {
Args});
2201 replaceAllUsesWithAndErase(
B, &
I, NewI);
2205void SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeTargetExt(
2212 if (ElemTy != AssignedType)
2225 if (CurrentType == AssignedType)
2232 " for value " +
V->getName(),
2241void SPIRVEmitIntrinsicsImpl::replacePointerOperandWithPtrCast(
2242 Instruction *
I,
Value *Pointer,
Type *ExpectedElementType,
2247 Type *PointerElemTy = deduceElementTypeHelper(Pointer,
false);
2248 if (PointerElemTy == ExpectedElementType ||
2253 Value *ExpectedElementVal =
2255 MetadataAsValue *VMD =
buildMD(ExpectedElementVal);
2257 bool FirstPtrCastOrAssignPtrType =
true;
2263 for (
auto User :
Pointer->users()) {
2266 (
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type &&
2267 II->getIntrinsicID() != Intrinsic::spv_ptrcast) ||
2268 II->getOperand(0) != Pointer)
2273 FirstPtrCastOrAssignPtrType =
false;
2274 if (
II->getOperand(1) != VMD ||
2281 if (
II->getIntrinsicID() != Intrinsic::spv_ptrcast)
2286 if (
II->getParent() !=
I->getParent())
2289 I->setOperand(OperandToReplace,
II);
2304 if (FirstPtrCastOrAssignPtrType) {
2309 }
else if (isTodoType(Pointer)) {
2310 eraseTodoType(Pointer);
2318 DenseSet<std::pair<Value *, Value *>> VisitedSubst{
2319 std::make_pair(
I, Pointer)};
2321 propagateElemType(Pointer, PrevElemTy, VisitedSubst);
2334 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_ptrcast, {
Types},
Args);
2340void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *
I,
2345 replacePointerOperandWithPtrCast(
2346 I,
SI->getValueOperand(), IntegerType::getInt8Ty(CurrF->
getContext()),
2352 Type *OpTy =
Op->getType();
2355 if (
auto It = AggrConstTypes.
find(OpI); It != AggrConstTypes.
end())
2358 if (OpTy ==
Op->getType())
2359 OpTy = deduceElementTypeByValueDeep(OpTy,
Op,
false);
2360 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 1,
B);
2365 Type *OpTy = LI->getType();
2376 Type *NewOpTy = OpTy;
2377 OpTy = deduceElementTypeByValueDeep(OpTy, LI,
false);
2378 if (OpTy == NewOpTy)
2379 insertTodoType(Pointer);
2382 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2387 Type *OpTy =
nullptr;
2399 OpTy = GEPI->getSourceElementType();
2401 replacePointerOperandWithPtrCast(
I, Pointer, OpTy, 0,
B);
2403 insertTodoType(Pointer);
2409 Value *
Op = IVI->getInsertedValueOperand();
2411 replacePointerOperandWithPtrCast(
2425 std::string DemangledName =
2429 bool HaveTypes =
false;
2430 for (
unsigned OpIdx = 0; OpIdx < CalledF->
arg_size(); ++OpIdx) {
2448 for (User *U : CalledArg->
users()) {
2450 if ((ElemTy = deduceElementTypeHelper(Inst,
false)) !=
nullptr)
2456 HaveTypes |= ElemTy !=
nullptr;
2461 if (DemangledName.empty() && !HaveTypes)
2465 TM.
getSubtarget<SPIRVSubtarget>(*CalledF).getPreferredInstructionSet();
2467 bool ParseBuiltinTypes =
2468 !DemangledName.empty() &&
2469 (!CalledF->
isDeclaration() || SPIRV::isBuiltin(DemangledName, Set));
2470 for (
unsigned OpIdx = 0; OpIdx < CI->
arg_size(); OpIdx++) {
2485 Type *ExpectedType =
2486 OpIdx < CalledArgTys.
size() ? CalledArgTys[OpIdx] :
nullptr;
2487 if (!ExpectedType && ParseBuiltinTypes)
2488 ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
2489 DemangledName, OpIdx,
I->getContext());
2490 if (!ExpectedType || ExpectedType->
isVoidTy())
2498 replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx,
B);
2503SPIRVEmitIntrinsicsImpl::visitInsertElementInst(InsertElementInst &
I) {
2506 if (
isVector1(
I.getType()) && !CanUseAnyVectorRank)
2510 I.getOperand(1)->getType(),
2511 I.getOperand(2)->getType()};
2513 B.SetInsertPoint(&
I);
2515 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertelt,
2517 replaceAllUsesWithAndErase(
B, &
I, NewI);
2522SPIRVEmitIntrinsicsImpl::visitExtractElementInst(ExtractElementInst &
I) {
2525 if (
isVector1(
I.getVectorOperandType()) && !CanUseAnyVectorRank)
2529 B.SetInsertPoint(&
I);
2531 I.getIndexOperand()->getType()};
2532 SmallVector<Value *, 2>
Args = {
I.getVectorOperand(),
I.getIndexOperand()};
2533 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractelt,
2535 replaceAllUsesWithAndErase(
B, &
I, NewI);
2539Instruction *SPIRVEmitIntrinsicsImpl::visitInsertValueInst(InsertValueInst &
I) {
2541 B.SetInsertPoint(&
I);
2544 Value *AggregateOp =
I.getAggregateOperand();
2548 Args.push_back(AggregateOp);
2549 Args.push_back(
I.getInsertedValueOperand());
2550 for (
auto &
Op :
I.indices())
2551 Args.push_back(
B.getInt32(
Op));
2553 B.CreateIntrinsicWithoutFolding(Intrinsic::spv_insertv, {
Types}, {
Args});
2554 replaceMemInstrUses(&
I, NewI,
B);
2559SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &
I) {
2561 B.SetInsertPoint(&
I);
2562 if (
I.getAggregateOperand()->getType()->isAggregateType()) {
2571 for (
auto &
Op :
I.indices())
2572 Args.push_back(
B.getInt32(
Op));
2573 Instruction *NewI =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
2574 {
I.getType()}, {
Args});
2580 any_of(
I.users(), [](User *U) { return isa<InsertValueInst>(U); })) {
2581 AggrConstTypes[NewI] =
I.getType();
2583 replaceMemInstrUses(&
I, NewI,
B);
2586 replaceAllUsesWithAndErase(
B, &
I, NewI);
2590 for (
const Use &U : NewI->
uses()) {
2591 User *Usr =
U.getUser();
2593 if (RI->getFunction()->getReturnType() != NewI->
getType()) {
2604 if (ArgNo < FT->getNumParams() &&
2605 !FT->getParamType(ArgNo)->isAggregateType()) {
2614Instruction *SPIRVEmitIntrinsicsImpl::visitLoadInst(LoadInst &
I) {
2615 if (!
I.getType()->isAggregateType())
2618 B.SetInsertPoint(&
I);
2619 TrackConstants =
false;
2624 unsigned IntrinsicId;
2625 SmallVector<Value *, 4>
Args = {
I.getPointerOperand(),
B.getInt16(Flags)};
2626 if (!
I.isAtomic()) {
2627 IntrinsicId = Intrinsic::spv_load;
2628 Args.push_back(
B.getInt32(
I.getAlign().value()));
2630 IntrinsicId = Intrinsic::spv_atomic_load;
2631 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2633 CallInst *NewI =
B.CreateIntrinsicWithoutFolding(
2634 IntrinsicId, {
I.getOperand(0)->getType()},
Args);
2636 replaceMemInstrUses(&
I, NewI,
B);
2640Instruction *SPIRVEmitIntrinsicsImpl::visitStoreInst(StoreInst &
I) {
2644 B.SetInsertPoint(&
I);
2645 TrackConstants =
false;
2649 auto *PtrOp =
I.getPointerOperand();
2651 if (
I.getValueOperand()->getType()->isAggregateType()) {
2659 "Unexpected argument of aggregate type, should be spv_extractv!");
2663 unsigned IntrinsicId;
2664 SmallVector<Value *, 4>
Args = {
I.getValueOperand(), PtrOp,
2666 if (!
I.isAtomic()) {
2667 IntrinsicId = Intrinsic::spv_store;
2668 Args.push_back(
B.getInt32(
I.getAlign().value()));
2670 IntrinsicId = Intrinsic::spv_atomic_store;
2671 Args.push_back(
B.getInt8(
static_cast<uint8_t
>(
I.getOrdering())));
2674 IntrinsicId, {
I.getValueOperand()->getType(), PtrOp->
getType()},
Args);
2676 I.eraseFromParent();
2680Instruction *SPIRVEmitIntrinsicsImpl::visitAllocaInst(AllocaInst &
I) {
2681 Value *ArraySize =
nullptr;
2682 if (
I.isArrayAllocation()) {
2685 SPIRV::Extension::SPV_INTEL_variable_length_array))
2687 "array allocation: this instruction requires the following "
2688 "SPIR-V extension: SPV_INTEL_variable_length_array",
2690 ArraySize =
I.getArraySize();
2693 B.SetInsertPoint(&
I);
2694 TrackConstants =
false;
2695 Type *PtrTy =
I.getType();
2698 ?
B.CreateIntrinsicWithoutFolding(
2699 Intrinsic::spv_alloca_array, {PtrTy, ArraySize->
getType()},
2700 {ArraySize,
B.getInt32(
I.getAlign().value())})
2701 :
B.CreateIntrinsicWithoutFolding(
Intrinsic::spv_alloca, {PtrTy},
2702 {
B.getInt32(
I.getAlign().value())});
2703 replaceAllUsesWithAndErase(
B, &
I, NewI);
2708SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &
I) {
2709 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
2711 B.SetInsertPoint(&
I);
2714 Args.push_back(
B.getInt32(
static_cast<uint32_t
>(
2718 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2719 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2720 uint32_t ScSem =
static_cast<uint32_t
>(
2729 Intrinsic::spv_cmpxchg, {
I.getPointerOperand()->getType()}, {
Args});
2730 replaceMemInstrUses(&
I, NewI,
B);
2734Instruction *SPIRVEmitIntrinsicsImpl::visitAtomicRMWInst(AtomicRMWInst &
I) {
2735 auto Op =
I.getOperation();
2746 B.SetInsertPoint(&
I);
2748 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2749 unsigned AS =
I.getPointerOperand()->getType()->getPointerAddressSpace();
2751 uint32_t
Scope =
static_cast<uint32_t
>(
2752 getMemScope(
M->getTargetTriple(),
I.getContext(),
I.getSyncScopeID()));
2753 uint32_t ScSem =
static_cast<uint32_t
>(
2756 M->getTargetTriple(),
2760 ?
"__translate_spirv_atomic_uinc_wrap"
2761 :
"__translate_spirv_atomic_udec_wrap");
2763 Type *ValTy =
I.getValOperand()->getType();
2764 Type *PtrTy =
I.getPointerOperand()->getType();
2766 raw_svector_ostream OS(FuncName);
2767 OS <<
"_p" << AS <<
"_";
2769 OS <<
"v" << VecTy->getNumElements();
2772 Type *Int32Ty =
B.getInt32Ty();
2773 Type *BoolTy =
B.getInt1Ty();
2775 ValTy, BoolTy, BoolTy};
2776 FunctionType *FT = FunctionType::get(ValTy, ArgTys,
false);
2777 FunctionCallee
FC =
M->getOrInsertFunction(FuncName, FT);
2781 I.getPointerOperand(),
B.getInt32(Scope),
2782 B.getInt32(MemSem),
I.getValOperand(),
2783 B.getInt1(
I.isVolatile()),
B.getInt1(
I.isElementwise())};
2784 CallInst *CI =
B.CreateCall(FC, Args);
2790 replaceAllUsesWithAndErase(
B, &
I, CI);
2799 case Intrinsic::spv_abort:
2801 case Intrinsic::trap:
2802 case Intrinsic::ubsantrap:
2804 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort);
2820 [&ST](
const Instruction &
II) { return isAbortCall(II, ST); }) &&
2821 "abort-like call must be the last non-debug instruction before its "
2822 "block's terminator");
2826Instruction *SPIRVEmitIntrinsicsImpl::visitUnreachableInst(UnreachableInst &
I) {
2827 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
2831 B.CreateIntrinsic(Intrinsic::spv_unreachable, {});
2838 return Name ==
"llvm.compiler.used" || Name ==
"llvm.used";
2852 while (!Stack.empty()) {
2853 const Value *
V = Stack.pop_back_val();
2854 if (!Visited.
insert(
V).second)
2862 Stack.append(
C->user_begin(),
C->user_end());
2878 auto &UserFunctions = GVUsers.getTransitiveUserFunctions(GV);
2879 if (UserFunctions.contains(
F))
2884 if (!UserFunctions.empty())
2889 const Module &M = *
F->getParent();
2890 const Function &FirstDefinition = *M.getFunctionDefs().
begin();
2891 return F == &FirstDefinition;
2894Value *SPIRVEmitIntrinsicsImpl::buildSpvUndefComposite(
Type *AggrTy,
2896 auto MakeLeaf = [&](
Type *ElemTy) -> Instruction * {
2897 CallInst *Leaf =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_undef, {});
2899 AggrConstTypes[Leaf] = ElemTy;
2902 SmallVector<Value *, 4> Elems;
2904 Elems.
assign(ArrTy->getNumElements(), MakeLeaf(ArrTy->getElementType()));
2907 DenseMap<Type *, Instruction *> LeafByType;
2908 for (
unsigned I = 0;
I < StructTy->getNumElements(); ++
I) {
2910 auto &
Entry = LeafByType[ElemTy];
2912 Entry = MakeLeaf(ElemTy);
2916 CallInst *Composite =
B.CreateIntrinsicWithoutFolding(
2917 Intrinsic::spv_const_composite, {
B.getInt32Ty()}, Elems);
2919 AggrConstTypes[Composite] = AggrTy;
2928void SPIRVEmitIntrinsicsImpl::reconstructAggregateReturns(
Function &Func,
2933 for (BasicBlock &BB : Func) {
2937 Value *RetVal = RI->getReturnValue();
2944 B.SetInsertPoint(RI);
2947 Value *Elt =
B.CreateExtractValue(RetVal,
I);
2948 Rebuilt =
B.CreateInsertValue(Rebuilt, Elt,
I);
2950 RI->setOperand(0, Rebuilt);
2954void SPIRVEmitIntrinsicsImpl::processGlobalValue(GlobalVariable &GV,
2964 deduceElementTypeHelper(&GV,
false);
2969 Value *InitOp = Init;
2976 CallInst *
Call =
B.CreateIntrinsicWithoutFolding(Intrinsic::spv_poison,
2977 {
B.getInt32Ty()}, {});
2982 InitOp = buildSpvUndefComposite(Init->
getType(),
B);
2987 CallInst *InitInst =
B.CreateIntrinsicWithoutFolding(
2988 Intrinsic::spv_init_global, {GV.
getType(), Ty}, {&GV,
Const});
2994 B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.
getType(), &GV);
3000bool SPIRVEmitIntrinsicsImpl::insertAssignPtrTypeIntrs(Instruction *
I,
3002 bool UnknownElemTypeI8) {
3008 if (
Type *ElemTy = deduceElementType(
I, UnknownElemTypeI8)) {
3015void SPIRVEmitIntrinsicsImpl::insertAssignTypeIntrs(Instruction *
I,
3018 static StringMap<unsigned> ResTypeWellKnown = {
3019 {
"async_work_group_copy", WellKnownTypes::Event},
3020 {
"async_work_group_strided_copy", WellKnownTypes::Event},
3021 {
"__spirv_GroupAsyncCopy", WellKnownTypes::Event}};
3025 bool IsKnown =
false;
3030 std::string DemangledName =
3033 if (DemangledName.length() > 0)
3035 SPIRV::lookupBuiltinNameHelper(DemangledName, &DecorationId);
3036 auto ResIt = ResTypeWellKnown.
find(DemangledName);
3037 if (ResIt != ResTypeWellKnown.
end()) {
3040 switch (ResIt->second) {
3041 case WellKnownTypes::Event:
3044 CanUseAnyVectorRank);
3049 switch (DecorationId) {
3052 case FPDecorationId::SAT:
3055 case FPDecorationId::RTE:
3057 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTE,
B);
3059 case FPDecorationId::RTZ:
3061 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTZ,
B);
3063 case FPDecorationId::RTP:
3065 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTP,
B);
3067 case FPDecorationId::RTN:
3069 CI, SPIRV::FPRoundingMode::FPRoundingMode::RTN,
B);
3075 Type *Ty =
I->getType();
3078 Type *TypeToAssign = Ty;
3081 auto It = AggrConstTypes.
find(
II);
3082 if (It == AggrConstTypes.
end())
3084 TypeToAssign = It->second;
3085 }
else if (
II->getIntrinsicID() == Intrinsic::spv_poison) {
3086 if (
auto It = AggrConstTypes.
find(
II); It != AggrConstTypes.
end())
3087 TypeToAssign = It->second;
3089 }
else if (
auto It = AggrConstTypes.
find(
I); It != AggrConstTypes.
end())
3090 TypeToAssign = It->second;
3094 for (
const auto &
Op :
I->operands()) {
3102 Type *OpTy =
Op->getType();
3104 CallInst *AssignCI =
3109 Type *OpTy =
Op->getType();
3125 Intrinsic::spv_assign_type, {OpTy},
3135bool SPIRVEmitIntrinsicsImpl::shouldTryToAddMemAliasingDecoration(
3136 Instruction *Inst) {
3138 if (!STI->
canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
3148void SPIRVEmitIntrinsicsImpl::insertSpirvDecorations(Instruction *
I,
3150 if (MDNode *MD =
I->getMetadata(
"spirv.Decorations")) {
3152 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3157 auto processMemAliasingDecoration = [&](
unsigned Kind) {
3158 if (MDNode *AliasListMD =
I->getMetadata(Kind)) {
3159 if (shouldTryToAddMemAliasingDecoration(
I)) {
3160 uint32_t Dec =
Kind == LLVMContext::MD_alias_scope
3161 ? SPIRV::Decoration::AliasScopeINTEL
3162 : SPIRV::Decoration::NoAliasINTEL;
3164 I, ConstantInt::get(
B.getInt32Ty(), Dec),
3167 B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
3168 {
I->getType()}, {
Args});
3172 processMemAliasingDecoration(LLVMContext::MD_alias_scope);
3173 processMemAliasingDecoration(LLVMContext::MD_noalias);
3176 if (MDNode *MD =
I->getMetadata(LLVMContext::MD_fpmath)) {
3178 bool AllowFPMaxError =
3180 if (!AllowFPMaxError)
3184 B.CreateIntrinsic(Intrinsic::spv_assign_fpmaxerror_decoration,
3190 LLVMContext &Ctx =
B.getContext();
3192 B.getInt32Ty(), SPIRV::Decoration::AuxDataInstructionMetadata));
3195 if (
I->hasMetadata(
"amdgpu.no.fine.grained.memory"))
3197 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.fine.grained.memory")}));
3198 if (
I->hasMetadata(
"amdgpu.no.remote.memory"))
3200 Ctx, {AuxMD,
MDString::get(Ctx,
"amdgpu.no.remote.memory")}));
3201 if (
I->hasMetadata(LLVMContext::MD_atomic_ignore_denormal_mode))
3203 Ctx, {AuxMD,
MDString::get(Ctx,
"atomic.ignore.denormal.mode")}));
3206 B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {
I->getType()},
3215 &FPFastMathDefaultInfoMap,
3217 auto it = FPFastMathDefaultInfoMap.
find(
F);
3218 if (it != FPFastMathDefaultInfoMap.
end())
3226 SPIRV::FPFastMathMode::None);
3228 SPIRV::FPFastMathMode::None);
3230 SPIRV::FPFastMathMode::None);
3231 return FPFastMathDefaultInfoMap[
F] = std::move(FPFastMathDefaultInfoVec);
3237 size_t BitWidth = Ty->getScalarSizeInBits();
3241 assert(Index >= 0 && Index < 3 &&
3242 "Expected FPFastMathDefaultInfo for half, float, or double");
3243 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3244 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3245 return FPFastMathDefaultInfoVec[Index];
3248void SPIRVEmitIntrinsicsImpl::insertConstantsForFPFastMathDefault(
Module &M) {
3250 if (!
ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3259 auto Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
3261 if (!
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
3269 ConstantInt::get(Type::getInt32Ty(
M.getContext()), 0);
3272 [[maybe_unused]] GlobalVariable *GV =
3273 new GlobalVariable(M,
3274 Type::getInt32Ty(
M.getContext()),
3288 MapVector<Function *, SPIRV::FPFastMathDefaultInfoVector>
3289 FPFastMathDefaultInfoMap;
3291 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
3300 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3302 "Expected 4 operands for FPFastMathDefault");
3308 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3310 SPIRV::FPFastMathDefaultInfo &
Info =
3313 Info.FPFastMathDefault =
true;
3314 }
else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3316 "Expected no operands for ContractionOff");
3320 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3322 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3323 Info.ContractionOff =
true;
3325 }
else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3327 "Expected 1 operand for SignedZeroInfNanPreserve");
3328 unsigned TargetWidth =
3333 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3337 assert(Index >= 0 && Index < 3 &&
3338 "Expected FPFastMathDefaultInfo for half, float, or double");
3339 assert(FPFastMathDefaultInfoVec.
size() == 3 &&
3340 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3341 FPFastMathDefaultInfoVec[
Index].SignedZeroInfNanPreserve =
true;
3345 DenseMap<unsigned, GlobalVariable *> GlobalVars;
3346 for (
auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
3347 if (FPFastMathDefaultInfoVec.
empty())
3350 for (
const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3351 assert(
Info.Ty &&
"Expected target type for FPFastMathDefaultInfo");
3354 if (Flags == SPIRV::FPFastMathMode::None && !
Info.ContractionOff &&
3355 !
Info.SignedZeroInfNanPreserve && !
Info.FPFastMathDefault)
3359 if (
Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract))
3361 "and AllowContract");
3363 if (
Info.SignedZeroInfNanPreserve &&
3365 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
3366 SPIRV::FPFastMathMode::NSZ))) {
3367 if (
Info.FPFastMathDefault)
3369 "SignedZeroInfNanPreserve but at least one of "
3370 "NotNaN/NotInf/NSZ is enabled.");
3373 if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
3374 !((Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
3375 (Flags & SPIRV::FPFastMathMode::AllowContract))) {
3377 "AllowTransform requires AllowReassoc and "
3378 "AllowContract to be set.");
3381 auto it = GlobalVars.
find(Flags);
3382 GlobalVariable *GV =
nullptr;
3383 if (it != GlobalVars.
end()) {
3389 ConstantInt::get(Type::getInt32Ty(
M.getContext()), Flags);
3392 GV =
new GlobalVariable(M,
3393 Type::getInt32Ty(
M.getContext()),
3398 GlobalVars[
Flags] = GV;
3404void SPIRVEmitIntrinsicsImpl::processInstrAfterVisit(Instruction *
I,
3407 bool IsConstComposite =
3408 II &&
II->getIntrinsicID() == Intrinsic::spv_const_composite;
3409 if (IsConstComposite && TrackConstants) {
3411 auto t = AggrConsts.
find(
I);
3415 {
II->getType(),
II->getType()}, t->second,
I, {},
B);
3417 NewOp->setArgOperand(0,
I);
3420 for (
const auto &
Op :
I->operands()) {
3424 unsigned OpNo =
Op.getOperandNo();
3425 if (
II && ((
II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
3426 (!
II->isBundleOperand(OpNo) &&
3427 II->paramHasAttr(OpNo, Attribute::ImmArg))))
3431 IsPhi ?
B.SetInsertPointPastAllocas(
I->getParent()->getParent())
3432 :
B.SetInsertPoint(
I);
3435 Type *OpTy =
Op->getType();
3443 {OpTy, OpTyVal->
getType()},
Op, OpTyVal, {},
B);
3445 if (!IsConstComposite &&
isPointerTy(OpTy) && OpElemTy !=
nullptr &&
3446 OpElemTy != IntegerType::getInt8Ty(
I->getContext())) {
3448 SmallVector<Value *, 2>
Args = {
3452 CallInst *PtrCasted =
B.CreateIntrinsicWithoutFolding(
3458 I->setOperand(OpNo, NewOp);
3464Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
Function *
F,
3466 SmallPtrSet<Function *, 0> FVisited;
3467 return deduceFunParamElementType(
F, OpIdx, FVisited);
3470Type *SPIRVEmitIntrinsicsImpl::deduceFunParamElementType(
3471 Function *
F,
unsigned OpIdx, SmallPtrSetImpl<Function *> &FVisited) {
3473 if (!FVisited.
insert(
F).second)
3476 SmallPtrSet<Value *, 0> Visited;
3479 for (User *U :
F->users()) {
3481 if (!CI || OpIdx >= CI->
arg_size())
3491 if (
Type *Ty = deduceElementTypeHelper(OpArg, Visited,
false))
3494 for (User *OpU : OpArg->
users()) {
3496 if (!Inst || Inst == CI)
3499 if (
Type *Ty = deduceElementTypeHelper(Inst, Visited,
false))
3506 if (FVisited.
find(OuterF) != FVisited.
end())
3508 for (
unsigned i = 0; i < OuterF->
arg_size(); ++i) {
3509 if (OuterF->
getArg(i) == OpArg) {
3510 Lookup.push_back(std::make_pair(OuterF, i));
3517 for (
auto &Pair :
Lookup) {
3518 if (
Type *Ty = deduceFunParamElementType(Pair.first, Pair.second, FVisited))
3525void SPIRVEmitIntrinsicsImpl::processParamTypesByFunHeader(
Function *
F,
3527 B.SetInsertPointPastAllocas(
F);
3528 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3534 for (User *U : Arg->
users()) {
3536 if (
GEP &&
GEP->getPointerOperand() == Arg) {
3554 for (User *U :
F->users()) {
3556 if (!CI || OpIdx >= CI->
arg_size())
3570 for (User *U : Arg->
users()) {
3574 CI->
getParent()->getParent() == CurrF) {
3576 deduceOperandElementTypeFunctionPointer(CI,
Ops, ElemTy,
false);
3588 B.SetInsertPointPastAllocas(
F);
3589 for (
unsigned OpIdx = 0; OpIdx <
F->arg_size(); ++OpIdx) {
3594 if (!ElemTy && (ElemTy = deduceFunParamElementType(
F, OpIdx)) !=
nullptr) {
3596 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
3600 propagateElemType(Arg, IntegerType::getInt8Ty(
F->getContext()),
3612 bool IsNewFTy =
false;
3628bool SPIRVEmitIntrinsicsImpl::processFunctionPointers(
Module &M) {
3631 if (
F.isIntrinsic())
3633 if (
F.isDeclaration()) {
3634 for (User *U :
F.users()) {
3637 UF &&
UF->hasPersonalityFn() &&
UF->getPersonalityFn() == &
F)
3651 for (User *U :
F.users()) {
3653 if (!
II ||
II->arg_size() != 3 ||
II->getOperand(0) != &
F)
3655 if (
II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
3656 II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
3664 if (Worklist.
empty())
3667 LLVMContext &Ctx =
M.getContext();
3674 for (
const auto &Arg :
F->args())
3677 IRB.CreateCall(
F, Args);
3679 IRB.CreateRetVoid();
3685void SPIRVEmitIntrinsicsImpl::applyDemangledPtrArgTypes(
IRBuilder<> &
B) {
3686 DenseMap<Function *, CallInst *> Ptrcasts;
3687 for (
auto It : FDeclPtrTys) {
3689 for (
auto *U :
F->users()) {
3694 for (
auto [Idx, ElemTy] : It.second) {
3702 B.SetInsertPointPastAllocas(Arg->
getParent());
3709 replaceUsesOfWithSpvPtrcast(
3710 Param,
normalizeType(ElemTy, CanUseAnyVectorRank), CI, Ptrcasts);
3719 .getFirstNonPHIOrAlloca());
3737 FDeclPtrTys.
clear();
3740GetElementPtrInst *SPIRVEmitIntrinsicsImpl::simplifyZeroLengthArrayGepInst(
3741 GetElementPtrInst *
GEP) {
3748 Type *SrcTy =
GEP->getSourceElementType();
3749 SmallVector<Value *, 8> Indices(
GEP->indices());
3751 if (ArrTy && ArrTy->getNumElements() == 0 &&
match(Indices[0],
m_Zero())) {
3752 Indices.erase(Indices.begin());
3753 SrcTy = ArrTy->getElementType();
3755 GEP->getNoWrapFlags(),
"",
3756 GEP->getIterator());
3761void SPIRVEmitIntrinsicsImpl::emitUnstructuredLoopControls(
Function &
F,
3768 if (
ST->canUseExtension(
3769 SPIRV::Extension::SPV_INTEL_unstructured_loop_controls)) {
3770 for (BasicBlock &BB :
F) {
3772 MDNode *LoopMD =
Term->getMetadata(LLVMContext::MD_loop);
3776 SmallVector<unsigned, 1>
Ops =
3778 unsigned LC =
Ops[0];
3779 if (LC == SPIRV::LoopControl::None)
3783 B.SetInsertPoint(Term);
3784 SmallVector<Value *, 4> IntrArgs;
3785 for (
unsigned Op :
Ops)
3787 B.CreateIntrinsic(Intrinsic::spv_loop_control_intel, IntrArgs);
3799 SmallPtrSet<BasicBlock *, 8> UsedMergeBlocks;
3806 SmallVector<unsigned, 1> LoopControlOps =
3808 if (LoopControlOps[0] == SPIRV::LoopControl::None)
3821 for (BasicBlock *BB : {Latch, Header}) {
3825 if (!
L->contains(Succ) && !UsedMergeBlocks.
contains(Succ))
3828 if (!MergeBlock || !UsedMergeBlocks.
insert(MergeBlock).second)
3831 B.SetInsertPoint(Header->getTerminator());
3834 SmallVector<Value *, 4>
Args = {MergeAddress, ContinueAddress};
3835 for (
unsigned Imm : LoopControlOps)
3836 Args.emplace_back(
B.getInt32(
Imm));
3837 B.CreateIntrinsic(Intrinsic::spv_loop_merge, {
Args});
3841bool SPIRVEmitIntrinsicsImpl::runOnFunction(
Function &Func) {
3842 if (
Func.isDeclaration())
3851 GR =
ST.getSPIRVGlobalRegistry();
3855 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
3857 CanUseAnyVectorRank =
3858 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
3862 AggrConstTypes.
clear();
3865 processParamTypesByFunHeader(CurrF,
B);
3869 SmallPtrSet<Instruction *, 4> DeadInsts;
3872 Type *ElTy =
SI->getValueOperand()->getType();
3887 normalizeType(SGEP->getResultElementType(), CanUseAnyVectorRank));
3891 GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(
GEP);
3893 GEP->replaceAllUsesWith(NewGEP);
3897 if (
Type *GepTy = getGEPType(
GEP))
3901 for (
auto *
I : DeadInsts) {
3902 assert(
I->use_empty() &&
"Dead instruction should not have any uses left");
3903 I->eraseFromParent();
3906 B.SetInsertPoint(
Func.getEntryBlock().begin());
3907 for (
auto &GV :
Func.getParent()->globals())
3908 processGlobalValue(GV,
B);
3910 reconstructAggregateReturns(Func,
B);
3911 preprocessUndefsAndPoisons(
B);
3912 simplifyNullAddrSpaceCasts();
3913 preprocessCompositeConstants(
B);
3921 Type *I32Ty =
B.getInt32Ty();
3926 insertCompositeAggregateArms(&
I,
B);
3927 AggrConstTypes[&
I] =
I.getType();
3928 I.mutateType(I32Ty);
3931 preprocessBoolVectorBitcasts(Func);
3932 SmallVector<Instruction *> Worklist(
3935 applyDemangledPtrArgTypes(
B);
3938 for (
auto &
I : Worklist) {
3940 if (isConvergenceIntrinsic(
I))
3943 bool Postpone = insertAssignPtrTypeIntrs(
I,
B,
false);
3945 insertAssignTypeIntrs(
I,
B);
3946 insertPtrCastOrAssignTypeInstr(
I,
B);
3951 insertAssignPtrTypeIntrs(
I,
B,
true);
3954 useRoundingMode(FPI,
B);
3959 SmallPtrSet<Instruction *, 4> IncompleteRets;
3961 deduceOperandElementType(&
I, &IncompleteRets);
3965 for (BasicBlock &BB : Func)
3966 for (PHINode &Phi : BB.
phis())
3968 deduceOperandElementType(&Phi,
nullptr);
3970 for (
auto *
I : Worklist) {
3971 TrackConstants =
true;
3981 if (isConvergenceIntrinsic(
I))
3985 processInstrAfterVisit(
I,
B);
3988 emitUnstructuredLoopControls(Func,
B);
3994bool SPIRVEmitIntrinsicsImpl::postprocessTypes(
Module &M) {
3995 if (!GR || TodoTypeSz == 0)
3998 unsigned SzTodo = TodoTypeSz;
3999 DenseMap<Value *, SmallPtrSet<Value *, 4>> ToProcess;
4006 if (!KnownTy || !AssignCI)
4012 SmallPtrSet<Value *, 0> Visited;
4013 if (
Type *ElemTy = deduceElementTypeHelper(
Op, Visited,
false,
true)) {
4014 if (ElemTy != KnownTy) {
4015 DenseSet<std::pair<Value *, Value *>> VisitedSubst;
4016 propagateElemType(CI, ElemTy, VisitedSubst);
4023 if (
Op->hasUseList()) {
4024 for (User *U :
Op->users()) {
4031 if (TodoTypeSz == 0)
4036 SmallPtrSet<Instruction *, 4> IncompleteRets;
4038 auto It = ToProcess.
find(&
I);
4039 if (It == ToProcess.
end())
4041 It->second.remove_if([
this](
Value *
V) {
return !isTodoType(
V); });
4042 if (It->second.size() == 0)
4044 deduceOperandElementType(&
I, &IncompleteRets, &It->second,
true);
4045 if (TodoTypeSz == 0)
4050 return SzTodo > TodoTypeSz;
4064 .Cases({
"char",
"signed char",
"unsigned char",
"short",
4065 "unsigned short",
"int",
"unsigned int",
"_Float16",
"float",
4073 unsigned NumElts = 0;
4074 if (
Count.getAsInteger(10, NumElts) || NumElts == 0)
4081 TypeStr.
split(Quals,
' ', -1,
false);
4084 if (Qual !=
"const" && Qual !=
"volatile" && Qual !=
"restrict" &&
4085 !(Qual.consume_front(
"AS") && !Qual.getAsInteger(10, AS)))
4092void SPIRVEmitIntrinsicsImpl::parseFunDeclarations(
Module &M) {
4094 if (!
F.isDeclaration() ||
F.isIntrinsic())
4097 if (DemangledName.empty())
4100 auto Set =
ST.getPreferredInstructionSet();
4101 auto [Grp, Opcode, ExtNo] = SPIRV::mapBuiltinToOpcode(DemangledName, Set);
4103 const bool IsBuiltin = Grp >= 0 || SPIRV::isBuiltin(DemangledName, Set);
4104 if (IsBuiltin && Opcode != SPIRV::OpGroupAsyncCopy)
4106 SmallVector<unsigned> Idxs;
4107 for (Argument &Arg :
F.args())
4112 LLVMContext &Ctx =
F.getContext();
4114 SPIRV::parseBuiltinTypeStr(TypeStrs, DemangledName, Ctx);
4115 if (TypeStrs.
empty())
4118 if (!IsBuiltin && (!
F.getName().starts_with(
"_Z") ||
F.hasStructRetAttr() ||
4119 StringRef(DemangledName).
count(
'(') != 1 ||
4120 StringRef(DemangledName).
count(
')') != 1 ||
4121 StringRef(DemangledName).
contains(
'<') ||
4122 TypeStrs.
size() !=
F.arg_size()))
4124 bool AllowLongVectors =
4125 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
4126 for (
unsigned Idx : Idxs) {
4127 if (Idx >= TypeStrs.
size())
4129 StringRef TypeStr = TypeStrs[
Idx].trim();
4130 Type *ElemTy = IsBuiltin
4131 ? SPIRV::parseBuiltinCallArgumentType(TypeStr, Ctx)
4141 FDeclPtrTys[&
F].emplace_back(Idx, ElemTy);
4143 ST.getSPIRVGlobalRegistry()->addDeducedElementType(
F.getArg(Idx),
4149bool SPIRVEmitIntrinsicsImpl::processMaskedMemIntrinsic(IntrinsicInst &
I) {
4150 const SPIRVSubtarget &
ST = TM.
getSubtarget<SPIRVSubtarget>(*
I.getFunction());
4152 if (
I.getIntrinsicID() == Intrinsic::masked_gather) {
4153 if (!
ST.canUseExtension(
4154 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4155 I.getContext().emitError(
4156 &
I,
"llvm.masked.gather requires SPV_INTEL_masked_gather_scatter "
4160 I.eraseFromParent();
4166 Value *Ptrs =
I.getArgOperand(0);
4168 Value *Passthru =
I.getArgOperand(2);
4171 uint32_t
Alignment =
I.getParamAlign(0).valueOrOne().value();
4173 SmallVector<Value *, 4>
Args = {Ptrs,
B.getInt32(Alignment),
Mask,
4178 auto *NewI =
B.CreateIntrinsic(Intrinsic::spv_masked_gather, Types, Args);
4180 I.eraseFromParent();
4184 if (
I.getIntrinsicID() == Intrinsic::masked_scatter) {
4185 if (!
ST.canUseExtension(
4186 SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
4187 I.getContext().emitError(
4188 &
I,
"llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter "
4191 I.eraseFromParent();
4198 Value *Ptrs =
I.getArgOperand(1);
4203 uint32_t
Alignment =
I.getParamAlign(1).valueOrOne().value();
4205 SmallVector<Value *, 4>
Args = {
Values, Ptrs,
B.getInt32(Alignment),
Mask};
4209 B.CreateIntrinsic(Intrinsic::spv_masked_scatter, Types, Args);
4210 I.eraseFromParent();
4221void SPIRVEmitIntrinsicsImpl::preprocessBoolVectorBitcasts(
Function &
F) {
4222 struct BoolVecBitcast {
4224 FixedVectorType *BoolVecTy;
4228 auto getAsBoolVec = [](
Type *Ty) -> FixedVectorType * {
4230 return (VTy && VTy->getElementType()->
isIntegerTy(1)) ? VTy :
nullptr;
4238 if (
auto *BVTy = getAsBoolVec(BC->getSrcTy()))
4240 else if (
auto *BVTy = getAsBoolVec(BC->getDestTy()))
4244 for (
auto &[BC, BoolVecTy, SrcIsBoolVec] : ToReplace) {
4246 Value *Src = BC->getOperand(0);
4247 unsigned BoolVecN = BoolVecTy->getNumElements();
4250 Type *OtherTy = SrcIsBoolVec ? BC->getDestTy() : Src->getType();
4251 unsigned NumElts = 1;
4253 NumElts = VTy->getNumElements();
4259 if (!SrcIsBoolVec) {
4262 auto GetLane = [&](
unsigned I) {
4265 Elt =
B.CreateExtractElement(IntVal,
B.getInt32(
I / EltBits));
4269 return B.CreateICmpNE(
And, ConstantInt::get(EltTy, 0));
4277 if (!Idx ||
Idx->getValue().uge(BoolVecN))
4279 B.SetInsertPoint(EE);
4280 EE->replaceAllUsesWith(GetLane(
Idx->getZExtValue()));
4281 EE->eraseFromParent();
4283 if (BC->use_empty()) {
4284 BC->eraseFromParent();
4288 B.SetInsertPoint(BC);
4290 for (
unsigned I = 0;
I < BoolVecN; ++
I)
4291 Result =
B.CreateInsertElement(Result, GetLane(
I),
B.getInt32(
I));
4295 for (
unsigned J = 0; J < NumElts; ++J) {
4296 Value *Elt = ConstantInt::get(EltTy, 0);
4297 for (
unsigned Bit = 0;
Bit < EltBits; ++
Bit) {
4299 B.CreateExtractElement(Src,
B.getInt32(J * EltBits + Bit));
4300 Value *Ext =
B.CreateZExt(Lane, EltTy);
4302 Ext =
B.CreateShl(Ext, ConstantInt::get(EltTy, Bit));
4303 Elt =
B.CreateOr(Elt, Ext);
4305 IntVal = NumElts > 1 ?
B.CreateInsertElement(IntVal, Elt,
B.getInt32(J))
4308 Result =
B.CreateBitCast(IntVal, BC->getDestTy());
4311 BC->replaceAllUsesWith(Result);
4312 BC->eraseFromParent();
4316bool SPIRVEmitIntrinsicsImpl::convertMaskedMemIntrinsics(
Module &M) {
4320 if (!
F.isIntrinsic())
4323 if (IID != Intrinsic::masked_gather && IID != Intrinsic::masked_scatter)
4328 Changed |= processMaskedMemIntrinsic(*
II);
4332 F.eraseFromParent();
4338bool SPIRVEmitIntrinsicsImpl::foldStaticArrayAllocas(
Module &M) {
4340 Type *I32Ty = Type::getInt32Ty(
M.getContext());
4342 if (
F.isDeclaration())
4347 for (Instruction &
I :
F.getEntryBlock()) {
4349 if (!AI || !AI->isStaticAlloca() || !AI->isArrayAllocation() ||
4350 AI->getAddressSpace() !=
4355 if (
Count->isZero() || !
Count->getValue().isIntN(32))
4357 AI->setAllocatedType(
4358 ArrayType::get(AI->getAllocatedType(),
Count->getZExtValue()));
4359 AI->setOperand(0, ConstantInt::get(I32Ty, 1));
4366bool SPIRVEmitIntrinsicsImpl::runOnModule(
Module &M) {
4368 bool Changed = foldStaticArrayAllocas(M);
4369 Changed |= convertMaskedMemIntrinsics(M);
4371 parseFunDeclarations(M);
4372 insertConstantsForFPFastMathDefault(M);
4383 if (!
F.isDeclaration() && !
F.isIntrinsic()) {
4385 processParamTypes(&
F,
B);
4389 CanTodoType =
false;
4390 Changed |= postprocessTypes(M);
4393 Changed |= processFunctionPointers(M);
4400 if (SPIRVEmitIntrinsicsImpl(TM).runOnModule(M))
4406 return new SPIRVEmitIntrinsicsLegacy(TM);
const TargetLowering & TLI
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
This file implements a map that provides insertion order iteration.
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 Type * getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I, Value *PointerOperand)
static void reportFatalOnTokenType(const Instruction *I)
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, MapVector< Function *, SPIRV::FPFastMathDefaultInfoVector > &FPFastMathDefaultInfoMap, Function *F)
static void emitAssignName(Instruction *I, IRBuilder<> &B)
static bool isArtificialGlobal(StringRef Name)
static Type * getPointeeTypeByCallInst(StringRef DemangledName, Function *CalledF, unsigned OpIdx)
static void createRoundingModeDecoration(Instruction *I, unsigned RoundingModeDeco, IRBuilder<> &B)
static void createDecorationIntrinsic(Instruction *I, MDNode *Node, IRBuilder<> &B)
static bool hasOnlyArtificialUses(const GlobalVariable &GV)
static bool isAggregateValueIdInstr(const Instruction &I)
static SPIRV::FPFastMathDefaultInfo & getFPFastMathDefaultInfo(SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty)
static bool isAbortCall(const Instruction &I, const SPIRVSubtarget &ST)
static cl::opt< bool > SpirvEmitOpNames("spirv-emit-op-names", cl::desc("Emit OpName for all instructions"), cl::init(false))
static bool tracesToPointerAlloca(Value *V)
static bool isUseListGlobal(StringRef Name)
static bool IsKernelArgInt8(Function *F, StoreInst *SI)
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B)
static bool isFirstIndexZero(const GetElementPtrInst *GEP)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool isSpvAggrPlaceholder(const Value *V)
static Type * getMemberPointeeType(Type *AggrTy, ArrayRef< unsigned > Indices)
static bool precededByAbortIntrinsic(const UnreachableInst &I, const SPIRVSubtarget &ST)
static FunctionType * getFunctionPointerElemType(Function *F, SPIRVGlobalRegistry *GR)
static bool isMultiRegisterAggregate(Value *V)
static void createSaturatedConversionDecoration(Instruction *I, IRBuilder<> &B)
static Type * parseDeclPtrElemType(StringRef TypeStr, LLVMContext &Ctx)
static bool shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers, const GlobalVariable &GV, const Function *F)
static Type * restoreMutatedType(SPIRVGlobalRegistry *GR, Instruction *I, Type *Ty)
static bool requireAssignType(Instruction *I)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the SmallPtrSet class.
This file defines the SmallString class.
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
static SymbolRef::Type getType(const Symbol *Sym)
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
This class represents an incoming formal argument to a Function.
const Function * getParent() const
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
@ UIncWrap
Increment one up to a maximum value.
@ UDecWrap
Decrement one until a minimum value or zero.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
static LLVM_ABI BlockAddress * get(Function *F, BasicBlock *BB)
Return a BlockAddress for the specified function and basic block.
bool isInlineAsm() const
Check if this call is an inline asm statement.
void setCallingConv(CallingConv::ID CC)
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI std::optional< RoundingMode > getRoundingMode() const
uint64_t getNumOperands() const
unsigned getProgramAddressSpace() const
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Type * getParamType(unsigned i) const
Parameter type accessors.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Type * getReturnType() const
Returns the type of the ret val.
Argument * getArg(unsigned i) const
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static LLVM_ABI Type * getTypeAtIndex(Type *Ty, Value *Idx)
Return the type of the element at the given index of an indexable type.
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static unsigned getPointerOperandIndex()
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Module * getParent()
Get the module that this global value is contained inside of...
PointerType * getType() const
Global values are always pointers.
@ InternalLinkage
Rename collisions when linking (static functions).
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI void addDestination(BasicBlock *Dest)
Add a destination.
static unsigned getInsertedValueOperandIndex()
Base class for instruction visitors.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Instruction * user_back()
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
static unsigned getPointerOperandIndex()
SmallVector< LoopT *, 4 > getLoopsInPreorder() const
Return all of the loops in the function in preorder across the loop nests, with siblings in forward p...
void analyze(ParentT F)
Create the loop forest for a function.
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Flags
Flags values. These may be or'd together.
This class implements a map that also provides access to all stored values in a deterministic order.
iterator find(const KeyT &Key)
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg, bool CanUseAnyVectorRank)
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI)
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg)
Type * findDeducedCompositeType(const Value *Val)
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld=true)
void addDeducedElementType(Value *Val, Type *Ty)
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Type * findMutated(const Value *Val)
void addDeducedCompositeType(Value *Val, Type *Ty)
Type * findDeducedElementType(const Value *Val)
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType)
CallInst * findAssignPtrTypeInstr(const Value *Val)
const SPIRVTargetLowering * getTargetLowering() const override
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
const SPIRVSubtarget * getSubtargetImpl() const
iterator find(ConstPtrType Ptr) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
iterator find(StringRef Key)
Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
Check if the string is empty.
constexpr size_t size() const
Get the string size.
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
A switch()-like statement whose cases are string literals.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static unsigned getPointerOperandIndex()
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
MachineMemOperand::Flags getLoadMemOperandFlags(const LoadInst &LI, const DataLayout &DL, AssumptionCache *AC=nullptr, const TargetLibraryInfo *LibInfo=nullptr, CodeGenOptLevel OptLevel=CodeGenOptLevel::Default) const
MachineMemOperand::Flags getStoreMemOperandFlags(const StoreInst &SI, const DataLayout &DL) const
const Triple & getTargetTriple() const
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
VendorType getVendor() const
Get the parsed vendor type of this triple.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getArrayElementType() const
LLVM_ABI StringRef getTargetExtName() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
bool isStructTy() const
True if this is an instance of StructType.
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
This function has undefined behavior.
void setOperand(unsigned i, Value *Val)
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
iterator_range< use_iterator > uses()
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
const ParentTy * getParent() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ SPIR_KERNEL
Used for SPIR kernel functions.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
auto m_Value()
Match an arbitrary value and ignore it.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
std::string lookupBuiltinNameHelper(StringRef DemangledCall, FPDecorationId *DecorationId)
Parses the name part of the demangled builtin call.
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
unsigned getNumElements(Type *Ty)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
ModulePass * createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
RelativeUniformCounterPtr Values
uint32_t getMemSemanticsWithStorageClass(const Triple &TT, uint32_t OrderSem, uint32_t StorageClassSem)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
bool isUntypedPointerVectorTy(const Type *T)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
bool sortBlocks(Function &F)
bool isa_and_nonnull(const Y &Val)
SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx, SyncScope::ID Id)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
bool isNestedPointer(const Type *Ty)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
Type * normalizeType(Type *Ty, bool CanUseAnyVectorRank)
auto reverse(ContainerTy &&C)
Type * getTypedPointerWrapper(Type *ElemTy, unsigned AS)
bool spirvPreserveAuxData(const Triple &TT)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
@ Ref
The access may reference the value stored in memory.
@ And
Bitwise or logical AND of integers.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
bool isLongVectorEXT(const Type *Ty, bool CanUseVector16=true)
Type * parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx)
DWARFExpression::Operation Op
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
constexpr unsigned BitWidth
bool isEquivalentTypes(Type *Ty1, Type *Ty2)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
bool hasInitializer(const GlobalVariable *GV)
bool isPointerTyOrWrapper(const Type *Ty)
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
PoisonValue * getNormalizedPoisonValue(Type *Ty, bool CanUseAnyVectorRank)
bool isUntypedPointerTy(const Type *T)
Type * reconstitutePeeledArrayType(Type *Ty)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)