31#define DEBUG_TYPE "spirv-module-analysis"
35 cl::desc(
"Dump MIR with SPIR-V dependencies info"),
40 cl::desc(
"SPIR-V capabilities to avoid if there are "
41 "other options enabling a feature"),
44 "SPIR-V Shader capability")));
66 if (MdNode && OpIndex < MdNode->getNumOperands()) {
67 const auto &
Op = MdNode->getOperand(
OpIndex);
68 return mdconst::extract<ConstantInt>(
Op)->getZExtValue();
74getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category,
83 bool MinVerOK = SPIRVVersion.
empty() || SPIRVVersion >= ReqMinVer;
85 ReqMaxVer.
empty() || SPIRVVersion.
empty() || SPIRVVersion <= ReqMaxVer;
88 if (ReqCaps.
empty()) {
89 if (ReqExts.
empty()) {
90 if (MinVerOK && MaxVerOK)
91 return {
true, {}, {}, ReqMinVer, ReqMaxVer};
94 }
else if (MinVerOK && MaxVerOK) {
95 if (ReqCaps.
size() == 1) {
96 auto Cap = ReqCaps[0];
98 return {
true, {Cap}, ReqExts, ReqMinVer, ReqMaxVer};
107 for (
auto Cap : ReqCaps)
110 for (
size_t i = 0, Sz = UseCaps.
size(); i < Sz; ++i) {
111 auto Cap = UseCaps[i];
112 if (i == Sz - 1 || !AvoidCaps.
S.
contains(Cap))
113 return {
true, {Cap}, ReqExts, ReqMinVer, ReqMaxVer};
120 if (
llvm::all_of(ReqExts, [&ST](
const SPIRV::Extension::Extension &Ext) {
121 return ST.canUseExtension(Ext);
132void SPIRVModuleAnalysis::setBaseInfo(
const Module &M) {
145 if (
auto MemModel =
M.getNamedMetadata(
"spirv.MemoryModel")) {
146 auto MemMD = MemModel->getOperand(0);
147 MAI.
Addr =
static_cast<SPIRV::AddressingModel::AddressingModel
>(
148 getMetadataUInt(MemMD, 0));
150 static_cast<SPIRV::MemoryModel::MemoryModel
>(getMetadataUInt(MemMD, 1));
153 MAI.
Mem =
ST->isOpenCLEnv() ? SPIRV::MemoryModel::OpenCL
154 : SPIRV::MemoryModel::GLSL450;
155 if (
MAI.
Mem == SPIRV::MemoryModel::OpenCL) {
156 unsigned PtrSize =
ST->getPointerSize();
157 MAI.
Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32
158 : PtrSize == 64 ? SPIRV::AddressingModel::Physical64
159 : SPIRV::AddressingModel::Logical;
162 MAI.
Addr = SPIRV::AddressingModel::Logical;
167 if (
auto VerNode =
M.getNamedMetadata(
"opencl.ocl.version")) {
168 MAI.
SrcLang = SPIRV::SourceLanguage::OpenCL_C;
171 assert(VerNode->getNumOperands() > 0 &&
"Invalid SPIR");
172 auto VersionMD = VerNode->getOperand(0);
173 unsigned MajorNum = getMetadataUInt(VersionMD, 0, 2);
174 unsigned MinorNum = getMetadataUInt(VersionMD, 1);
175 unsigned RevNum = getMetadataUInt(VersionMD, 2);
178 (std::max(1U, MajorNum) * 100 + MinorNum) * 1000 + RevNum;
184 if (
ST->isOpenCLEnv()) {
185 MAI.
SrcLang = SPIRV::SourceLanguage::OpenCL_CPP;
193 if (
auto ExtNode =
M.getNamedMetadata(
"opencl.used.extensions")) {
194 for (
unsigned I = 0, E = ExtNode->getNumOperands();
I != E; ++
I) {
212 if (
ST->isOpenCLEnv()) {
215 SPIRV::InstructionSet::OpenCL_std)] =
224 bool DoInsert =
true) {
227 assert(
MI &&
"There should be an instruction that defines the register");
233void SPIRVModuleAnalysis::collectGlobalEntities(
234 const std::vector<SPIRV::DTSortableEntry *> &DepsGraph,
237 bool UsePreOrder =
false) {
239 for (
const auto *E : DepsGraph) {
243 RecHoistUtil = [MSType, UsePreOrder, &Visited, &Pred,
245 if (Visited.count(E) || !Pred(E))
254 for (
auto *S : E->getDeps())
265 collectDefInstr(Reg, MF, &
MAI, MSType, IsFirst);
272 for (
auto *S : E->getDeps())
283void SPIRVModuleAnalysis::processDefInstrs(
const Module &M) {
284 std::vector<SPIRV::DTSortableEntry *> DepsGraph;
288 collectGlobalEntities(
292 for (
auto F =
M.begin(), E =
M.end();
F != E; ++
F) {
299 if (
MI.getOpcode() == SPIRV::OpExtension) {
301 auto Ext = SPIRV::Extension::Extension(
MI.getOperand(0).getImm());
304 }
else if (
MI.getOpcode() == SPIRV::OpCapability) {
305 auto Cap = SPIRV::Capability::Capability(
MI.getOperand(0).getImm());
313 collectGlobalEntities(
324 if (
MI.getOpcode() == SPIRV::OpDecorate) {
326 auto Dec =
MI.getOperand(1).getImm();
327 if (Dec ==
static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) {
328 auto Lnk =
MI.getOperand(
MI.getNumOperands() - 1).getImm();
329 if (Lnk ==
static_cast<unsigned>(SPIRV::LinkageType::Import)) {
337 }
else if (
MI.getOpcode() == SPIRV::OpFunction) {
350void SPIRVModuleAnalysis::collectFuncPtrs() {
352 if (
MI->getOpcode() == SPIRV::OpConstantFunctionPointerINTEL)
361 "Constant function pointer must refer to function definition");
362 Register FunDefReg = FunDef->getReg();
366 "Function definition must refer to a global register");
381 InstrSignature Signature;
382 for (
unsigned i = 0; i <
MI.getNumOperands(); ++i) {
393 Signature.push_back(h);
403 bool Append =
true) {
406 auto FoundMI = IS.insert(MISign);
418void SPIRVModuleAnalysis::processOtherInstrs(
const Module &M) {
420 for (
auto F =
M.begin(), E =
M.end();
F != E; ++
F) {
421 if ((*F).isDeclaration())
429 const unsigned OpCode =
MI.getOpcode();
430 if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
432 }
else if (OpCode == SPIRV::OpEntryPoint) {
436 collectFuncNames(
MI, &*
F);
441 }
else if (OpCode == SPIRV::OpFunction) {
442 collectFuncNames(
MI, &*
F);
443 }
else if (OpCode == SPIRV::OpTypeForwardPointer) {
453void SPIRVModuleAnalysis::numberRegistersGlobally(
const Module &M) {
454 for (
auto F =
M.begin(), E =
M.end();
F != E; ++
F) {
455 if ((*F).isDeclaration())
470 if (
MI.getOpcode() != SPIRV::OpExtInst)
472 auto Set =
MI.getOperand(2).getImm();
482 SPIRV::OperandCategory::OperandCategory Category,
uint32_t i,
484 addRequirements(getSymbolicOperandRequirements(Category, i, ST, *
this));
487void SPIRV::RequirementHandler::recursiveAddCapabilities(
489 for (
const auto &Cap : ToPrune) {
493 recursiveAddCapabilities(ImplicitDecls);
498 for (
const auto &Cap : ToAdd) {
499 bool IsNewlyInserted = AllCaps.insert(Cap).second;
500 if (!IsNewlyInserted)
504 recursiveAddCapabilities(ImplicitDecls);
505 MinimalCaps.push_back(Cap);
514 if (Req.
Cap.has_value())
515 addCapabilities({Req.
Cap.value()});
517 addExtensions(Req.
Exts);
520 if (!MaxVersion.empty() && Req.
MinVer > MaxVersion) {
522 <<
" and <= " << MaxVersion <<
"\n");
526 if (MinVersion.empty() || Req.
MinVer > MinVersion)
531 if (!MinVersion.empty() && Req.
MaxVer < MinVersion) {
533 <<
" and >= " << MinVersion <<
"\n");
537 if (MaxVersion.empty() || Req.
MaxVer < MaxVersion)
545 bool IsSatisfiable =
true;
546 auto TargetVer = ST.getSPIRVVersion();
548 if (!MaxVersion.empty() && !TargetVer.empty() && MaxVersion < TargetVer) {
550 dbgs() <<
"Target SPIR-V version too high for required features\n"
551 <<
"Required max version: " << MaxVersion <<
" target version "
552 << TargetVer <<
"\n");
553 IsSatisfiable =
false;
556 if (!MinVersion.empty() && !TargetVer.empty() && MinVersion > TargetVer) {
557 LLVM_DEBUG(
dbgs() <<
"Target SPIR-V version too low for required features\n"
558 <<
"Required min version: " << MinVersion
559 <<
" target version " << TargetVer <<
"\n");
560 IsSatisfiable =
false;
563 if (!MinVersion.empty() && !MaxVersion.empty() && MinVersion > MaxVersion) {
566 <<
"Version is too low for some features and too high for others.\n"
567 <<
"Required SPIR-V min version: " << MinVersion
568 <<
" required SPIR-V max version " << MaxVersion <<
"\n");
569 IsSatisfiable =
false;
572 for (
auto Cap : MinimalCaps) {
573 if (AvailableCaps.contains(Cap))
577 OperandCategory::CapabilityOperand, Cap)
579 IsSatisfiable =
false;
582 for (
auto Ext : AllExtensions) {
583 if (ST.canUseExtension(Ext))
587 OperandCategory::ExtensionOperand, Ext)
589 IsSatisfiable =
false;
598 for (
const auto Cap : ToAdd)
599 if (AvailableCaps.insert(Cap).second)
601 SPIRV::OperandCategory::CapabilityOperand, Cap));
605 const Capability::Capability
ToRemove,
606 const Capability::Capability IfPresent) {
607 if (AllCaps.contains(IfPresent))
614 if (ST.isOpenCLEnv()) {
615 initAvailableCapabilitiesForOpenCL(ST);
619 if (ST.isVulkanEnv()) {
620 initAvailableCapabilitiesForVulkan(ST);
627void RequirementHandler::initAvailableCapabilitiesForOpenCL(
630 addAvailableCaps({Capability::Addresses, Capability::Float16Buffer,
631 Capability::Int16, Capability::Int8, Capability::Kernel,
632 Capability::Linkage, Capability::Vector16,
633 Capability::Groups, Capability::GenericPointer,
634 Capability::Shader});
635 if (ST.hasOpenCLFullProfile())
636 addAvailableCaps({Capability::Int64, Capability::Int64Atomics});
637 if (ST.hasOpenCLImageSupport()) {
638 addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler,
639 Capability::Image1D, Capability::SampledBuffer,
640 Capability::ImageBuffer});
642 addAvailableCaps({Capability::ImageReadWrite});
646 addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage});
648 addAvailableCaps({Capability::GroupNonUniform,
649 Capability::GroupNonUniformVote,
650 Capability::GroupNonUniformArithmetic,
651 Capability::GroupNonUniformBallot,
652 Capability::GroupNonUniformClustered,
653 Capability::GroupNonUniformShuffle,
654 Capability::GroupNonUniformShuffleRelative});
656 addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero,
657 Capability::SignedZeroInfNanPreserve,
658 Capability::RoundingModeRTE,
659 Capability::RoundingModeRTZ});
661 addAvailableCaps({Capability::Float16, Capability::Float64});
664 for (
auto Extension :
ST.getAllAvailableExtensions()) {
667 addAvailableCaps(EnabledCapabilities);
673void RequirementHandler::initAvailableCapabilitiesForVulkan(
675 addAvailableCaps({Capability::Shader, Capability::Linkage});
678 addAvailableCaps({Capability::Int16, Capability::Int64, Capability::Float16,
679 Capability::Float64, Capability::GroupNonUniform});
690 int64_t DecOp =
MI.getOperand(DecIndex).getImm();
691 auto Dec =
static_cast<SPIRV::Decoration::Decoration
>(DecOp);
693 SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs));
695 if (Dec == SPIRV::Decoration::BuiltIn) {
696 int64_t BuiltInOp =
MI.getOperand(DecIndex + 1).getImm();
697 auto BuiltIn =
static_cast<SPIRV::BuiltIn::BuiltIn
>(BuiltInOp);
699 SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
700 }
else if (Dec == SPIRV::Decoration::LinkageAttributes) {
701 int64_t LinkageOp =
MI.getOperand(
MI.getNumOperands() - 1).getImm();
702 SPIRV::LinkageType::LinkageType LnkType =
703 static_cast<SPIRV::LinkageType::LinkageType
>(LinkageOp);
704 if (LnkType == SPIRV::LinkageType::LinkOnceODR)
705 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
706 }
else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
707 Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
708 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
709 }
else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
710 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
711 }
else if (Dec == SPIRV::Decoration::InitModeINTEL ||
712 Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
714 SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
722 assert(
MI.getNumOperands() >= 8 &&
"Insufficient operands for OpTypeImage");
725 int64_t ImgFormatOp =
MI.getOperand(7).getImm();
726 auto ImgFormat =
static_cast<SPIRV::ImageFormat::ImageFormat
>(ImgFormatOp);
730 bool IsArrayed =
MI.getOperand(4).getImm() == 1;
731 bool IsMultisampled =
MI.getOperand(5).getImm() == 1;
732 bool NoSampler =
MI.getOperand(6).getImm() == 2;
735 switch (
MI.getOperand(2).getImm()) {
736 case SPIRV::Dim::DIM_1D:
738 : SPIRV::Capability::Sampled1D);
740 case SPIRV::Dim::DIM_2D:
741 if (IsMultisampled && NoSampler)
744 case SPIRV::Dim::DIM_Cube:
748 : SPIRV::Capability::SampledCubeArray);
750 case SPIRV::Dim::DIM_Rect:
752 : SPIRV::Capability::SampledRect);
754 case SPIRV::Dim::DIM_Buffer:
756 : SPIRV::Capability::SampledBuffer);
758 case SPIRV::Dim::DIM_SubpassData:
765 if (
MI.getNumOperands() > 8 &&
766 MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
773#define ATOM_FLT_REQ_EXT_MSG(ExtName) \
774 "The atomic float instruction requires the following SPIR-V " \
775 "extension: SPV_EXT_shader_atomic_float" ExtName
780 "Expect register operand in atomic float instruction");
782 SPIRVType *TypeDef =
MI.getMF()->getRegInfo().getVRegDef(TypeReg);
783 if (TypeDef->
getOpcode() != SPIRV::OpTypeFloat)
785 "floating-point type scalar");
788 unsigned Op =
MI.getOpcode();
789 if (
Op == SPIRV::OpAtomicFAddEXT) {
790 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
792 Reqs.
addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
795 if (!ST.canUseExtension(
796 SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
798 Reqs.
addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
809 "Unexpected floating-point type width in atomic float instruction");
812 if (!ST.canUseExtension(
813 SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
815 Reqs.
addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
818 Reqs.
addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
821 Reqs.
addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
824 Reqs.
addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
828 "Unexpected floating-point type width in atomic float instruction");
836 switch (
MI.getOpcode()) {
837 case SPIRV::OpMemoryModel: {
838 int64_t
Addr =
MI.getOperand(0).getImm();
841 int64_t Mem =
MI.getOperand(1).getImm();
846 case SPIRV::OpEntryPoint: {
847 int64_t Exe =
MI.getOperand(0).getImm();
852 case SPIRV::OpExecutionMode:
853 case SPIRV::OpExecutionModeId: {
854 int64_t Exe =
MI.getOperand(1).getImm();
859 case SPIRV::OpTypeMatrix:
862 case SPIRV::OpTypeInt: {
863 unsigned BitWidth =
MI.getOperand(1).getImm();
872 case SPIRV::OpTypeFloat: {
873 unsigned BitWidth =
MI.getOperand(1).getImm();
880 case SPIRV::OpTypeVector: {
881 unsigned NumComponents =
MI.getOperand(2).getImm();
882 if (NumComponents == 8 || NumComponents == 16)
886 case SPIRV::OpTypePointer: {
887 auto SC =
MI.getOperand(1).getImm();
892 if (!ST.isOpenCLEnv())
897 if (TypeDef->
getOpcode() == SPIRV::OpTypeFloat &&
902 case SPIRV::OpBitReverse:
903 case SPIRV::OpBitFieldInsert:
904 case SPIRV::OpBitFieldSExtract:
905 case SPIRV::OpBitFieldUExtract:
906 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
910 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
913 case SPIRV::OpTypeRuntimeArray:
916 case SPIRV::OpTypeOpaque:
917 case SPIRV::OpTypeEvent:
920 case SPIRV::OpTypePipe:
921 case SPIRV::OpTypeReserveId:
924 case SPIRV::OpTypeDeviceEvent:
925 case SPIRV::OpTypeQueue:
926 case SPIRV::OpBuildNDRange:
929 case SPIRV::OpDecorate:
930 case SPIRV::OpDecorateId:
931 case SPIRV::OpDecorateString:
934 case SPIRV::OpMemberDecorate:
935 case SPIRV::OpMemberDecorateString:
938 case SPIRV::OpInBoundsPtrAccessChain:
941 case SPIRV::OpConstantSampler:
944 case SPIRV::OpTypeImage:
947 case SPIRV::OpTypeSampler:
950 case SPIRV::OpTypeForwardPointer:
954 case SPIRV::OpAtomicFlagTestAndSet:
955 case SPIRV::OpAtomicLoad:
956 case SPIRV::OpAtomicStore:
957 case SPIRV::OpAtomicExchange:
958 case SPIRV::OpAtomicCompareExchange:
959 case SPIRV::OpAtomicIIncrement:
960 case SPIRV::OpAtomicIDecrement:
961 case SPIRV::OpAtomicIAdd:
962 case SPIRV::OpAtomicISub:
963 case SPIRV::OpAtomicUMin:
964 case SPIRV::OpAtomicUMax:
965 case SPIRV::OpAtomicSMin:
966 case SPIRV::OpAtomicSMax:
967 case SPIRV::OpAtomicAnd:
968 case SPIRV::OpAtomicOr:
969 case SPIRV::OpAtomicXor: {
972 if (
MI.getOpcode() == SPIRV::OpAtomicStore) {
974 InstrPtr =
MRI.getVRegDef(
MI.getOperand(3).getReg());
975 assert(InstrPtr &&
"Unexpected type instruction for OpAtomicStore");
980 if (TypeDef->
getOpcode() == SPIRV::OpTypeInt) {
987 case SPIRV::OpGroupNonUniformIAdd:
988 case SPIRV::OpGroupNonUniformFAdd:
989 case SPIRV::OpGroupNonUniformIMul:
990 case SPIRV::OpGroupNonUniformFMul:
991 case SPIRV::OpGroupNonUniformSMin:
992 case SPIRV::OpGroupNonUniformUMin:
993 case SPIRV::OpGroupNonUniformFMin:
994 case SPIRV::OpGroupNonUniformSMax:
995 case SPIRV::OpGroupNonUniformUMax:
996 case SPIRV::OpGroupNonUniformFMax:
997 case SPIRV::OpGroupNonUniformBitwiseAnd:
998 case SPIRV::OpGroupNonUniformBitwiseOr:
999 case SPIRV::OpGroupNonUniformBitwiseXor:
1000 case SPIRV::OpGroupNonUniformLogicalAnd:
1001 case SPIRV::OpGroupNonUniformLogicalOr:
1002 case SPIRV::OpGroupNonUniformLogicalXor: {
1004 int64_t GroupOp =
MI.getOperand(3).getImm();
1006 case SPIRV::GroupOperation::Reduce:
1007 case SPIRV::GroupOperation::InclusiveScan:
1008 case SPIRV::GroupOperation::ExclusiveScan:
1010 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1011 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformBallot);
1013 case SPIRV::GroupOperation::ClusteredReduce:
1014 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformClustered);
1016 case SPIRV::GroupOperation::PartitionedReduceNV:
1017 case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
1018 case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
1019 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
1024 case SPIRV::OpGroupNonUniformShuffle:
1025 case SPIRV::OpGroupNonUniformShuffleXor:
1026 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformShuffle);
1028 case SPIRV::OpGroupNonUniformShuffleUp:
1029 case SPIRV::OpGroupNonUniformShuffleDown:
1030 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
1032 case SPIRV::OpGroupAll:
1033 case SPIRV::OpGroupAny:
1034 case SPIRV::OpGroupBroadcast:
1035 case SPIRV::OpGroupIAdd:
1036 case SPIRV::OpGroupFAdd:
1037 case SPIRV::OpGroupFMin:
1038 case SPIRV::OpGroupUMin:
1039 case SPIRV::OpGroupSMin:
1040 case SPIRV::OpGroupFMax:
1041 case SPIRV::OpGroupUMax:
1042 case SPIRV::OpGroupSMax:
1045 case SPIRV::OpGroupNonUniformElect:
1048 case SPIRV::OpGroupNonUniformAll:
1049 case SPIRV::OpGroupNonUniformAny:
1050 case SPIRV::OpGroupNonUniformAllEqual:
1053 case SPIRV::OpGroupNonUniformBroadcast:
1054 case SPIRV::OpGroupNonUniformBroadcastFirst:
1055 case SPIRV::OpGroupNonUniformBallot:
1056 case SPIRV::OpGroupNonUniformInverseBallot:
1057 case SPIRV::OpGroupNonUniformBallotBitExtract:
1058 case SPIRV::OpGroupNonUniformBallotBitCount:
1059 case SPIRV::OpGroupNonUniformBallotFindLSB:
1060 case SPIRV::OpGroupNonUniformBallotFindMSB:
1061 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformBallot);
1063 case SPIRV::OpSubgroupShuffleINTEL:
1064 case SPIRV::OpSubgroupShuffleDownINTEL:
1065 case SPIRV::OpSubgroupShuffleUpINTEL:
1066 case SPIRV::OpSubgroupShuffleXorINTEL:
1067 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1068 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1069 Reqs.
addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
1072 case SPIRV::OpSubgroupBlockReadINTEL:
1073 case SPIRV::OpSubgroupBlockWriteINTEL:
1074 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1075 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1076 Reqs.
addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
1079 case SPIRV::OpSubgroupImageBlockReadINTEL:
1080 case SPIRV::OpSubgroupImageBlockWriteINTEL:
1081 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1082 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1083 Reqs.
addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
1086 case SPIRV::OpAssumeTrueKHR:
1087 case SPIRV::OpExpectKHR:
1088 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
1089 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
1093 case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
1094 case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
1095 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
1096 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
1097 Reqs.
addCapability(SPIRV::Capability::USMStorageClassesINTEL);
1100 case SPIRV::OpConstantFunctionPointerINTEL:
1101 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1102 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1103 Reqs.
addCapability(SPIRV::Capability::FunctionPointersINTEL);
1106 case SPIRV::OpGroupNonUniformRotateKHR:
1107 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
1109 "following SPIR-V extension: SPV_KHR_subgroup_rotate",
1111 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
1112 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
1115 case SPIRV::OpGroupIMulKHR:
1116 case SPIRV::OpGroupFMulKHR:
1117 case SPIRV::OpGroupBitwiseAndKHR:
1118 case SPIRV::OpGroupBitwiseOrKHR:
1119 case SPIRV::OpGroupBitwiseXorKHR:
1120 case SPIRV::OpGroupLogicalAndKHR:
1121 case SPIRV::OpGroupLogicalOrKHR:
1122 case SPIRV::OpGroupLogicalXorKHR:
1123 if (ST.canUseExtension(
1124 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
1125 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
1126 Reqs.
addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
1129 case SPIRV::OpReadClockKHR:
1130 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
1132 "following SPIR-V extension: SPV_KHR_shader_clock",
1134 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
1137 case SPIRV::OpFunctionPointerCallINTEL:
1138 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1139 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1140 Reqs.
addCapability(SPIRV::Capability::FunctionPointersINTEL);
1143 case SPIRV::OpAtomicFAddEXT:
1144 case SPIRV::OpAtomicFMinEXT:
1145 case SPIRV::OpAtomicFMaxEXT:
1148 case SPIRV::OpConvertBF16ToFINTEL:
1149 case SPIRV::OpConvertFToBF16INTEL:
1150 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
1151 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
1152 Reqs.
addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
1155 case SPIRV::OpVariableLengthArrayINTEL:
1156 case SPIRV::OpSaveMemoryINTEL:
1157 case SPIRV::OpRestoreMemoryINTEL:
1158 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
1159 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
1160 Reqs.
addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
1163 case SPIRV::OpAsmTargetINTEL:
1164 case SPIRV::OpAsmINTEL:
1165 case SPIRV::OpAsmCallINTEL:
1166 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) {
1167 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_inline_assembly);
1171 case SPIRV::OpTypeCooperativeMatrixKHR:
1172 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
1174 "OpTypeCooperativeMatrixKHR type requires the "
1175 "following SPIR-V extension: SPV_KHR_cooperative_matrix",
1177 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
1178 Reqs.
addCapability(SPIRV::Capability::CooperativeMatrixKHR);
1188 SPIRV::Capability::Shader);
1194 for (
auto F = M.begin(), E = M.end();
F != E; ++
F) {
1203 auto Node = M.getNamedMetadata(
"spirv.ExecutionMode");
1206 bool RequireFloatControls =
false,
1207 VerLower14 = !ST.isAtLeastSPIRVVer(
VersionTuple(1, 4));
1208 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
1209 MDNode *MDN = cast<MDNode>(
Node->getOperand(i));
1211 if (
auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
1214 auto EM = Const->getZExtValue();
1216 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
1219 case SPIRV::ExecutionMode::DenormPreserve:
1220 case SPIRV::ExecutionMode::DenormFlushToZero:
1221 case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
1222 case SPIRV::ExecutionMode::RoundingModeRTE:
1223 case SPIRV::ExecutionMode::RoundingModeRTZ:
1224 RequireFloatControls = VerLower14;
1230 if (RequireFloatControls &&
1231 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
1234 for (
auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
1236 if (
F.isDeclaration())
1238 if (
F.getMetadata(
"reqd_work_group_size"))
1240 SPIRV::OperandCategory::ExecutionModeOperand,
1241 SPIRV::ExecutionMode::LocalSize, ST);
1242 if (
F.getFnAttribute(
"hlsl.numthreads").isValid()) {
1244 SPIRV::OperandCategory::ExecutionModeOperand,
1245 SPIRV::ExecutionMode::LocalSize, ST);
1247 if (
F.getMetadata(
"work_group_size_hint"))
1249 SPIRV::OperandCategory::ExecutionModeOperand,
1250 SPIRV::ExecutionMode::LocalSizeHint, ST);
1251 if (
F.getMetadata(
"intel_reqd_sub_group_size"))
1253 SPIRV::OperandCategory::ExecutionModeOperand,
1254 SPIRV::ExecutionMode::SubgroupSize, ST);
1255 if (
F.getMetadata(
"vec_type_hint"))
1257 SPIRV::OperandCategory::ExecutionModeOperand,
1258 SPIRV::ExecutionMode::VecTypeHint, ST);
1260 if (
F.hasOptNone() &&
1261 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
1270 unsigned Flags = SPIRV::FPFastMathMode::None;
1272 Flags |= SPIRV::FPFastMathMode::NotNaN;
1274 Flags |= SPIRV::FPFastMathMode::NotInf;
1276 Flags |= SPIRV::FPFastMathMode::NSZ;
1278 Flags |= SPIRV::FPFastMathMode::AllowRecip;
1280 Flags |= SPIRV::FPFastMathMode::Fast;
1288 getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
1289 SPIRV::Decoration::NoSignedWrap, ST, Reqs)
1292 SPIRV::Decoration::NoSignedWrap, {});
1295 getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
1296 SPIRV::Decoration::NoUnsignedWrap, ST,
1300 SPIRV::Decoration::NoUnsignedWrap, {});
1302 if (!
TII.canUseFastMathFlags(
I))
1305 if (FMFlags == SPIRV::FPFastMathMode::None)
1307 Register DstReg =
I.getOperand(0).getReg();
1315 for (
auto F = M.begin(), E = M.end();
F != E; ++
F) {
1319 for (
auto &
MBB : *MF)
1320 for (
auto &
MI :
MBB)
1335 ST = TM.getSubtargetImpl();
1336 GR = ST->getSPIRVGlobalRegistry();
1337 TII = ST->getInstrInfo();
1339 MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
1349 processDefInstrs(M);
1352 numberRegistersGlobally(M);
1355 if (GR->hasConstFunPtr())
1359 processOtherInstrs(M);
1366 GR->setBound(MAI.
MaxID);
unsigned const MachineRegisterInfo * MRI
ReachingDefAnalysis InstSet & ToRemove
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
const HexagonInstrInfo * TII
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
#define ATOM_FLT_REQ_EXT_MSG(ExtName)
static void addDecorations(const Module &M, const SPIRVInstrInfo &TII, MachineModuleInfo *MMI, const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI)
static cl::opt< bool > SPVDumpDeps("spv-dump-deps", cl::desc("Dump MIR with SPIR-V dependencies info"), cl::Optional, cl::init(false))
static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI, SPIRV::ModuleSectionType MSType, InstrTraces &IS, bool Append=true)
static void addOpTypeImageReqs(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static void AddAtomicFloatRequirements(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static InstrSignature instrToSignature(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI)
unsigned unsigned DefaultVal
static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII, SPIRV::RequirementHandler &Reqs)
static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI, MachineModuleInfo *MMI, const SPIRVSubtarget &ST)
void addInstrRequirements(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static cl::list< SPIRV::Capability::Capability > AvoidCapabilities("avoid-spirv-capabilities", cl::desc("SPIR-V capabilities to avoid if there are " "other options enabling a feature"), cl::ZeroOrMore, cl::Hidden, cl::values(clEnumValN(SPIRV::Capability::Shader, "Shader", "SPIR-V Shader capability")))
static unsigned getFastMathFlags(const MachineInstr &I)
std::set< InstrSignature > InstrTraces
Target-Independent Code Generator Pass Configuration Options pass.
This is the shared class of boolean and integer constants.
This is an important base class in LLVM.
This class represents an Operation in the Expression.
Implements a dense probed hash-table based set.
const MDOperand & getOperand(unsigned I) const
unsigned getNumOperands() const
Return number of MDNode operands.
Tracking metadata reference owned by Metadata.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
This class contains meta information specific to a module.
MachineFunction * getMachineFunction(const Function &F) const
Returns the MachineFunction associated to IR function F if there is one, otherwise nullptr.
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
A Module instance is used to store all the information related to an LLVM module.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
Wrapper class representing virtual and physical registers.
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
constexpr bool isValid() const
const MachineOperand * getFunctionDefinitionByUse(const MachineOperand *Use)
void buildDepsGraph(std::vector< SPIRV::DTSortableEntry * > &Graph, MachineModuleInfo *MMI=nullptr)
bool isConstantInstr(const MachineInstr &MI) const
bool isDecorationInstr(const MachineInstr &MI) const
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
bool contains(const T &V) const
Check if the SmallSet contains the given element.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
std::pair< typename Base::iterator, bool > insert(StringRef key)
Target-Independent Code Generator Pass Configuration Options.
Target - Wrapper for Target specific information.
Represents a version number in the form major[.minor[.subminor[.build]]].
bool empty() const
Determine whether this version information is empty (e.g., all version components are zero).
std::pair< iterator, bool > insert(const ValueT &V)
@ C
The default llvm calling convention, compatible with C.
Reg
All possible values of the reg field in the ModR/M byte.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
std::string getStringImm(const MachineInstr &MI, unsigned StartIndex)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
hash_code hash_value(const FixedPointSemantics &Val)
ExtensionList getSymbolicOperandExtensions(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
CapabilityList getSymbolicOperandCapabilities(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
VersionTuple getSymbolicOperandMaxVersion(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
void initializeSPIRVModuleAnalysisPass(PassRegistry &)
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
CapabilityList getCapabilitiesEnabledByExtension(SPIRV::Extension::Extension Extension)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
std::string getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category, int32_t Value)
VersionTuple getSymbolicOperandMinVersion(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
constexpr unsigned BitWidth
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
SmallSet< SPIRV::Capability::Capability, 4 > S
static struct SPIRV::ModuleAnalysisInfo MAI
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Register getRegisterAlias(const MachineFunction *MF, Register Reg)
SmallVector< MachineInstr *, 4 > GlobalVarList
DenseMap< const Function *, Register > FuncMap
void setRegisterAlias(const MachineFunction *MF, Register Reg, Register AliasReg)
bool hasRegisterAlias(const MachineFunction *MF, Register Reg)
RegisterAliasMapTy RegisterAliasTable
bool getSkipEmission(const MachineInstr *MI)
MemoryModel::MemoryModel Mem
InstrList MS[NUM_MODULE_SECTIONS]
AddressingModel::AddressingModel Addr
void setSkipEmission(MachineInstr *MI)
SourceLanguage::SourceLanguage SrcLang
DenseSet< MachineInstr * > InstrsToDelete
DenseMap< unsigned, Register > ExtInstSetMap
void checkSatisfiable(const SPIRVSubtarget &ST) const
void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category, uint32_t i, const SPIRVSubtarget &ST)
void addRequirements(const Requirements &Req)
bool isCapabilityAvailable(Capability::Capability Cap) const
void removeCapabilityIf(const Capability::Capability ToRemove, const Capability::Capability IfPresent)
void addAvailableCaps(const CapabilityList &ToAdd)
void addExtension(Extension::Extension ToAdd)
void initAvailableCapabilities(const SPIRVSubtarget &ST)
void addCapability(Capability::Capability ToAdd)
void addCapabilities(const CapabilityList &ToAdd)
const std::optional< Capability::Capability > Cap
const VersionTuple MinVer
const VersionTuple MaxVer