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}, {}, 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}, {}, 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);
713 assert(
MI.getNumOperands() >= 8 &&
"Insufficient operands for OpTypeImage");
716 int64_t ImgFormatOp =
MI.getOperand(7).getImm();
717 auto ImgFormat =
static_cast<SPIRV::ImageFormat::ImageFormat
>(ImgFormatOp);
721 bool IsArrayed =
MI.getOperand(4).getImm() == 1;
722 bool IsMultisampled =
MI.getOperand(5).getImm() == 1;
723 bool NoSampler =
MI.getOperand(6).getImm() == 2;
726 switch (
MI.getOperand(2).getImm()) {
727 case SPIRV::Dim::DIM_1D:
729 : SPIRV::Capability::Sampled1D);
731 case SPIRV::Dim::DIM_2D:
732 if (IsMultisampled && NoSampler)
735 case SPIRV::Dim::DIM_Cube:
739 : SPIRV::Capability::SampledCubeArray);
741 case SPIRV::Dim::DIM_Rect:
743 : SPIRV::Capability::SampledRect);
745 case SPIRV::Dim::DIM_Buffer:
747 : SPIRV::Capability::SampledBuffer);
749 case SPIRV::Dim::DIM_SubpassData:
756 if (
MI.getNumOperands() > 8 &&
757 MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
764#define ATOM_FLT_REQ_EXT_MSG(ExtName) \
765 "The atomic float instruction requires the following SPIR-V " \
766 "extension: SPV_EXT_shader_atomic_float" ExtName
771 "Expect register operand in atomic float instruction");
773 SPIRVType *TypeDef =
MI.getMF()->getRegInfo().getVRegDef(TypeReg);
774 if (TypeDef->
getOpcode() != SPIRV::OpTypeFloat)
776 "floating-point type scalar");
779 unsigned Op =
MI.getOpcode();
780 if (
Op == SPIRV::OpAtomicFAddEXT) {
781 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
783 Reqs.
addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
786 if (!ST.canUseExtension(
787 SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
789 Reqs.
addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
800 "Unexpected floating-point type width in atomic float instruction");
803 if (!ST.canUseExtension(
804 SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
806 Reqs.
addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
809 Reqs.
addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
812 Reqs.
addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
815 Reqs.
addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
819 "Unexpected floating-point type width in atomic float instruction");
827 switch (
MI.getOpcode()) {
828 case SPIRV::OpMemoryModel: {
829 int64_t
Addr =
MI.getOperand(0).getImm();
832 int64_t Mem =
MI.getOperand(1).getImm();
837 case SPIRV::OpEntryPoint: {
838 int64_t Exe =
MI.getOperand(0).getImm();
843 case SPIRV::OpExecutionMode:
844 case SPIRV::OpExecutionModeId: {
845 int64_t Exe =
MI.getOperand(1).getImm();
850 case SPIRV::OpTypeMatrix:
853 case SPIRV::OpTypeInt: {
854 unsigned BitWidth =
MI.getOperand(1).getImm();
863 case SPIRV::OpTypeFloat: {
864 unsigned BitWidth =
MI.getOperand(1).getImm();
871 case SPIRV::OpTypeVector: {
872 unsigned NumComponents =
MI.getOperand(2).getImm();
873 if (NumComponents == 8 || NumComponents == 16)
877 case SPIRV::OpTypePointer: {
878 auto SC =
MI.getOperand(1).getImm();
883 if (!ST.isOpenCLEnv())
888 if (TypeDef->
getOpcode() == SPIRV::OpTypeFloat &&
893 case SPIRV::OpBitReverse:
894 case SPIRV::OpBitFieldInsert:
895 case SPIRV::OpBitFieldSExtract:
896 case SPIRV::OpBitFieldUExtract:
897 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
901 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
904 case SPIRV::OpTypeRuntimeArray:
907 case SPIRV::OpTypeOpaque:
908 case SPIRV::OpTypeEvent:
911 case SPIRV::OpTypePipe:
912 case SPIRV::OpTypeReserveId:
915 case SPIRV::OpTypeDeviceEvent:
916 case SPIRV::OpTypeQueue:
917 case SPIRV::OpBuildNDRange:
920 case SPIRV::OpDecorate:
921 case SPIRV::OpDecorateId:
922 case SPIRV::OpDecorateString:
925 case SPIRV::OpMemberDecorate:
926 case SPIRV::OpMemberDecorateString:
929 case SPIRV::OpInBoundsPtrAccessChain:
932 case SPIRV::OpConstantSampler:
935 case SPIRV::OpTypeImage:
938 case SPIRV::OpTypeSampler:
941 case SPIRV::OpTypeForwardPointer:
945 case SPIRV::OpAtomicFlagTestAndSet:
946 case SPIRV::OpAtomicLoad:
947 case SPIRV::OpAtomicStore:
948 case SPIRV::OpAtomicExchange:
949 case SPIRV::OpAtomicCompareExchange:
950 case SPIRV::OpAtomicIIncrement:
951 case SPIRV::OpAtomicIDecrement:
952 case SPIRV::OpAtomicIAdd:
953 case SPIRV::OpAtomicISub:
954 case SPIRV::OpAtomicUMin:
955 case SPIRV::OpAtomicUMax:
956 case SPIRV::OpAtomicSMin:
957 case SPIRV::OpAtomicSMax:
958 case SPIRV::OpAtomicAnd:
959 case SPIRV::OpAtomicOr:
960 case SPIRV::OpAtomicXor: {
963 if (
MI.getOpcode() == SPIRV::OpAtomicStore) {
965 InstrPtr =
MRI.getVRegDef(
MI.getOperand(3).getReg());
966 assert(InstrPtr &&
"Unexpected type instruction for OpAtomicStore");
971 if (TypeDef->
getOpcode() == SPIRV::OpTypeInt) {
978 case SPIRV::OpGroupNonUniformIAdd:
979 case SPIRV::OpGroupNonUniformFAdd:
980 case SPIRV::OpGroupNonUniformIMul:
981 case SPIRV::OpGroupNonUniformFMul:
982 case SPIRV::OpGroupNonUniformSMin:
983 case SPIRV::OpGroupNonUniformUMin:
984 case SPIRV::OpGroupNonUniformFMin:
985 case SPIRV::OpGroupNonUniformSMax:
986 case SPIRV::OpGroupNonUniformUMax:
987 case SPIRV::OpGroupNonUniformFMax:
988 case SPIRV::OpGroupNonUniformBitwiseAnd:
989 case SPIRV::OpGroupNonUniformBitwiseOr:
990 case SPIRV::OpGroupNonUniformBitwiseXor:
991 case SPIRV::OpGroupNonUniformLogicalAnd:
992 case SPIRV::OpGroupNonUniformLogicalOr:
993 case SPIRV::OpGroupNonUniformLogicalXor: {
995 int64_t GroupOp =
MI.getOperand(3).getImm();
997 case SPIRV::GroupOperation::Reduce:
998 case SPIRV::GroupOperation::InclusiveScan:
999 case SPIRV::GroupOperation::ExclusiveScan:
1001 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1002 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformBallot);
1004 case SPIRV::GroupOperation::ClusteredReduce:
1005 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformClustered);
1007 case SPIRV::GroupOperation::PartitionedReduceNV:
1008 case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
1009 case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
1010 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
1015 case SPIRV::OpGroupNonUniformShuffle:
1016 case SPIRV::OpGroupNonUniformShuffleXor:
1017 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformShuffle);
1019 case SPIRV::OpGroupNonUniformShuffleUp:
1020 case SPIRV::OpGroupNonUniformShuffleDown:
1021 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
1023 case SPIRV::OpGroupAll:
1024 case SPIRV::OpGroupAny:
1025 case SPIRV::OpGroupBroadcast:
1026 case SPIRV::OpGroupIAdd:
1027 case SPIRV::OpGroupFAdd:
1028 case SPIRV::OpGroupFMin:
1029 case SPIRV::OpGroupUMin:
1030 case SPIRV::OpGroupSMin:
1031 case SPIRV::OpGroupFMax:
1032 case SPIRV::OpGroupUMax:
1033 case SPIRV::OpGroupSMax:
1036 case SPIRV::OpGroupNonUniformElect:
1039 case SPIRV::OpGroupNonUniformAll:
1040 case SPIRV::OpGroupNonUniformAny:
1041 case SPIRV::OpGroupNonUniformAllEqual:
1044 case SPIRV::OpGroupNonUniformBroadcast:
1045 case SPIRV::OpGroupNonUniformBroadcastFirst:
1046 case SPIRV::OpGroupNonUniformBallot:
1047 case SPIRV::OpGroupNonUniformInverseBallot:
1048 case SPIRV::OpGroupNonUniformBallotBitExtract:
1049 case SPIRV::OpGroupNonUniformBallotBitCount:
1050 case SPIRV::OpGroupNonUniformBallotFindLSB:
1051 case SPIRV::OpGroupNonUniformBallotFindMSB:
1052 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformBallot);
1054 case SPIRV::OpSubgroupShuffleINTEL:
1055 case SPIRV::OpSubgroupShuffleDownINTEL:
1056 case SPIRV::OpSubgroupShuffleUpINTEL:
1057 case SPIRV::OpSubgroupShuffleXorINTEL:
1058 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1059 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1060 Reqs.
addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
1063 case SPIRV::OpSubgroupBlockReadINTEL:
1064 case SPIRV::OpSubgroupBlockWriteINTEL:
1065 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1066 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1067 Reqs.
addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
1070 case SPIRV::OpSubgroupImageBlockReadINTEL:
1071 case SPIRV::OpSubgroupImageBlockWriteINTEL:
1072 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1073 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1074 Reqs.
addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
1077 case SPIRV::OpAssumeTrueKHR:
1078 case SPIRV::OpExpectKHR:
1079 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
1080 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
1084 case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
1085 case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
1086 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
1087 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
1088 Reqs.
addCapability(SPIRV::Capability::USMStorageClassesINTEL);
1091 case SPIRV::OpConstantFunctionPointerINTEL:
1092 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1093 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1094 Reqs.
addCapability(SPIRV::Capability::FunctionPointersINTEL);
1097 case SPIRV::OpGroupNonUniformRotateKHR:
1098 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
1100 "following SPIR-V extension: SPV_KHR_subgroup_rotate",
1102 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
1103 Reqs.
addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
1106 case SPIRV::OpGroupIMulKHR:
1107 case SPIRV::OpGroupFMulKHR:
1108 case SPIRV::OpGroupBitwiseAndKHR:
1109 case SPIRV::OpGroupBitwiseOrKHR:
1110 case SPIRV::OpGroupBitwiseXorKHR:
1111 case SPIRV::OpGroupLogicalAndKHR:
1112 case SPIRV::OpGroupLogicalOrKHR:
1113 case SPIRV::OpGroupLogicalXorKHR:
1114 if (ST.canUseExtension(
1115 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
1116 Reqs.
addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
1117 Reqs.
addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
1120 case SPIRV::OpFunctionPointerCallINTEL:
1121 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1122 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1123 Reqs.
addCapability(SPIRV::Capability::FunctionPointersINTEL);
1126 case SPIRV::OpAtomicFAddEXT:
1127 case SPIRV::OpAtomicFMinEXT:
1128 case SPIRV::OpAtomicFMaxEXT:
1131 case SPIRV::OpConvertBF16ToFINTEL:
1132 case SPIRV::OpConvertFToBF16INTEL:
1133 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
1134 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
1135 Reqs.
addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
1138 case SPIRV::OpVariableLengthArrayINTEL:
1139 case SPIRV::OpSaveMemoryINTEL:
1140 case SPIRV::OpRestoreMemoryINTEL:
1141 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
1142 Reqs.
addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
1143 Reqs.
addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
1154 SPIRV::Capability::Shader);
1160 for (
auto F = M.begin(), E = M.end();
F != E; ++
F) {
1169 auto Node = M.getNamedMetadata(
"spirv.ExecutionMode");
1172 bool RequireFloatControls =
false,
1173 VerLower14 = !ST.isAtLeastSPIRVVer(
VersionTuple(1, 4));
1174 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
1175 MDNode *MDN = cast<MDNode>(
Node->getOperand(i));
1177 if (
auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
1180 auto EM = Const->getZExtValue();
1182 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
1185 case SPIRV::ExecutionMode::DenormPreserve:
1186 case SPIRV::ExecutionMode::DenormFlushToZero:
1187 case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
1188 case SPIRV::ExecutionMode::RoundingModeRTE:
1189 case SPIRV::ExecutionMode::RoundingModeRTZ:
1190 RequireFloatControls = VerLower14;
1196 if (RequireFloatControls &&
1197 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
1200 for (
auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
1202 if (
F.isDeclaration())
1204 if (
F.getMetadata(
"reqd_work_group_size"))
1206 SPIRV::OperandCategory::ExecutionModeOperand,
1207 SPIRV::ExecutionMode::LocalSize, ST);
1208 if (
F.getFnAttribute(
"hlsl.numthreads").isValid()) {
1210 SPIRV::OperandCategory::ExecutionModeOperand,
1211 SPIRV::ExecutionMode::LocalSize, ST);
1213 if (
F.getMetadata(
"work_group_size_hint"))
1215 SPIRV::OperandCategory::ExecutionModeOperand,
1216 SPIRV::ExecutionMode::LocalSizeHint, ST);
1217 if (
F.getMetadata(
"intel_reqd_sub_group_size"))
1219 SPIRV::OperandCategory::ExecutionModeOperand,
1220 SPIRV::ExecutionMode::SubgroupSize, ST);
1221 if (
F.getMetadata(
"vec_type_hint"))
1223 SPIRV::OperandCategory::ExecutionModeOperand,
1224 SPIRV::ExecutionMode::VecTypeHint, ST);
1226 if (
F.hasOptNone() &&
1227 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
1236 unsigned Flags = SPIRV::FPFastMathMode::None;
1238 Flags |= SPIRV::FPFastMathMode::NotNaN;
1240 Flags |= SPIRV::FPFastMathMode::NotInf;
1242 Flags |= SPIRV::FPFastMathMode::NSZ;
1244 Flags |= SPIRV::FPFastMathMode::AllowRecip;
1246 Flags |= SPIRV::FPFastMathMode::Fast;
1254 getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
1255 SPIRV::Decoration::NoSignedWrap, ST, Reqs)
1258 SPIRV::Decoration::NoSignedWrap, {});
1261 getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
1262 SPIRV::Decoration::NoUnsignedWrap, ST,
1266 SPIRV::Decoration::NoUnsignedWrap, {});
1268 if (!
TII.canUseFastMathFlags(
I))
1271 if (FMFlags == SPIRV::FPFastMathMode::None)
1273 Register DstReg =
I.getOperand(0).getReg();
1281 for (
auto F = M.begin(), E = M.end();
F != E; ++
F) {
1285 for (
auto &
MBB : *MF)
1286 for (
auto &
MI :
MBB)
1301 ST =
TM.getSubtargetImpl();
1302 GR = ST->getSPIRVGlobalRegistry();
1303 TII = ST->getInstrInfo();
1305 MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
1315 processDefInstrs(M);
1318 numberRegistersGlobally(M);
1321 if (GR->hasConstFunPtr())
1325 processOtherInstrs(M);
1332 GR->setBound(MAI.
MaxID);
unsigned const MachineRegisterInfo * MRI
ReachingDefAnalysis InstSet & ToRemove
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
const HexagonInstrInfo * TII
const char LLVMTargetMachineRef TM
#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