Updated spirv-tools.

This commit is contained in:
Бранимир Караџић
2024-12-28 22:40:57 -08:00
parent af34836458
commit b0ef2b8c4b
51 changed files with 1466 additions and 138 deletions

View File

@@ -1 +1 @@
"v2024.4", "SPIRV-Tools v2024.4 v2024.4.rc1-27-g4a6ce351"
"v2024.4", "SPIRV-Tools v2024.4 v2024.4.rc2-10-g7812970d"

View File

@@ -24,8 +24,12 @@ static const spv::Capability pygen_variable_caps_AtomicFloat16MinMaxEXTAtomicFlo
static const spv::Capability pygen_variable_caps_BFloat16ConversionINTEL[] = {spv::Capability::BFloat16ConversionINTEL};
static const spv::Capability pygen_variable_caps_BindlessTextureNV[] = {spv::Capability::BindlessTextureNV};
static const spv::Capability pygen_variable_caps_BlockingPipesINTEL[] = {spv::Capability::BlockingPipesINTEL};
static const spv::Capability pygen_variable_caps_CooperativeMatrixConversionsNV[] = {spv::Capability::CooperativeMatrixConversionsNV};
static const spv::Capability pygen_variable_caps_CooperativeMatrixKHR[] = {spv::Capability::CooperativeMatrixKHR};
static const spv::Capability pygen_variable_caps_CooperativeMatrixNV[] = {spv::Capability::CooperativeMatrixNV};
static const spv::Capability pygen_variable_caps_CooperativeMatrixPerElementOperationsNV[] = {spv::Capability::CooperativeMatrixPerElementOperationsNV};
static const spv::Capability pygen_variable_caps_CooperativeMatrixReductionsNV[] = {spv::Capability::CooperativeMatrixReductionsNV};
static const spv::Capability pygen_variable_caps_CooperativeMatrixTensorAddressingNV[] = {spv::Capability::CooperativeMatrixTensorAddressingNV};
static const spv::Capability pygen_variable_caps_DemoteToHelperInvocation[] = {spv::Capability::DemoteToHelperInvocation};
static const spv::Capability pygen_variable_caps_DerivativeControl[] = {spv::Capability::DerivativeControl};
static const spv::Capability pygen_variable_caps_DeviceEnqueue[] = {spv::Capability::DeviceEnqueue};
@@ -94,6 +98,7 @@ static const spv::Capability pygen_variable_caps_SubgroupImageBlockIOINTEL[] = {
static const spv::Capability pygen_variable_caps_SubgroupImageMediaBlockIOINTEL[] = {spv::Capability::SubgroupImageMediaBlockIOINTEL};
static const spv::Capability pygen_variable_caps_SubgroupShuffleINTEL[] = {spv::Capability::SubgroupShuffleINTEL};
static const spv::Capability pygen_variable_caps_SubgroupVoteKHR[] = {spv::Capability::SubgroupVoteKHR};
static const spv::Capability pygen_variable_caps_TensorAddressingNV[] = {spv::Capability::TensorAddressingNV};
static const spv::Capability pygen_variable_caps_TextureBlockMatch2QCOM[] = {spv::Capability::TextureBlockMatch2QCOM};
static const spv::Capability pygen_variable_caps_TextureBlockMatchQCOM[] = {spv::Capability::TextureBlockMatchQCOM};
static const spv::Capability pygen_variable_caps_TextureBoxFilterQCOM[] = {spv::Capability::TextureBoxFilterQCOM};
@@ -591,6 +596,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
{"ReorderThreadWithHintNV", spv::Op::OpReorderThreadWithHintNV, 0, nullptr, 1, pygen_variable_caps_ShaderInvocationReorderNV, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TypeHitObjectNV", spv::Op::OpTypeHitObjectNV, 0, nullptr, 1, pygen_variable_caps_ShaderInvocationReorderNV, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"ImageSampleFootprintNV", spv::Op::OpImageSampleFootprintNV, 0, nullptr, 1, pygen_variable_caps_ImageFootprintNV, 7, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_IMAGE}, 1, 1, 1, pygen_variable_exts_SPV_NV_shader_image_footprint, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixConvertNV", spv::Op::OpCooperativeMatrixConvertNV, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixConversionsNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"EmitMeshTasksEXT", spv::Op::OpEmitMeshTasksEXT, 0, nullptr, 1, pygen_variable_caps_MeshShadingEXT, 4, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"SetMeshOutputsEXT", spv::Op::OpSetMeshOutputsEXT, 0, nullptr, 1, pygen_variable_caps_MeshShadingEXT, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"GroupNonUniformPartitionNV", spv::Op::OpGroupNonUniformPartitionNV, 0, nullptr, 1, pygen_variable_caps_GroupNonUniformPartitionedNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_NV_shader_subgroup_partitioned, 0xffffffffu, 0xffffffffu},
@@ -613,8 +619,25 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
{"CooperativeMatrixLengthNV", spv::Op::OpCooperativeMatrixLengthNV, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_NV_cooperative_matrix, 0xffffffffu, 0xffffffffu},
{"BeginInvocationInterlockEXT", spv::Op::OpBeginInvocationInterlockEXT, 0, nullptr, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu},
{"EndInvocationInterlockEXT", spv::Op::OpEndInvocationInterlockEXT, 0, nullptr, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixReduceNV", spv::Op::OpCooperativeMatrixReduceNV, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixReductionsNV, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixLoadTensorNV", spv::Op::OpCooperativeMatrixLoadTensorNV, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixTensorAddressingNV, 7, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_MEMORY_ACCESS, SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixStoreTensorNV", spv::Op::OpCooperativeMatrixStoreTensorNV, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixTensorAddressingNV, 5, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_MEMORY_ACCESS, SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixPerElementOpNV", spv::Op::OpCooperativeMatrixPerElementOpNV, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixPerElementOperationsNV, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TypeTensorLayoutNV", spv::Op::OpTypeTensorLayoutNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 3, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TypeTensorViewNV", spv::Op::OpTypeTensorViewNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 4, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"CreateTensorLayoutNV", spv::Op::OpCreateTensorLayoutNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TensorLayoutSetDimensionNV", spv::Op::OpTensorLayoutSetDimensionNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TensorLayoutSetStrideNV", spv::Op::OpTensorLayoutSetStrideNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TensorLayoutSliceNV", spv::Op::OpTensorLayoutSliceNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TensorLayoutSetClampValueNV", spv::Op::OpTensorLayoutSetClampValueNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"CreateTensorViewNV", spv::Op::OpCreateTensorViewNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TensorViewSetDimensionNV", spv::Op::OpTensorViewSetDimensionNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TensorViewSetStrideNV", spv::Op::OpTensorViewSetStrideNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"DemoteToHelperInvocation", spv::Op::OpDemoteToHelperInvocation, 1, pygen_variable_aliases_OpDemoteToHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocation, 0, {}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu},
{"IsHelperInvocationEXT", spv::Op::OpIsHelperInvocationEXT, 0, nullptr, 1, pygen_variable_caps_DemoteToHelperInvocation, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, 0xffffffffu, 0xffffffffu},
{"TensorViewSetClipNV", spv::Op::OpTensorViewSetClipNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 7, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TensorLayoutSetBlockSizeNV", spv::Op::OpTensorLayoutSetBlockSizeNV, 0, nullptr, 1, pygen_variable_caps_TensorAddressingNV, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixTransposeNV", spv::Op::OpCooperativeMatrixTransposeNV, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixConversionsNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"ConvertUToImageNV", spv::Op::OpConvertUToImageNV, 0, nullptr, 1, pygen_variable_caps_BindlessTextureNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"ConvertUToSamplerNV", spv::Op::OpConvertUToSamplerNV, 0, nullptr, 1, pygen_variable_caps_BindlessTextureNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"ConvertImageToUNV", spv::Op::OpConvertImageToUNV, 0, nullptr, 1, pygen_variable_caps_BindlessTextureNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},

File diff suppressed because one or more lines are too long

View File

@@ -120,6 +120,7 @@ kSPV_NVX_multiview_per_view_attributes,
kSPV_NV_bindless_texture,
kSPV_NV_compute_shader_derivatives,
kSPV_NV_cooperative_matrix,
kSPV_NV_cooperative_matrix2,
kSPV_NV_displacement_micromap,
kSPV_NV_fragment_shader_barycentric,
kSPV_NV_geometry_shader_passthrough,
@@ -135,6 +136,7 @@ kSPV_NV_shader_sm_builtins,
kSPV_NV_shader_subgroup_partitioned,
kSPV_NV_shading_rate,
kSPV_NV_stereo_view_rendering,
kSPV_NV_tensor_addressing,
kSPV_NV_viewport_array2,
kSPV_QCOM_image_processing,
kSPV_QCOM_image_processing2,

View File

@@ -43,4 +43,5 @@
{42, "Rendong Liang", "spq", "Rendong Liang spq"},
{43, "LLVM", "LLVM SPIR-V Backend", "LLVM LLVM SPIR-V Backend"},
{44, "Robert Konrad", "Kongruent", "Robert Konrad Kongruent"},
{45, "Kitsunebi Games", "Nuvk SPIR-V Emitter and DLSL compiler", "Kitsunebi Games Nuvk SPIR-V Emitter and DLSL compiler"},
{45, "Kitsunebi Games", "Nuvk SPIR-V Emitter and DLSL compiler", "Kitsunebi Games Nuvk SPIR-V Emitter and DLSL compiler"},
{46, "Nintendo", "", "Nintendo"},

View File

@@ -100,6 +100,8 @@ static const spv::Capability pygen_variable_caps_CacheControlsINTEL[] = {spv::Ca
static const spv::Capability pygen_variable_caps_ClipDistance[] = {spv::Capability::ClipDistance};
static const spv::Capability pygen_variable_caps_ComputeDerivativeGroupLinearNVComputeDerivativeGroupLinearKHR[] = {spv::Capability::ComputeDerivativeGroupLinearNV, spv::Capability::ComputeDerivativeGroupLinearKHR};
static const spv::Capability pygen_variable_caps_ComputeDerivativeGroupQuadsNVComputeDerivativeGroupQuadsKHR[] = {spv::Capability::ComputeDerivativeGroupQuadsNV, spv::Capability::ComputeDerivativeGroupQuadsKHR};
static const spv::Capability pygen_variable_caps_CooperativeMatrixBlockLoadsNV[] = {spv::Capability::CooperativeMatrixBlockLoadsNV};
static const spv::Capability pygen_variable_caps_CooperativeMatrixTensorAddressingNV[] = {spv::Capability::CooperativeMatrixTensorAddressingNV};
static const spv::Capability pygen_variable_caps_CoreBuiltinsARM[] = {spv::Capability::CoreBuiltinsARM};
static const spv::Capability pygen_variable_caps_CullDistance[] = {spv::Capability::CullDistance};
static const spv::Capability pygen_variable_caps_DenormFlushToZero[] = {spv::Capability::DenormFlushToZero};
@@ -351,6 +353,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NVX_multiview_per_view_
static const spvtools::Extension pygen_variable_exts_SPV_NVX_multiview_per_view_attributesSPV_NV_mesh_shader[] = {spvtools::Extension::kSPV_NVX_multiview_per_view_attributes, spvtools::Extension::kSPV_NV_mesh_shader};
static const spvtools::Extension pygen_variable_exts_SPV_NV_bindless_texture[] = {spvtools::Extension::kSPV_NV_bindless_texture};
static const spvtools::Extension pygen_variable_exts_SPV_NV_cooperative_matrix[] = {spvtools::Extension::kSPV_NV_cooperative_matrix};
static const spvtools::Extension pygen_variable_exts_SPV_NV_cooperative_matrix2[] = {spvtools::Extension::kSPV_NV_cooperative_matrix2};
static const spvtools::Extension pygen_variable_exts_SPV_NV_displacement_micromap[] = {spvtools::Extension::kSPV_NV_displacement_micromap};
static const spvtools::Extension pygen_variable_exts_SPV_NV_geometry_shader_passthrough[] = {spvtools::Extension::kSPV_NV_geometry_shader_passthrough};
static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shader[] = {spvtools::Extension::kSPV_NV_mesh_shader};
@@ -365,6 +368,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_invocation_re
static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_sm_builtins[] = {spvtools::Extension::kSPV_NV_shader_sm_builtins};
static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_subgroup_partitioned[] = {spvtools::Extension::kSPV_NV_shader_subgroup_partitioned};
static const spvtools::Extension pygen_variable_exts_SPV_NV_stereo_view_rendering[] = {spvtools::Extension::kSPV_NV_stereo_view_rendering};
static const spvtools::Extension pygen_variable_exts_SPV_NV_tensor_addressing[] = {spvtools::Extension::kSPV_NV_tensor_addressing};
static const spvtools::Extension pygen_variable_exts_SPV_NV_viewport_array2[] = {spvtools::Extension::kSPV_NV_viewport_array2};
static const spvtools::Extension pygen_variable_exts_SPV_QCOM_image_processing[] = {spvtools::Extension::kSPV_QCOM_image_processing};
static const spvtools::Extension pygen_variable_exts_SPV_QCOM_image_processing2[] = {spvtools::Extension::kSPV_QCOM_image_processing2};
@@ -1317,6 +1321,12 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"AtomicFloat16VectorNV", 5404, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_NV_shader_atomic_fp16_vector, {}, 0xffffffffu, 0xffffffffu},
{"RayTracingDisplacementMicromapNV", 5409, 0, nullptr, 1, pygen_variable_caps_RayTracingKHR, 1, pygen_variable_exts_SPV_NV_displacement_micromap, {}, 0xffffffffu, 0xffffffffu},
{"RawAccessChainsNV", 5414, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_NV_raw_access_chains, {}, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixReductionsNV", 5430, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_NV_cooperative_matrix2, {}, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixConversionsNV", 5431, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_NV_cooperative_matrix2, {}, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixPerElementOperationsNV", 5432, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_NV_cooperative_matrix2, {}, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixTensorAddressingNV", 5433, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_NV_cooperative_matrix2, {}, 0xffffffffu, 0xffffffffu},
{"CooperativeMatrixBlockLoadsNV", 5434, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_NV_cooperative_matrix2, {}, 0xffffffffu, 0xffffffffu},
{"TensorAddressingNV", 5439, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_NV_tensor_addressing, {}, 0xffffffffu, 0xffffffffu},
{"SubgroupShuffleINTEL", 5568, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
{"SubgroupBufferBlockIOINTEL", 5569, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
{"SubgroupImageBlockIOINTEL", 5570, 0, nullptr, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
@@ -1434,6 +1444,26 @@ static const spv_operand_desc_t pygen_variable_CooperativeMatrixUseEntries[] = {
{"MatrixAccumulatorKHR", 2, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_CooperativeMatrixReduceEntries[] = {
{"Row", 0x0001, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"Column", 0x0002, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"2x2", 0x0004, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_TensorClampModeEntries[] = {
{"Undefined", 0, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"Constant", 1, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"ClampToEdge", 2, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"Repeat", 3, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"RepeatMirrored", 4, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_TensorAddressingOperandsEntries[] = {
{"None", 0x0000, 0, nullptr, 0, nullptr, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"TensorView", 0x0001, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixTensorAddressingNV, 0, nullptr, {SPV_OPERAND_TYPE_ID}, 0xffffffffu, 0xffffffffu},
{"DecodeFunc", 0x0002, 0, nullptr, 1, pygen_variable_caps_CooperativeMatrixBlockLoadsNV, 0, nullptr, {SPV_OPERAND_TYPE_ID}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_InitializationModeQualifierEntries[] = {
{"InitOnDeviceReprogramINTEL", 0, 0, nullptr, 1, pygen_variable_caps_GlobalVariableFPGADecorationsINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"InitOnDeviceResetINTEL", 1, 0, nullptr, 1, pygen_variable_caps_GlobalVariableFPGADecorationsINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
@@ -1626,6 +1656,9 @@ static const spv_operand_desc_group_t pygen_variable_OperandInfoTable[] = {
{SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS, ARRAY_SIZE(pygen_variable_CooperativeMatrixOperandsEntries), pygen_variable_CooperativeMatrixOperandsEntries},
{SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT, ARRAY_SIZE(pygen_variable_CooperativeMatrixLayoutEntries), pygen_variable_CooperativeMatrixLayoutEntries},
{SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE, ARRAY_SIZE(pygen_variable_CooperativeMatrixUseEntries), pygen_variable_CooperativeMatrixUseEntries},
{SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE, ARRAY_SIZE(pygen_variable_CooperativeMatrixReduceEntries), pygen_variable_CooperativeMatrixReduceEntries},
{SPV_OPERAND_TYPE_TENSOR_CLAMP_MODE, ARRAY_SIZE(pygen_variable_TensorClampModeEntries), pygen_variable_TensorClampModeEntries},
{SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS, ARRAY_SIZE(pygen_variable_TensorAddressingOperandsEntries), pygen_variable_TensorAddressingOperandsEntries},
{SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER, ARRAY_SIZE(pygen_variable_InitializationModeQualifierEntries), pygen_variable_InitializationModeQualifierEntries},
{SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL, ARRAY_SIZE(pygen_variable_LoadCacheControlEntries), pygen_variable_LoadCacheControlEntries},
{SPV_OPERAND_TYPE_STORE_CACHE_CONTROL, ARRAY_SIZE(pygen_variable_StoreCacheControlEntries), pygen_variable_StoreCacheControlEntries},

View File

@@ -315,6 +315,12 @@ typedef enum spv_operand_type_t {
SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS,
// Optional enum type from SPV_NV_raw_access_chains
SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS,
// Enum type from SPV_NV_tensor_addressing
SPV_OPERAND_TYPE_TENSOR_CLAMP_MODE,
// Enum type from SPV_NV_cooperative_matrix2
SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE,
// Enum type from SPV_NV_cooperative_matrix2
SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS,
// This is a sentinel value, and does not represent an operand type.
// It should come last.
@@ -535,6 +541,7 @@ SPIRV_TOOLS_EXPORT const char* spvSoftwareVersionDetailsString(void);
// SPV_ENV_VULKAN_1_1_SPIRV_1_4 -> SPIR-V 1.4
// SPV_ENV_VULKAN_1_2 -> SPIR-V 1.5
// SPV_ENV_VULKAN_1_3 -> SPIR-V 1.6
// SPV_ENV_VULKAN_1_4 -> SPIR-V 1.6
// Consult the description of API entry points for specific rules.
typedef enum {
SPV_ENV_UNIVERSAL_1_0, // SPIR-V 1.0 latest revision, no other restrictions.
@@ -572,6 +579,7 @@ typedef enum {
SPV_ENV_UNIVERSAL_1_6, // SPIR-V 1.6 latest revision, no other restrictions.
SPV_ENV_VULKAN_1_3, // Vulkan 1.3 latest revision.
SPV_ENV_VULKAN_1_4, // Vulkan 1.4 latest revision.
SPV_ENV_MAX // Keep this as the last enum value.
} spv_target_env;

View File

@@ -717,13 +717,16 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
case SPV_OPERAND_TYPE_LOOP_CONTROL:
case SPV_OPERAND_TYPE_IMAGE:
case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
case SPV_OPERAND_TYPE_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
case SPV_OPERAND_TYPE_SELECTION_CONTROL:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: {
case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS:
case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE:
case SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS: {
// This operand is a mask.
// Map an optional operand type to its corresponding concrete type.

View File

@@ -23,8 +23,10 @@
#include <cassert>
#include <cstring>
#include <iomanip>
#include <ios>
#include <memory>
#include <set>
#include <sstream>
#include <stack>
#include <unordered_map>
#include <utility>

View File

@@ -15,7 +15,7 @@
#ifndef SOURCE_DISASSEMBLE_H_
#define SOURCE_DISASSEMBLE_H_
#include <iosfwd>
#include <ios>
#include <sstream>
#include <string>
@@ -94,11 +94,11 @@ class InstructionDisassembler {
// Emits an operand for the given instruction, where the instruction
// is at offset words from the start of the binary.
void EmitOperand(std::ostream& stream, const spv_parsed_instruction_t& inst,
const uint16_t operand_index) const;
uint16_t operand_index) const;
// Emits a mask expression for the given mask word of the specified type.
void EmitMaskOperand(std::ostream& stream, const spv_operand_type_t type,
const uint32_t word) const;
void EmitMaskOperand(std::ostream& stream, spv_operand_type_t type,
uint32_t word) const;
// Generate part of the instruction as a comment to be added to
// |id_comments_|.

View File

@@ -12,11 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stddef.h>
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <iterator>
#include <limits>
#include <type_traits>
#include <vector>

View File

@@ -102,6 +102,7 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable,
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_VULKAN_1_4:
*pExtInstTable = &kTable_1_0;
return SPV_SUCCESS;
default:

View File

@@ -382,6 +382,8 @@ int32_t spvOpcodeGeneratesType(spv::Op op) {
case spv::Op::OpTypeRayQueryKHR:
case spv::Op::OpTypeHitObjectNV:
case spv::Op::OpTypeUntypedPointerKHR:
case spv::Op::OpTypeTensorLayoutNV:
case spv::Op::OpTypeTensorViewNV:
return true;
default:
// In particular, OpTypeForwardPointer does not generate a type,
@@ -419,6 +421,7 @@ bool spvOpcodeIsLoad(const spv::Op opcode) {
case spv::Op::OpImageSampleProjExplicitLod:
case spv::Op::OpImageSampleProjDrefImplicitLod:
case spv::Op::OpImageSampleProjDrefExplicitLod:
case spv::Op::OpImageSampleFootprintNV:
case spv::Op::OpImageFetch:
case spv::Op::OpImageGather:
case spv::Op::OpImageDrefGather:
@@ -745,6 +748,7 @@ bool spvOpcodeIsImageSample(const spv::Op opcode) {
case spv::Op::OpImageSparseSampleExplicitLod:
case spv::Op::OpImageSparseSampleDrefImplicitLod:
case spv::Op::OpImageSparseSampleDrefExplicitLod:
case spv::Op::OpImageSampleFootprintNV:
return true;
default:
return false;

View File

@@ -231,6 +231,12 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
return "cooperative matrix layout";
case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE:
return "cooperative matrix use";
case SPV_OPERAND_TYPE_TENSOR_CLAMP_MODE:
return "tensor clamp mode";
case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE:
return "cooperative matrix reduce";
case SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS:
return "tensor addressing operands";
case SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER:
return "initialization mode qualifier";
case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER:
@@ -389,6 +395,7 @@ bool spvOperandIsConcrete(spv_operand_type_t type) {
case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL:
case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS:
case SPV_OPERAND_TYPE_FPENCODING:
case SPV_OPERAND_TYPE_TENSOR_CLAMP_MODE:
return true;
default:
break;
@@ -409,6 +416,8 @@ bool spvOperandIsConcreteMask(spv_operand_type_t type) {
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS:
case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE:
case SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS:
return true;
default:
break;
@@ -598,6 +607,16 @@ std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
case spv::Op::OpTypeArray:
out = [](unsigned index) { return index == 1; };
break;
case spv::Op::OpCooperativeMatrixPerElementOpNV:
out = [](unsigned index) { return index == 3; };
break;
case spv::Op::OpCooperativeMatrixReduceNV:
out = [](unsigned index) { return index == 4; };
break;
case spv::Op::OpCooperativeMatrixLoadTensorNV:
// approximate, due to variable operands
out = [](unsigned index) { return index > 6; };
break;
default:
out = [](unsigned) { return false; };
break;

View File

@@ -43,6 +43,7 @@ constexpr uint32_t kGlobalVariableVariableIndex = 12;
constexpr uint32_t kExtInstSetInIdx = 0;
constexpr uint32_t kExtInstOpInIdx = 1;
constexpr uint32_t kInterpolantInIdx = 2;
constexpr uint32_t kCooperativeMatrixLoadSourceAddrInIdx = 0;
// Sorting functor to present annotation instructions in an easy-to-process
// order. The functor orders by opcode first and falls back on unique id
@@ -438,6 +439,11 @@ uint32_t AggressiveDCEPass::GetLoadedVariableFromNonFunctionCalls(
}
break;
}
case spv::Op::OpCooperativeMatrixLoadNV:
case spv::Op::OpCooperativeMatrixLoadKHR:
case spv::Op::OpCooperativeMatrixLoadTensorNV:
return GetVariableId(
inst->GetSingleWordInOperand(kCooperativeMatrixLoadSourceAddrInIdx));
default:
break;
}
@@ -670,6 +676,7 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() {
auto op = dbg.GetShader100DebugOpcode();
if (op == NonSemanticShaderDebugInfo100DebugCompilationUnit ||
op == NonSemanticShaderDebugInfo100DebugEntryPoint ||
op == NonSemanticShaderDebugInfo100DebugSource ||
op == NonSemanticShaderDebugInfo100DebugSourceContinued) {
AddToWorklist(&dbg);
}
@@ -1029,7 +1036,8 @@ void AggressiveDCEPass::InitExtensions() {
"SPV_KHR_compute_shader_derivatives",
"SPV_NV_cooperative_matrix",
"SPV_KHR_cooperative_matrix",
"SPV_KHR_ray_tracing_position_fetch"
"SPV_KHR_ray_tracing_position_fetch",
"SPV_KHR_fragment_shading_rate"
});
// clang-format on
}

View File

@@ -70,6 +70,11 @@ void EliminateDeadMembersPass::FindLiveMembers() {
MarkPointeeTypeAsFullUsed(inst.type_id());
break;
}
} else if (inst.opcode() == spv::Op::OpTypePointer) {
uint32_t storage_class = inst.GetSingleWordInOperand(0);
if (storage_class == uint32_t(spv::StorageClass::PhysicalStorageBuffer)) {
MarkTypeAsFullyUsed(inst.GetSingleWordInOperand(1));
}
}
}
@@ -200,6 +205,8 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForExtract(
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeCooperativeMatrixNV:
case spv::Op::OpTypeCooperativeMatrixKHR:
type_id = type_inst->GetSingleWordInOperand(0);
break;
default:
@@ -246,6 +253,8 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForAccessChain(
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeCooperativeMatrixNV:
case spv::Op::OpTypeCooperativeMatrixKHR:
type_id = type_inst->GetSingleWordInOperand(0);
break;
default:
@@ -505,6 +514,8 @@ bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) {
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeCooperativeMatrixNV:
case spv::Op::OpTypeCooperativeMatrixKHR:
new_operands.emplace_back(inst->GetInOperand(i));
type_id = type_inst->GetSingleWordInOperand(0);
break;
@@ -578,6 +589,8 @@ bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) {
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeCooperativeMatrixNV:
case spv::Op::OpTypeCooperativeMatrixKHR:
type_id = type_inst->GetSingleWordInOperand(0);
break;
default:
@@ -639,6 +652,8 @@ bool EliminateDeadMembersPass::UpdateCompositeInsert(Instruction* inst) {
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeCooperativeMatrixNV:
case spv::Op::OpTypeCooperativeMatrixKHR:
type_id = type_inst->GetSingleWordInOperand(0);
break;
default:

View File

@@ -1790,6 +1790,7 @@ bool CompositeExtractFeedingConstruct(
return false;
}
}
assert(first_element_inst != nullptr);
// The last check it to see that the object being extracted from is the
// correct type.

View File

@@ -926,9 +926,35 @@ uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
void IRContext::AddCalls(const Function* func, std::queue<uint32_t>* todo) {
for (auto bi = func->begin(); bi != func->end(); ++bi)
for (auto ii = bi->begin(); ii != bi->end(); ++ii)
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
if (ii->opcode() == spv::Op::OpFunctionCall)
todo->push(ii->GetSingleWordInOperand(0));
if (ii->opcode() == spv::Op::OpCooperativeMatrixPerElementOpNV)
todo->push(ii->GetSingleWordInOperand(1));
if (ii->opcode() == spv::Op::OpCooperativeMatrixReduceNV)
todo->push(ii->GetSingleWordInOperand(2));
if (ii->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) {
const auto memory_operands_index = 3;
auto mask = ii->GetSingleWordInOperand(memory_operands_index);
uint32_t count = 1;
if (mask & uint32_t(spv::MemoryAccessMask::Aligned)) ++count;
if (mask & uint32_t(spv::MemoryAccessMask::MakePointerAvailableKHR))
++count;
if (mask & uint32_t(spv::MemoryAccessMask::MakePointerVisibleKHR))
++count;
const auto tensor_operands_index = memory_operands_index + count;
mask = ii->GetSingleWordInOperand(tensor_operands_index);
count = 1;
if (mask & uint32_t(spv::TensorAddressingOperandsMask::TensorView))
++count;
if (mask & uint32_t(spv::TensorAddressingOperandsMask::DecodeFunc)) {
todo->push(ii->GetSingleWordInOperand(tensor_operands_index + count));
}
}
}
}
bool IRContext::ProcessEntryPointCallTree(ProcessFunction& pfn) {

View File

@@ -430,7 +430,8 @@ void LocalAccessChainConvertPass::InitExtensions() {
"SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add",
"SPV_EXT_fragment_shader_interlock",
"SPV_KHR_compute_shader_derivatives", "SPV_NV_cooperative_matrix",
"SPV_KHR_cooperative_matrix", "SPV_KHR_ray_tracing_position_fetch"});
"SPV_KHR_cooperative_matrix", "SPV_KHR_ray_tracing_position_fetch",
"SPV_KHR_fragment_shading_rate"});
}
bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds(

View File

@@ -294,7 +294,8 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
"SPV_KHR_compute_shader_derivatives",
"SPV_NV_cooperative_matrix",
"SPV_KHR_cooperative_matrix",
"SPV_KHR_ray_tracing_position_fetch"});
"SPV_KHR_ray_tracing_position_fetch",
"SPV_KHR_fragment_shading_rate"});
}
} // namespace opt

View File

@@ -144,7 +144,8 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() {
"SPV_KHR_compute_shader_derivatives",
"SPV_NV_cooperative_matrix",
"SPV_KHR_cooperative_matrix",
"SPV_KHR_ray_tracing_position_fetch"});
"SPV_KHR_ray_tracing_position_fetch",
"SPV_KHR_fragment_shading_rate"});
}
bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
std::vector<Instruction*> users;

View File

@@ -499,6 +499,7 @@ Pass::Status LoopFissionPass::Process() {
// next iteration.
if (split_multiple_times_) {
inner_most_loops = std::move(new_loops_to_split);
new_loops_to_split = {};
} else {
break;
}

View File

@@ -18,6 +18,7 @@
#include <charconv>
#include <memory>
#include <string>
#include <system_error>
#include <unordered_map>
#include <utility>
#include <vector>

View File

@@ -49,6 +49,7 @@ constexpr uint32_t kOpTypeImageMSIndex = kOpTypeImageArrayedIndex + 1;
constexpr uint32_t kOpTypeImageSampledIndex = kOpTypeImageMSIndex + 1;
constexpr uint32_t kOpTypeImageFormatIndex = kOpTypeImageSampledIndex + 1;
constexpr uint32_t kOpImageReadImageIndex = 0;
constexpr uint32_t kOpImageWriteImageIndex = 0;
constexpr uint32_t kOpImageSparseReadImageIndex = 0;
constexpr uint32_t kOpExtInstSetInIndex = 0;
constexpr uint32_t kOpExtInstInstructionInIndex = 1;
@@ -338,6 +339,8 @@ Handler_OpImageRead_StorageImageReadWithoutFormat(
const uint32_t dim = type->GetSingleWordInOperand(kOpTypeImageDimIndex);
const uint32_t format = type->GetSingleWordInOperand(kOpTypeImageFormatIndex);
// If the Image Format is Unknown and Dim is SubpassData,
// StorageImageReadWithoutFormat is required.
const bool is_unknown = spv::ImageFormat(format) == spv::ImageFormat::Unknown;
const bool requires_capability_for_unknown =
spv::Dim(dim) != spv::Dim::SubpassData;
@@ -346,6 +349,26 @@ Handler_OpImageRead_StorageImageReadWithoutFormat(
: std::nullopt;
}
static std::optional<spv::Capability>
Handler_OpImageWrite_StorageImageWriteWithoutFormat(
const Instruction* instruction) {
assert(instruction->opcode() == spv::Op::OpImageWrite &&
"This handler only support OpImageWrite opcodes.");
const auto* def_use_mgr = instruction->context()->get_def_use_mgr();
const uint32_t image_index =
instruction->GetSingleWordInOperand(kOpImageWriteImageIndex);
const uint32_t type_index = def_use_mgr->GetDef(image_index)->type_id();
// If the Image Format is Unknown, StorageImageWriteWithoutFormat is required.
const Instruction* type = def_use_mgr->GetDef(type_index);
const uint32_t format = type->GetSingleWordInOperand(kOpTypeImageFormatIndex);
const bool is_unknown = spv::ImageFormat(format) == spv::ImageFormat::Unknown;
return is_unknown
? std::optional(spv::Capability::StorageImageWriteWithoutFormat)
: std::nullopt;
}
static std::optional<spv::Capability>
Handler_OpImageSparseRead_StorageImageReadWithoutFormat(
const Instruction* instruction) {
@@ -365,9 +388,10 @@ Handler_OpImageSparseRead_StorageImageReadWithoutFormat(
}
// Opcode of interest to determine capabilities requirements.
constexpr std::array<std::pair<spv::Op, OpcodeHandler>, 12> kOpcodeHandlers{{
constexpr std::array<std::pair<spv::Op, OpcodeHandler>, 13> kOpcodeHandlers{{
// clang-format off
{spv::Op::OpImageRead, Handler_OpImageRead_StorageImageReadWithoutFormat},
{spv::Op::OpImageWrite, Handler_OpImageWrite_StorageImageWriteWithoutFormat},
{spv::Op::OpImageSparseRead, Handler_OpImageSparseRead_StorageImageReadWithoutFormat},
{spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float16 },
{spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float64 },

View File

@@ -100,6 +100,7 @@ class TrimCapabilitiesPass : public Pass {
spv::Capability::Shader,
spv::Capability::ShaderClockKHR,
spv::Capability::StorageImageReadWithoutFormat,
spv::Capability::StorageImageWriteWithoutFormat,
spv::Capability::StorageInputOutput16,
spv::Capability::StoragePushConstant16,
spv::Capability::StorageUniform16,

View File

@@ -441,6 +441,28 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) {
{SPV_OPERAND_TYPE_ID, {coop_mat->use_id()}}});
break;
}
case Type::kTensorLayoutNV: {
auto tensor_layout = type->AsTensorLayoutNV();
typeInst = MakeUnique<Instruction>(
context(), spv::Op::OpTypeTensorLayoutNV, 0, id,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {tensor_layout->dim_id()}},
{SPV_OPERAND_TYPE_ID, {tensor_layout->clamp_mode_id()}}});
break;
}
case Type::kTensorViewNV: {
auto tensor_view = type->AsTensorViewNV();
std::vector<Operand> operands;
operands.push_back(Operand{SPV_OPERAND_TYPE_ID, {tensor_view->dim_id()}});
operands.push_back(
Operand{SPV_OPERAND_TYPE_ID, {tensor_view->has_dimensions_id()}});
for (auto p : tensor_view->perm()) {
operands.push_back(Operand{SPV_OPERAND_TYPE_ID, {p}});
}
typeInst = MakeUnique<Instruction>(context(), spv::Op::OpTypeTensorViewNV,
0, id, operands);
break;
}
default:
assert(false && "Unexpected type");
break;
@@ -667,6 +689,18 @@ Type* TypeManager::RebuildType(uint32_t type_id, const Type& type) {
cm_type->use_id());
break;
}
case Type::kTensorLayoutNV: {
const TensorLayoutNV* tl_type = type.AsTensorLayoutNV();
rebuilt_ty = MakeUnique<TensorLayoutNV>(tl_type->dim_id(),
tl_type->clamp_mode_id());
break;
}
case Type::kTensorViewNV: {
const TensorViewNV* tv_type = type.AsTensorViewNV();
rebuilt_ty = MakeUnique<TensorViewNV>(
tv_type->dim_id(), tv_type->has_dimensions_id(), tv_type->perm());
break;
}
default:
assert(false && "Unhandled type");
return nullptr;
@@ -914,6 +948,20 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) {
case spv::Op::OpTypeHitObjectNV:
type = new HitObjectNV();
break;
case spv::Op::OpTypeTensorLayoutNV:
type = new TensorLayoutNV(inst.GetSingleWordInOperand(0),
inst.GetSingleWordInOperand(1));
break;
case spv::Op::OpTypeTensorViewNV: {
const auto count = inst.NumOperands();
std::vector<uint32_t> perm;
for (uint32_t i = 2; i < count; ++i) {
perm.push_back(inst.GetSingleWordOperand(i));
}
type = new TensorViewNV(inst.GetSingleWordInOperand(0),
inst.GetSingleWordInOperand(1), perm);
break;
}
default:
assert(false && "Type not handled by the type manager.");
break;

View File

@@ -179,6 +179,8 @@ bool Type::operator==(const Type& other) const {
DeclareKindCase(CooperativeMatrixKHR);
DeclareKindCase(RayQueryKHR);
DeclareKindCase(HitObjectNV);
DeclareKindCase(TensorLayoutNV);
DeclareKindCase(TensorViewNV);
#undef DeclareKindCase
default:
assert(false && "Unhandled type");
@@ -235,6 +237,8 @@ size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const {
DeclareKindCase(CooperativeMatrixKHR);
DeclareKindCase(RayQueryKHR);
DeclareKindCase(HitObjectNV);
DeclareKindCase(TensorLayoutNV);
DeclareKindCase(TensorViewNV);
#undef DeclareKindCase
default:
assert(false && "Unhandled type");
@@ -747,7 +751,55 @@ bool CooperativeMatrixKHR::IsSameImpl(const Type* that,
if (!mt) return false;
return component_type_->IsSameImpl(mt->component_type_, seen) &&
scope_id_ == mt->scope_id_ && rows_id_ == mt->rows_id_ &&
columns_id_ == mt->columns_id_ && HasSameDecorations(that);
columns_id_ == mt->columns_id_ && use_id_ == mt->use_id_ &&
HasSameDecorations(that);
}
TensorLayoutNV::TensorLayoutNV(const uint32_t dim, const uint32_t clamp_mode)
: Type(kTensorLayoutNV), dim_id_(dim), clamp_mode_id_(clamp_mode) {}
std::string TensorLayoutNV::str() const {
std::ostringstream oss;
oss << "<" << dim_id_ << ", " << clamp_mode_id_ << ">";
return oss.str();
}
size_t TensorLayoutNV::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
return hash_combine(hash, dim_id_, clamp_mode_id_);
}
bool TensorLayoutNV::IsSameImpl(const Type* that, IsSameCache*) const {
const TensorLayoutNV* tl = that->AsTensorLayoutNV();
if (!tl) return false;
return dim_id_ == tl->dim_id_ && clamp_mode_id_ == tl->clamp_mode_id_;
}
TensorViewNV::TensorViewNV(const uint32_t dim, const uint32_t clamp_mode,
const std::vector<uint32_t>& perm)
: Type(kTensorViewNV),
dim_id_(dim),
has_dimensions_id_(clamp_mode),
perm_(perm) {}
std::string TensorViewNV::str() const {
std::ostringstream oss;
oss << "<" << dim_id_ << ", " << has_dimensions_id_;
for (auto p : perm_) {
oss << ", " << p;
}
oss << ">";
return oss.str();
}
size_t TensorViewNV::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
return hash_combine(hash, dim_id_, has_dimensions_id_, perm_);
}
bool TensorViewNV::IsSameImpl(const Type* that, IsSameCache*) const {
const TensorViewNV* tv = that->AsTensorViewNV();
if (!tv) return false;
return dim_id_ == tv->dim_id_ &&
has_dimensions_id_ == tv->has_dimensions_id_ && perm_ == tv->perm_;
}
} // namespace analysis

View File

@@ -63,6 +63,8 @@ class CooperativeMatrixNV;
class CooperativeMatrixKHR;
class RayQueryKHR;
class HitObjectNV;
class TensorLayoutNV;
class TensorViewNV;
// Abstract class for a SPIR-V type. It has a bunch of As<sublcass>() methods,
// which is used as a way to probe the actual <subclass>.
@@ -104,6 +106,8 @@ class Type {
kCooperativeMatrixKHR,
kRayQueryKHR,
kHitObjectNV,
kTensorLayoutNV,
kTensorViewNV,
kLast
};
@@ -206,6 +210,8 @@ class Type {
DeclareCastMethod(CooperativeMatrixKHR)
DeclareCastMethod(RayQueryKHR)
DeclareCastMethod(HitObjectNV)
DeclareCastMethod(TensorLayoutNV)
DeclareCastMethod(TensorViewNV)
#undef DeclareCastMethod
protected:
@@ -659,6 +665,53 @@ class CooperativeMatrixKHR : public Type {
const uint32_t use_id_;
};
class TensorLayoutNV : public Type {
public:
TensorLayoutNV(const uint32_t dim, const uint32_t clamp_mode);
TensorLayoutNV(const TensorLayoutNV&) = default;
std::string str() const override;
TensorLayoutNV* AsTensorLayoutNV() override { return this; }
const TensorLayoutNV* AsTensorLayoutNV() const override { return this; }
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
uint32_t dim_id() const { return dim_id_; }
uint32_t clamp_mode_id() const { return clamp_mode_id_; }
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
const uint32_t dim_id_;
const uint32_t clamp_mode_id_;
};
class TensorViewNV : public Type {
public:
TensorViewNV(const uint32_t dim, const uint32_t clamp_mode,
const std::vector<uint32_t>& perm);
TensorViewNV(const TensorViewNV&) = default;
std::string str() const override;
TensorViewNV* AsTensorViewNV() override { return this; }
const TensorViewNV* AsTensorViewNV() const override { return this; }
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
uint32_t dim_id() const { return dim_id_; }
uint32_t has_dimensions_id() const { return has_dimensions_id_; }
const std::vector<uint32_t>& perm() const { return perm_; }
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
const uint32_t dim_id_;
const uint32_t has_dimensions_id_;
std::vector<uint32_t> perm_;
};
#define DefineParameterlessType(type, name) \
class type : public Type { \
public: \

View File

@@ -14,26 +14,7 @@
#include "source/print.h"
#if defined(SPIRV_ANDROID) || defined(SPIRV_LINUX) || defined(SPIRV_MAC) || \
defined(SPIRV_IOS) || defined(SPIRV_TVOS) || defined(SPIRV_FREEBSD) || \
defined(SPIRV_OPENBSD) || defined(SPIRV_EMSCRIPTEN) || \
defined(SPIRV_FUCHSIA) || defined(SPIRV_GNU) || defined(SPIRV_QNX)
namespace spvtools {
clr::reset::operator const char*() { return "\x1b[0m"; }
clr::grey::operator const char*() { return "\x1b[1;30m"; }
clr::red::operator const char*() { return "\x1b[31m"; }
clr::green::operator const char*() { return "\x1b[32m"; }
clr::yellow::operator const char*() { return "\x1b[33m"; }
clr::blue::operator const char*() { return "\x1b[34m"; }
} // namespace spvtools
#elif defined(SPIRV_WINDOWS)
#if defined(SPIRV_WINDOWS)
#include <windows.h>
namespace spvtools {
@@ -111,17 +92,17 @@ clr::blue::operator const char*() {
#else
namespace spvtools {
clr::reset::operator const char*() { return ""; }
clr::reset::operator const char*() { return "\x1b[0m"; }
clr::grey::operator const char*() { return ""; }
clr::grey::operator const char*() { return "\x1b[1;30m"; }
clr::red::operator const char*() { return ""; }
clr::red::operator const char*() { return "\x1b[31m"; }
clr::green::operator const char*() { return ""; }
clr::green::operator const char*() { return "\x1b[32m"; }
clr::yellow::operator const char*() { return ""; }
clr::yellow::operator const char*() { return "\x1b[33m"; }
clr::blue::operator const char*() { return ""; }
clr::blue::operator const char*() { return "\x1b[34m"; }
} // namespace spvtools
#endif

View File

@@ -14,11 +14,13 @@
#include "source/spirv_target_env.h"
#include <array>
#include <cassert>
#include <cctype>
#include <cstring>
#include <string>
#include <utility>
#include "source/latest_version_spirv_header.h"
#include "source/spirv_constant.h"
#include "spirv-tools/libspirv.h"
@@ -77,6 +79,8 @@ const char* spvTargetEnvDescription(spv_target_env env) {
return "SPIR-V 1.6";
case SPV_ENV_VULKAN_1_3:
return "SPIR-V 1.6 (under Vulkan 1.3 semantics)";
case SPV_ENV_VULKAN_1_4:
return "SPIR-V 1.6 (under Vulkan 1.4 semantics)";
case SPV_ENV_MAX:
assert(false && "Invalid target environment value.");
break;
@@ -120,6 +124,7 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) {
return SPV_SPIRV_VERSION_WORD(1, 5);
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_VULKAN_1_4:
return SPV_SPIRV_VERSION_WORD(1, 6);
case SPV_ENV_MAX:
assert(false && "Invalid target environment value.");
@@ -128,32 +133,44 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) {
return SPV_SPIRV_VERSION_WORD(0, 0);
}
static const std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = {
{"vulkan1.1spv1.4", SPV_ENV_VULKAN_1_1_SPIRV_1_4},
{"vulkan1.0", SPV_ENV_VULKAN_1_0},
{"vulkan1.1", SPV_ENV_VULKAN_1_1},
{"vulkan1.2", SPV_ENV_VULKAN_1_2},
{"vulkan1.3", SPV_ENV_VULKAN_1_3},
{"spv1.0", SPV_ENV_UNIVERSAL_1_0},
{"spv1.1", SPV_ENV_UNIVERSAL_1_1},
{"spv1.2", SPV_ENV_UNIVERSAL_1_2},
{"spv1.3", SPV_ENV_UNIVERSAL_1_3},
{"spv1.4", SPV_ENV_UNIVERSAL_1_4},
{"spv1.5", SPV_ENV_UNIVERSAL_1_5},
{"spv1.6", SPV_ENV_UNIVERSAL_1_6},
{"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2},
{"opencl1.2", SPV_ENV_OPENCL_1_2},
{"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0},
{"opencl2.0", SPV_ENV_OPENCL_2_0},
{"opencl2.1embedded", SPV_ENV_OPENCL_EMBEDDED_2_1},
{"opencl2.1", SPV_ENV_OPENCL_2_1},
{"opencl2.2embedded", SPV_ENV_OPENCL_EMBEDDED_2_2},
{"opencl2.2", SPV_ENV_OPENCL_2_2},
{"opengl4.0", SPV_ENV_OPENGL_4_0},
{"opengl4.1", SPV_ENV_OPENGL_4_1},
{"opengl4.2", SPV_ENV_OPENGL_4_2},
{"opengl4.3", SPV_ENV_OPENGL_4_3},
{"opengl4.5", SPV_ENV_OPENGL_4_5},
// When a new SPIR-V version is released, update this table.
static_assert(spv::Version == 0x10600);
constexpr auto ordered_universal_envs = std::array<spv_target_env, 7>{
SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
SPV_ENV_UNIVERSAL_1_6,
};
// When a new SPIR-V version is released, update this table.
static_assert(spv::Version == 0x10600);
inline constexpr std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] =
{
{"vulkan1.1spv1.4", SPV_ENV_VULKAN_1_1_SPIRV_1_4},
{"vulkan1.0", SPV_ENV_VULKAN_1_0},
{"vulkan1.1", SPV_ENV_VULKAN_1_1},
{"vulkan1.2", SPV_ENV_VULKAN_1_2},
{"vulkan1.3", SPV_ENV_VULKAN_1_3},
{"vulkan1.4", SPV_ENV_VULKAN_1_4},
{"spv1.0", SPV_ENV_UNIVERSAL_1_0},
{"spv1.1", SPV_ENV_UNIVERSAL_1_1},
{"spv1.2", SPV_ENV_UNIVERSAL_1_2},
{"spv1.3", SPV_ENV_UNIVERSAL_1_3},
{"spv1.4", SPV_ENV_UNIVERSAL_1_4},
{"spv1.5", SPV_ENV_UNIVERSAL_1_5},
{"spv1.6", SPV_ENV_UNIVERSAL_1_6},
{"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2},
{"opencl1.2", SPV_ENV_OPENCL_1_2},
{"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0},
{"opencl2.0", SPV_ENV_OPENCL_2_0},
{"opencl2.1embedded", SPV_ENV_OPENCL_EMBEDDED_2_1},
{"opencl2.1", SPV_ENV_OPENCL_2_1},
{"opencl2.2embedded", SPV_ENV_OPENCL_EMBEDDED_2_2},
{"opencl2.2", SPV_ENV_OPENCL_2_2},
{"opengl4.0", SPV_ENV_OPENGL_4_0},
{"opengl4.1", SPV_ENV_OPENGL_4_1},
{"opengl4.2", SPV_ENV_OPENGL_4_2},
{"opengl4.3", SPV_ENV_OPENGL_4_3},
{"opengl4.5", SPV_ENV_OPENGL_4_5},
};
bool spvParseTargetEnv(const char* s, spv_target_env* env) {
@@ -172,6 +189,59 @@ bool spvParseTargetEnv(const char* s, spv_target_env* env) {
return false;
}
bool spvReadEnvironmentFromText(const std::vector<char>& text,
spv_target_env* env) {
// Version is expected to match "; Version: 1.X"
// Version string must occur in header, that is, initial lines of comments
// Once a non-comment line occurs, the header has ended
for (std::size_t i = 0; i < text.size(); ++i) {
char c = text[i];
if (c == ';') {
// Try to match against the expected version string
constexpr const char* kVersionPrefix = "; Version: 1.";
constexpr const auto kPrefixLength = 13;
// 'minor_digit_pos' is the expected position of the version digit.
const auto minor_digit_pos = i + kPrefixLength;
if (minor_digit_pos >= text.size()) return false;
// Match the prefix.
auto j = 1;
for (; j < kPrefixLength; ++j) {
if (kVersionPrefix[j] != text[i + j]) break;
}
// j will match the prefix length if all characters before matched
if (j == kPrefixLength) {
// This expects only one digit in the minor number.
static_assert(((spv::Version >> 8) & 0xff) < 10);
char minor = text[minor_digit_pos];
char next_char =
minor_digit_pos + 1 < text.size() ? text[minor_digit_pos + 1] : 0;
if (std::isdigit(minor) && !std::isdigit(next_char)) {
const auto index = minor - '0';
assert(index >= 0);
if (static_cast<size_t>(index) < ordered_universal_envs.size()) {
*env = ordered_universal_envs[index];
return true;
}
}
}
// If no match, determine whether the header has ended (in which case,
// assumption has failed.)
// Skip until the next line.
i += j;
for (; i < text.size(); ++i) {
if (text[i] == '\n') break;
}
} else if (!std::isspace(c)) {
// Allow blanks, but end the search if we find something else.
break;
}
}
return false;
}
#define VULKAN_VER(MAJOR, MINOR) ((MAJOR << 22) | (MINOR << 12))
#define SPIRV_VER(MAJOR, MINOR) ((MAJOR << 16) | (MINOR << 8))
@@ -188,7 +258,8 @@ static const VulkanEnv ordered_vulkan_envs[] = {
{SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)},
{SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)},
{SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)},
{SPV_ENV_VULKAN_1_3, VULKAN_VER(1, 3), SPIRV_VER(1, 6)}};
{SPV_ENV_VULKAN_1_3, VULKAN_VER(1, 3), SPIRV_VER(1, 6)},
{SPV_ENV_VULKAN_1_4, VULKAN_VER(1, 4), SPIRV_VER(1, 6)}};
bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver,
spv_target_env* env) {
@@ -229,6 +300,7 @@ bool spvIsVulkanEnv(spv_target_env env) {
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_VULKAN_1_4:
return true;
case SPV_ENV_WEBGPU_0:
assert(false && "Deprecated target environment value.");
@@ -259,6 +331,7 @@ bool spvIsOpenCLEnv(spv_target_env env) {
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_VULKAN_1_4:
return false;
case SPV_ENV_OPENCL_1_2:
case SPV_ENV_OPENCL_EMBEDDED_1_2:
@@ -301,6 +374,7 @@ bool spvIsOpenGLEnv(spv_target_env env) {
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_VULKAN_1_4:
return false;
case SPV_ENV_OPENGL_4_0:
case SPV_ENV_OPENGL_4_1:
@@ -340,6 +414,7 @@ bool spvIsValidEnv(spv_target_env env) {
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_VULKAN_1_4:
case SPV_ENV_OPENGL_4_0:
case SPV_ENV_OPENGL_4_1:
case SPV_ENV_OPENGL_4_2:
@@ -376,7 +451,8 @@ std::string spvLogStringForEnv(spv_target_env env) {
case SPV_ENV_VULKAN_1_1:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_VULKAN_1_3: {
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_VULKAN_1_4: {
return "Vulkan";
}
case SPV_ENV_UNIVERSAL_1_0:

View File

@@ -16,6 +16,8 @@
#define SOURCE_SPIRV_TARGET_ENV_H_
#include <string>
#include <utility>
#include <vector>
#include "spirv-tools/libspirv.h"
@@ -46,4 +48,9 @@ std::string spvLogStringForEnv(spv_target_env env);
// occur to satisfy this limit.
std::string spvTargetEnvList(const int pad, const int wrap);
// Reads the target environment from the header comments of disassembly. Returns
// true if valid name found, false otherwise.
bool spvReadEnvironmentFromText(const std::vector<char>& text,
spv_target_env* env);
#endif // SOURCE_SPIRV_TARGET_ENV_H_

View File

@@ -43,6 +43,7 @@ spv_context spvContextCreate(spv_target_env env) {
case SPV_ENV_VULKAN_1_2:
case SPV_ENV_UNIVERSAL_1_6:
case SPV_ENV_VULKAN_1_3:
case SPV_ENV_VULKAN_1_4:
break;
default:
return nullptr;

View File

@@ -201,7 +201,7 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar,
}
// Optional literal operands can fail to parse. In that case use
// SPV_FAILED_MATCH to avoid emitting a diagostic. Use the following
// SPV_FAILED_MATCH to avoid emitting a diagnostic. Use the following
// for those situations.
spv_result_t error_code_for_literals =
spvOperandIsOptional(type) ? SPV_FAILED_MATCH : SPV_ERROR_INVALID_TEXT;
@@ -414,7 +414,9 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar,
case SPV_OPERAND_TYPE_SELECTION_CONTROL:
case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: {
case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS:
case SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS:
case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE: {
uint32_t value;
if (auto error = grammar.parseMaskOperand(type, textValue, &value)) {
return context->diagnostic(error)

View File

@@ -20,6 +20,7 @@
#include <map>
#include <set>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
@@ -278,7 +279,7 @@ class Function {
Construct& FindConstructForEntryBlock(const BasicBlock* entry_block,
ConstructType t);
/// The result id of the OpLabel that defined this block
/// The result id of OpFunction
uint32_t id_;
/// The type of the function

View File

@@ -366,6 +366,7 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
if (auto error = RayTracingPass(*vstate, &instruction)) return error;
if (auto error = RayReorderNVPass(*vstate, &instruction)) return error;
if (auto error = MeshShadingPass(*vstate, &instruction)) return error;
if (auto error = TensorLayoutPass(*vstate, &instruction)) return error;
}
// Validate the preconditions involving adjacent instructions. e.g.

View File

@@ -226,6 +226,9 @@ spv_result_t MeshShadingPass(ValidationState_t& _, const Instruction* inst);
/// Calculates the reachability of basic blocks.
void ReachabilityPass(ValidationState_t& _);
/// Validates tensor layout and view instructions.
spv_result_t TensorLayoutPass(ValidationState_t& _, const Instruction* inst);
/// Validates execution limitations.
///
/// Verifies execution models are allowed for all functionality they contain.

View File

@@ -62,7 +62,7 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) {
<< operand_index;
}
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, type_id, result_type);
_.CooperativeMatrixShapesMatch(inst, result_type, type_id, false);
if (ret != SPV_SUCCESS) return ret;
} else if (_.GetOperandTypeId(inst, operand_index) != result_type)
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -96,7 +96,7 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) {
<< operand_index;
}
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, type_id, result_type);
_.CooperativeMatrixShapesMatch(inst, result_type, type_id, false);
if (ret != SPV_SUCCESS) return ret;
} else if (_.GetOperandTypeId(inst, operand_index) != result_type)
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -142,7 +142,7 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) {
<< operand_index;
}
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, type_id, result_type);
_.CooperativeMatrixShapesMatch(inst, result_type, type_id, false);
if (ret != SPV_SUCCESS) return ret;
}
@@ -672,6 +672,128 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) {
break;
}
case spv::Op::OpCooperativeMatrixReduceNV: {
if (!_.IsCooperativeMatrixKHRType(result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Result Type must be a cooperative matrix type: "
<< spvOpcodeString(opcode);
}
const auto result_comp_type_id =
_.FindDef(result_type)->GetOperandAs<uint32_t>(1);
const auto matrix_id = inst->GetOperandAs<uint32_t>(2);
const auto matrix = _.FindDef(matrix_id);
const auto matrix_type_id = matrix->type_id();
if (!_.IsCooperativeMatrixKHRType(matrix_type_id)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Matrix must have a cooperative matrix type: "
<< spvOpcodeString(opcode);
}
const auto matrix_type = _.FindDef(matrix_type_id);
const auto matrix_comp_type_id = matrix_type->GetOperandAs<uint32_t>(1);
if (matrix_comp_type_id != result_comp_type_id) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Result Type and Matrix type must have the same component "
"type: "
<< spvOpcodeString(opcode);
}
if (_.FindDef(result_type)->GetOperandAs<uint32_t>(2) !=
matrix_type->GetOperandAs<uint32_t>(2)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Result Type and Matrix type must have the same scope: "
<< spvOpcodeString(opcode);
}
if (!_.IsCooperativeMatrixAccType(result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Result Type must have UseAccumulator: "
<< spvOpcodeString(opcode);
}
if (!_.IsCooperativeMatrixAccType(matrix_type_id)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Matrix type must have UseAccumulator: "
<< spvOpcodeString(opcode);
}
const auto reduce_value = inst->GetOperandAs<uint32_t>(3);
if ((reduce_value &
uint32_t(
spv::CooperativeMatrixReduceMask::CooperativeMatrixReduce2x2)) &&
(reduce_value & uint32_t(spv::CooperativeMatrixReduceMask::Row |
spv::CooperativeMatrixReduceMask::Column))) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Reduce 2x2 must not be used with Row/Column: "
<< spvOpcodeString(opcode);
}
std::tuple<bool, bool, uint32_t> result_rows, result_cols, matrix_rows,
matrix_cols;
result_rows =
_.EvalInt32IfConst(_.FindDef(result_type)->GetOperandAs<uint32_t>(3));
result_cols =
_.EvalInt32IfConst(_.FindDef(result_type)->GetOperandAs<uint32_t>(4));
matrix_rows = _.EvalInt32IfConst(matrix_type->GetOperandAs<uint32_t>(3));
matrix_cols = _.EvalInt32IfConst(matrix_type->GetOperandAs<uint32_t>(4));
if (reduce_value &
uint32_t(
spv::CooperativeMatrixReduceMask::CooperativeMatrixReduce2x2)) {
if (std::get<1>(result_rows) && std::get<1>(result_cols) &&
std::get<1>(matrix_rows) && std::get<1>(matrix_cols) &&
(std::get<2>(result_rows) != std::get<2>(matrix_rows) / 2 ||
std::get<2>(result_cols) != std::get<2>(matrix_cols) / 2)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "For Reduce2x2, result rows/cols must be half of matrix "
"rows/cols: "
<< spvOpcodeString(opcode);
}
}
if (reduce_value == uint32_t(spv::CooperativeMatrixReduceMask::Row)) {
if (std::get<1>(result_rows) && std::get<1>(matrix_rows) &&
std::get<2>(result_rows) != std::get<2>(matrix_rows)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "For ReduceRow, result rows must match matrix rows: "
<< spvOpcodeString(opcode);
}
}
if (reduce_value == uint32_t(spv::CooperativeMatrixReduceMask::Column)) {
if (std::get<1>(result_cols) && std::get<1>(matrix_cols) &&
std::get<2>(result_cols) != std::get<2>(matrix_cols)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "For ReduceColumn, result cols must match matrix cols: "
<< spvOpcodeString(opcode);
}
}
const auto combine_func_id = inst->GetOperandAs<uint32_t>(4);
const auto combine_func = _.FindDef(combine_func_id);
if (!combine_func || combine_func->opcode() != spv::Op::OpFunction) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "CombineFunc must be a function: " << spvOpcodeString(opcode);
}
const auto function_type_id = combine_func->GetOperandAs<uint32_t>(3);
const auto function_type = _.FindDef(function_type_id);
if (function_type->operands().size() != 4) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "CombineFunc must have two parameters: "
<< spvOpcodeString(opcode);
}
for (uint32_t i = 0; i < 3; ++i) {
// checks return type and two params
const auto param_type_id = function_type->GetOperandAs<uint32_t>(i + 1);
if (param_type_id != matrix_comp_type_id) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "CombineFunc return type and parameters must match matrix "
"component type: "
<< spvOpcodeString(opcode);
}
}
break;
}
default:
break;
}

View File

@@ -49,7 +49,7 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
if (_.IsCooperativeMatrixType(result_type) ||
_.IsCooperativeMatrixType(input_type)) {
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, result_type, input_type);
_.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
if (ret != SPV_SUCCESS) return ret;
} else {
if (_.GetDimension(result_type) != _.GetDimension(input_type))
@@ -79,7 +79,7 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
if (_.IsCooperativeMatrixType(result_type) ||
_.IsCooperativeMatrixType(input_type)) {
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, result_type, input_type);
_.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
if (ret != SPV_SUCCESS) return ret;
} else {
if (_.GetDimension(result_type) != _.GetDimension(input_type))
@@ -111,7 +111,7 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
if (_.IsCooperativeMatrixType(result_type) ||
_.IsCooperativeMatrixType(input_type)) {
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, result_type, input_type);
_.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
if (ret != SPV_SUCCESS) return ret;
} else {
if (_.GetDimension(result_type) != _.GetDimension(input_type))
@@ -142,7 +142,7 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
if (_.IsCooperativeMatrixType(result_type) ||
_.IsCooperativeMatrixType(input_type)) {
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, result_type, input_type);
_.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
if (ret != SPV_SUCCESS) return ret;
} else {
if (_.GetDimension(result_type) != _.GetDimension(input_type))
@@ -177,7 +177,7 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
if (_.IsCooperativeMatrixType(result_type) ||
_.IsCooperativeMatrixType(input_type)) {
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, result_type, input_type);
_.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
if (ret != SPV_SUCCESS) return ret;
} else {
if (_.GetDimension(result_type) != _.GetDimension(input_type))
@@ -213,7 +213,7 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
if (_.IsCooperativeMatrixType(result_type) ||
_.IsCooperativeMatrixType(input_type)) {
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, result_type, input_type);
_.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
if (ret != SPV_SUCCESS) return ret;
} else {
if (_.GetDimension(result_type) != _.GetDimension(input_type))
@@ -497,8 +497,8 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
<< "matrix: " << spvOpcodeString(opcode);
if (result_is_coopmat) {
spv_result_t ret =
_.CooperativeMatrixShapesMatch(inst, result_type, input_type);
spv_result_t ret = _.CooperativeMatrixShapesMatch(inst, result_type,
input_type, false);
if (ret != SPV_SUCCESS) return ret;
}
@@ -568,6 +568,43 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
break;
}
case spv::Op::OpCooperativeMatrixConvertNV:
case spv::Op::OpCooperativeMatrixTransposeNV: {
if (!_.IsCooperativeMatrixType(result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected cooperative matrix Result Type: "
<< spvOpcodeString(opcode);
}
const uint32_t input_type = _.GetOperandTypeId(inst, 2);
if (!_.IsCooperativeMatrixType(input_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected cooperative matrix type for Matrix input: "
<< spvOpcodeString(opcode);
}
bool swap_row_col = (opcode == spv::Op::OpCooperativeMatrixTransposeNV);
if (auto error = _.CooperativeMatrixShapesMatch(
inst, result_type, input_type, true, swap_row_col))
return error;
if (opcode == spv::Op::OpCooperativeMatrixConvertNV) {
if (_.FindDef(result_type)->GetOperandAs<uint32_t>(1) !=
_.FindDef(input_type)->GetOperandAs<uint32_t>(1)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Result Type and Matrix component types mismatch: "
<< spvOpcodeString(opcode);
}
}
if (opcode == spv::Op::OpCooperativeMatrixTransposeNV) {
if (!_.IsCooperativeMatrixBType(result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Result Type must have UseB: " << spvOpcodeString(opcode);
}
}
break;
}
default:
break;
}

View File

@@ -169,7 +169,7 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp,
case spv::Op::OpTypeSampler:
case spv::Op::OpTypeImage:
if (vstate.HasCapability(spv::Capability::BindlessTextureNV))
return baseAlignment = vstate.samplerimage_variable_address_mode() / 8;
return vstate.samplerimage_variable_address_mode() / 8;
assert(0);
return 0;
case spv::Op::OpTypeInt:

View File

@@ -3090,7 +3090,6 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
// validation.
case NonSemanticShaderDebugInfo100DebugInfoNone:
case NonSemanticShaderDebugInfo100DebugCompilationUnit:
case NonSemanticShaderDebugInfo100DebugTypeBasic:
case NonSemanticShaderDebugInfo100DebugTypePointer:
case NonSemanticShaderDebugInfo100DebugTypeQualifier:
case NonSemanticShaderDebugInfo100DebugTypeArray:
@@ -3116,7 +3115,6 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
case NonSemanticShaderDebugInfo100DebugInlinedAt:
case NonSemanticShaderDebugInfo100DebugLocalVariable:
case NonSemanticShaderDebugInfo100DebugInlinedVariable:
case NonSemanticShaderDebugInfo100DebugDeclare:
case NonSemanticShaderDebugInfo100DebugValue:
case NonSemanticShaderDebugInfo100DebugOperation:
case NonSemanticShaderDebugInfo100DebugExpression:
@@ -3125,6 +3123,24 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
case NonSemanticShaderDebugInfo100DebugImportedEntity:
case NonSemanticShaderDebugInfo100DebugSource:
break;
// These checks are for operands that are differnet in
// ShaderDebugInfo100
case NonSemanticShaderDebugInfo100DebugTypeBasic: {
CHECK_CONST_UINT_OPERAND("Flags", 8);
break;
}
case NonSemanticShaderDebugInfo100DebugDeclare: {
for (uint32_t word_index = 8; word_index < num_words; ++word_index) {
auto index_inst = _.FindDef(inst->word(word_index));
auto type_id = index_inst != nullptr ? index_inst->type_id() : 0;
if (type_id == 0 || !IsIntScalar(_, type_id, false, false))
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< ext_inst_name() << ": "
<< "expected index must be scalar integer";
}
break;
}
case NonSemanticShaderDebugInfo100DebugTypeMatrix: {
CHECK_DEBUG_OPERAND("Vector Type", CommonDebugInfoDebugTypeVector, 5);
@@ -3146,14 +3162,84 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
}
break;
}
// TODO: Add validation rules for remaining cases as well.
case NonSemanticShaderDebugInfo100DebugFunctionDefinition:
case NonSemanticShaderDebugInfo100DebugSourceContinued:
case NonSemanticShaderDebugInfo100DebugLine:
case NonSemanticShaderDebugInfo100DebugFunctionDefinition: {
CHECK_DEBUG_OPERAND("Function", CommonDebugInfoDebugFunction, 5);
CHECK_OPERAND("Definition", spv::Op::OpFunction, 6);
const auto* current_function = inst->function();
if (current_function->first_block()->id() != inst->block()->id()) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< ext_inst_name()
<< ": must be in the entry basic block of the function";
}
const uint32_t definition_id = inst->word(6);
if (definition_id != current_function->id()) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< ext_inst_name()
<< ": operand Definition must point to the OpFunction it is "
"inside";
}
break;
}
case NonSemanticShaderDebugInfo100DebugLine: {
CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 5);
CHECK_CONST_UINT_OPERAND("Line Start", 6);
CHECK_CONST_UINT_OPERAND("Line End", 7);
CHECK_CONST_UINT_OPERAND("Column Start", 8);
CHECK_CONST_UINT_OPERAND("Column End", 9);
// above already validates if 32-bit and non-spec constant
// but want to use EvalInt32IfConst to be consistent with other Eval
// locations
bool is_int32 = false, is_const_int32 = false;
uint32_t line_start = 0;
uint32_t line_end = 0;
uint32_t column_start = 0;
uint32_t column_end = 0;
std::tie(is_int32, is_const_int32, line_start) =
_.EvalInt32IfConst(inst->word(6));
std::tie(is_int32, is_const_int32, line_end) =
_.EvalInt32IfConst(inst->word(7));
std::tie(is_int32, is_const_int32, column_start) =
_.EvalInt32IfConst(inst->word(8));
std::tie(is_int32, is_const_int32, column_end) =
_.EvalInt32IfConst(inst->word(9));
if (line_end < line_start) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< ext_inst_name() << ": operand Line End (" << line_end
<< ") is less than Line Start (" << line_start << ")";
} else if (line_start == line_end && column_end < column_start) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< ext_inst_name() << ": operand Column End (" << column_end
<< ") is less than Column Start (" << column_start
<< ") when Line Start equals Line End";
}
break;
}
case NonSemanticShaderDebugInfo100DebugSourceContinued: {
CHECK_OPERAND("Text", spv::Op::OpString, 5);
break;
}
case NonSemanticShaderDebugInfo100DebugBuildIdentifier: {
CHECK_OPERAND("Identifier", spv::Op::OpString, 5);
CHECK_CONST_UINT_OPERAND("Flags", 6);
break;
}
case NonSemanticShaderDebugInfo100DebugStoragePath: {
CHECK_OPERAND("Path", spv::Op::OpString, 5);
break;
}
case NonSemanticShaderDebugInfo100DebugEntryPoint: {
CHECK_DEBUG_OPERAND("Entry Point", CommonDebugInfoDebugFunction, 5);
CHECK_DEBUG_OPERAND("Compilation Unit",
CommonDebugInfoDebugCompilationUnit, 6);
CHECK_OPERAND("Compiler Signature", spv::Op::OpString, 7);
CHECK_OPERAND("Command-line Arguments", spv::Op::OpString, 8);
break;
}
// Has no additional checks
case NonSemanticShaderDebugInfo100DebugNoLine:
case NonSemanticShaderDebugInfo100DebugBuildIdentifier:
case NonSemanticShaderDebugInfo100DebugStoragePath:
case NonSemanticShaderDebugInfo100DebugEntryPoint:
break;
case NonSemanticShaderDebugInfo100InstructionsMax:
assert(0);
@@ -3455,9 +3541,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
}
case CommonDebugInfoDebugFunction: {
CHECK_OPERAND("Name", spv::Op::OpString, 5);
auto validate_type = ValidateOperandDebugType(_, "Type", inst, 6,
ext_inst_name, false);
if (validate_type != SPV_SUCCESS) return validate_type;
CHECK_DEBUG_OPERAND("Type", CommonDebugInfoDebugTypeFunction, 6);
CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
CHECK_CONST_UINT_OPERAND("Line", 8);
CHECK_CONST_UINT_OPERAND("Column", 9);
@@ -3492,9 +3576,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
}
case CommonDebugInfoDebugFunctionDeclaration: {
CHECK_OPERAND("Name", spv::Op::OpString, 5);
auto validate_type = ValidateOperandDebugType(_, "Type", inst, 6,
ext_inst_name, false);
if (validate_type != SPV_SUCCESS) return validate_type;
CHECK_DEBUG_OPERAND("Type", CommonDebugInfoDebugTypeFunction, 6);
CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
CHECK_CONST_UINT_OPERAND("Line", 8);
CHECK_CONST_UINT_OPERAND("Column", 9);
@@ -3556,18 +3638,6 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
}
CHECK_DEBUG_OPERAND("Expression", CommonDebugInfoDebugExpression, 7);
if (vulkanDebugInfo) {
for (uint32_t word_index = 8; word_index < num_words;
++word_index) {
auto index_inst = _.FindDef(inst->word(word_index));
auto type_id = index_inst != nullptr ? index_inst->type_id() : 0;
if (type_id == 0 || !IsIntScalar(_, type_id, false, false))
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< ext_inst_name() << ": "
<< "expected index must be scalar integer";
}
}
break;
}
case CommonDebugInfoDebugExpression: {

View File

@@ -86,7 +86,10 @@ spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) {
spv::Op::OpGetKernelPreferredWorkGroupSizeMultiple,
spv::Op::OpGetKernelLocalSizeForSubgroupCount,
spv::Op::OpGetKernelMaxNumSubgroups,
spv::Op::OpName};
spv::Op::OpName,
spv::Op::OpCooperativeMatrixPerElementOpNV,
spv::Op::OpCooperativeMatrixReduceNV,
spv::Op::OpCooperativeMatrixLoadTensorNV};
for (auto& pair : inst->uses()) {
const auto* use = pair.first;
if (std::find(acceptable.begin(), acceptable.end(), use->opcode()) ==
@@ -280,7 +283,7 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _,
function_type->GetOperandAs<uint32_t>(param_index);
const auto parameter_type = _.FindDef(parameter_type_id);
if (!parameter_type || argument_type->id() != parameter_type->id()) {
if (!_.options()->before_hlsl_legalization ||
if (!parameter_type || !_.options()->before_hlsl_legalization ||
!DoPointeesLogicallyMatch(argument_type, parameter_type, _)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpFunctionCall Argument <id> " << _.getIdName(argument_id)
@@ -341,6 +344,80 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _,
return SPV_SUCCESS;
}
spv_result_t ValidateCooperativeMatrixPerElementOp(ValidationState_t& _,
const Instruction* inst) {
const auto function_id = inst->GetOperandAs<uint32_t>(3);
const auto function = _.FindDef(function_id);
if (!function || spv::Op::OpFunction != function->opcode()) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixPerElementOpNV Function <id> "
<< _.getIdName(function_id) << " is not a function.";
}
const auto matrix_id = inst->GetOperandAs<uint32_t>(2);
const auto matrix = _.FindDef(matrix_id);
const auto matrix_type_id = matrix->type_id();
if (!_.IsCooperativeMatrixKHRType(matrix_type_id)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixPerElementOpNV Matrix <id> "
<< _.getIdName(matrix_id) << " is not a cooperative matrix.";
}
const auto result_type_id = inst->GetOperandAs<uint32_t>(0);
if (matrix_type_id != result_type_id) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixPerElementOpNV Result Type <id> "
<< _.getIdName(result_type_id) << " must match matrix type <id> "
<< _.getIdName(matrix_type_id) << ".";
}
const auto matrix_comp_type_id =
_.FindDef(matrix_type_id)->GetOperandAs<uint32_t>(1);
const auto function_type_id = function->GetOperandAs<uint32_t>(3);
const auto function_type = _.FindDef(function_type_id);
auto return_type_id = function_type->GetOperandAs<uint32_t>(1);
if (return_type_id != matrix_comp_type_id) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixPerElementOpNV function return type <id> "
<< _.getIdName(return_type_id)
<< " must match matrix component type <id> "
<< _.getIdName(matrix_comp_type_id) << ".";
}
if (function_type->operands().size() < 5) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixPerElementOpNV function type <id> "
<< _.getIdName(function_type_id)
<< " must have a least three parameters.";
}
const auto param0_id = function_type->GetOperandAs<uint32_t>(2);
const auto param1_id = function_type->GetOperandAs<uint32_t>(3);
const auto param2_id = function_type->GetOperandAs<uint32_t>(4);
if (!_.IsIntScalarType(param0_id) || _.GetBitWidth(param0_id) != 32) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixPerElementOpNV function type first parameter "
"type <id> "
<< _.getIdName(param0_id) << " must be a 32-bit integer.";
}
if (!_.IsIntScalarType(param1_id) || _.GetBitWidth(param1_id) != 32) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixPerElementOpNV function type second "
"parameter type <id> "
<< _.getIdName(param1_id) << " must be a 32-bit integer.";
}
if (param2_id != matrix_comp_type_id) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixPerElementOpNV function type third parameter "
"type <id> "
<< _.getIdName(param2_id) << " must match matrix component type.";
}
return SPV_SUCCESS;
}
} // namespace
spv_result_t FunctionPass(ValidationState_t& _, const Instruction* inst) {
@@ -354,6 +431,10 @@ spv_result_t FunctionPass(ValidationState_t& _, const Instruction* inst) {
case spv::Op::OpFunctionCall:
if (auto error = ValidateFunctionCall(_, inst)) return error;
break;
case spv::Op::OpCooperativeMatrixPerElementOpNV:
if (auto error = ValidateCooperativeMatrixPerElementOp(_, inst))
return error;
break;
default:
break;
}

View File

@@ -163,6 +163,7 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) {
!spvOpcodeGeneratesType(opcode) && !spvOpcodeIsDebug(opcode) &&
!inst->IsDebugInfo() && !inst->IsNonSemantic() &&
!spvOpcodeIsDecoration(opcode) && opcode != spv::Op::OpFunction &&
opcode != spv::Op::OpSizeOf &&
opcode != spv::Op::OpCooperativeMatrixLengthNV &&
opcode != spv::Op::OpCooperativeMatrixLengthKHR &&
!spvOpcodeGeneratesUntypedPointer(opcode) &&
@@ -185,6 +186,7 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) {
opcode != spv::Op::OpSelectionMerge &&
opcode != spv::Op::OpLoopMerge &&
opcode != spv::Op::OpFunction &&
opcode != spv::Op::OpSizeOf &&
opcode != spv::Op::OpCooperativeMatrixLengthNV &&
opcode != spv::Op::OpCooperativeMatrixLengthKHR &&
!spvOpcodeGeneratesUntypedPointer(opcode) &&

View File

@@ -994,6 +994,7 @@ bool IsAllowedSampledImageOperand(spv::Op opcode, ValidationState_t& _) {
case spv::Op::OpImageBlockMatchWindowSSDQCOM:
case spv::Op::OpImageBlockMatchGatherSADQCOM:
case spv::Op::OpImageBlockMatchGatherSSDQCOM:
case spv::Op::OpImageSampleFootprintNV:
return true;
case spv::Op::OpStore:
if (_.HasCapability(spv::Capability::BindlessTextureNV)) return true;

View File

@@ -475,6 +475,12 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) {
const uint32_t entry_point = inst->word(1);
_.RegisterExecutionModeForEntryPoint(entry_point,
spv::ExecutionMode(inst->word(2)));
if (inst->GetOperandAs<spv::ExecutionMode>(1) ==
spv::ExecutionMode::LocalSize ||
inst->GetOperandAs<spv::ExecutionMode>(1) ==
spv::ExecutionMode::LocalSizeId) {
_.RegisterEntryPointLocalSize(entry_point, inst);
}
} else if (opcode == spv::Op::OpVariable) {
const auto storage_class = inst->GetOperandAs<spv::StorageClass>(2);
if (auto error = LimitCheckNumVars(_, inst->id(), storage_class)) {

View File

@@ -75,8 +75,8 @@ spv_result_t ModuleScopedInstructions(ValidationState_t& _,
if (local_debug_info) {
if (_.in_function_body() == false) {
// DebugScope, DebugNoScope, DebugDeclare, DebugValue must
// appear in a function body.
// TODO - Print the actual name of the instruction as this list is
// not complete (see ext_inst_name in ValidateExtInst() for example)
return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
<< "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
<< "of debug info extension must appear in a function "

View File

@@ -233,6 +233,7 @@ std::pair<spv::StorageClass, spv::StorageClass> GetStorageClass(
spv::StorageClass src_sc = spv::StorageClass::Max;
switch (inst->opcode()) {
case spv::Op::OpCooperativeMatrixLoadNV:
case spv::Op::OpCooperativeMatrixLoadTensorNV:
case spv::Op::OpCooperativeMatrixLoadKHR:
case spv::Op::OpLoad: {
auto load_pointer = _.FindDef(inst->GetOperandAs<uint32_t>(2));
@@ -241,6 +242,7 @@ std::pair<spv::StorageClass, spv::StorageClass> GetStorageClass(
break;
}
case spv::Op::OpCooperativeMatrixStoreNV:
case spv::Op::OpCooperativeMatrixStoreTensorNV:
case spv::Op::OpCooperativeMatrixStoreKHR:
case spv::Op::OpStore: {
auto store_pointer = _.FindDef(inst->GetOperandAs<uint32_t>(0));
@@ -330,6 +332,7 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
if (mask & uint32_t(spv::MemoryAccessMask::MakePointerAvailableKHR)) {
if (inst->opcode() == spv::Op::OpLoad ||
inst->opcode() == spv::Op::OpCooperativeMatrixLoadNV ||
inst->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV ||
inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "MakePointerAvailableKHR cannot be used with OpLoad.";
@@ -350,7 +353,8 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
if (mask & uint32_t(spv::MemoryAccessMask::MakePointerVisibleKHR)) {
if (inst->opcode() == spv::Op::OpStore ||
inst->opcode() == spv::Op::OpCooperativeMatrixStoreNV ||
inst->opcode() == spv::Op::OpCooperativeMatrixStoreKHR) {
inst->opcode() == spv::Op::OpCooperativeMatrixStoreKHR ||
inst->opcode() == spv::Op::OpCooperativeMatrixStoreTensorNV) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "MakePointerVisibleKHR cannot be used with OpStore.";
}
@@ -2111,14 +2115,16 @@ spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _,
const auto storage_class =
pointer_type->GetOperandAs<spv::StorageClass>(storage_class_index);
if (storage_class != spv::StorageClass::Workgroup &&
storage_class != spv::StorageClass::StorageBuffer &&
storage_class != spv::StorageClass::PhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< _.VkErrorID(8973) << opname
<< " storage class for pointer type <id> "
<< _.getIdName(pointer_type_id)
<< " is not Workgroup, StorageBuffer, or PhysicalStorageBuffer.";
if (spvIsVulkanEnv(_.context()->target_env)) {
if (storage_class != spv::StorageClass::Workgroup &&
storage_class != spv::StorageClass::StorageBuffer &&
storage_class != spv::StorageClass::PhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< _.VkErrorID(8973) << opname
<< " storage class for pointer type <id> "
<< _.getIdName(pointer_type_id)
<< " is not Workgroup, StorageBuffer, or PhysicalStorageBuffer.";
}
}
if (!untyped) {
@@ -2176,6 +2182,222 @@ spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _,
return SPV_SUCCESS;
}
// Returns the number of instruction words taken up by a tensor addressing
// operands argument and its implied operands.
int TensorAddressingOperandsNumWords(spv::TensorAddressingOperandsMask mask) {
int result = 1; // Count the mask
if ((mask & spv::TensorAddressingOperandsMask::TensorView) !=
spv::TensorAddressingOperandsMask::MaskNone)
++result;
if ((mask & spv::TensorAddressingOperandsMask::DecodeFunc) !=
spv::TensorAddressingOperandsMask::MaskNone)
++result;
return result;
}
spv_result_t ValidateCooperativeMatrixLoadStoreTensorNV(
ValidationState_t& _, const Instruction* inst) {
uint32_t type_id;
const char* opname;
if (inst->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) {
type_id = inst->type_id();
opname = "spv::Op::OpCooperativeMatrixLoadTensorNV";
} else {
// get Object operand's type
type_id = _.FindDef(inst->GetOperandAs<uint32_t>(1))->type_id();
opname = "spv::Op::OpCooperativeMatrixStoreTensorNV";
}
auto matrix_type = _.FindDef(type_id);
if (matrix_type->opcode() != spv::Op::OpTypeCooperativeMatrixKHR) {
if (inst->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "spv::Op::OpCooperativeMatrixLoadTensorNV Result Type <id> "
<< _.getIdName(type_id) << " is not a cooperative matrix type.";
} else {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "spv::Op::OpCooperativeMatrixStoreTensorNV Object type <id> "
<< _.getIdName(type_id) << " is not a cooperative matrix type.";
}
}
const auto pointer_index =
(inst->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) ? 2u : 0u;
const auto pointer_id = inst->GetOperandAs<uint32_t>(pointer_index);
const auto pointer = _.FindDef(pointer_id);
if (!pointer ||
((_.addressing_model() == spv::AddressingModel::Logical) &&
((!_.features().variable_pointers &&
!spvOpcodeReturnsLogicalPointer(pointer->opcode())) ||
(_.features().variable_pointers &&
!spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " Pointer <id> " << _.getIdName(pointer_id)
<< " is not a logical pointer.";
}
const auto pointer_type_id = pointer->type_id();
const auto pointer_type = _.FindDef(pointer_type_id);
if (!pointer_type || pointer_type->opcode() != spv::Op::OpTypePointer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " type for pointer <id> " << _.getIdName(pointer_id)
<< " is not a pointer type.";
}
const auto storage_class_index = 1u;
const auto storage_class =
pointer_type->GetOperandAs<spv::StorageClass>(storage_class_index);
if (storage_class != spv::StorageClass::Workgroup &&
storage_class != spv::StorageClass::StorageBuffer &&
storage_class != spv::StorageClass::PhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< _.VkErrorID(8973) << opname
<< " storage class for pointer type <id> "
<< _.getIdName(pointer_type_id)
<< " is not Workgroup, StorageBuffer, or PhysicalStorageBuffer.";
}
if (inst->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) {
const auto object_index = 3;
const auto object_id = inst->GetOperandAs<uint32_t>(object_index);
const auto object = _.FindDef(object_id);
if (!object || object->type_id() != type_id) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " Object <id> " << _.getIdName(object_id)
<< " type does not match Result Type.";
}
}
const auto tensor_layout_index =
(inst->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) ? 4u : 2u;
const auto tensor_layout_id =
inst->GetOperandAs<uint32_t>(tensor_layout_index);
const auto tensor_layout = _.FindDef(tensor_layout_id);
if (!tensor_layout || _.FindDef(tensor_layout->type_id())->opcode() !=
spv::Op::OpTypeTensorLayoutNV) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " TensorLayout <id> " << _.getIdName(tensor_layout_id)
<< " does not have a tensor layout type.";
}
const auto memory_access_index =
(inst->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) ? 5u : 3u;
if (inst->operands().size() > memory_access_index) {
if (auto error = CheckMemoryAccess(_, inst, memory_access_index))
return error;
}
const auto memory_access_mask =
inst->GetOperandAs<uint32_t>(memory_access_index);
const auto tensor_operands_index =
memory_access_index + MemoryAccessNumWords(memory_access_mask);
const auto tensor_operands =
inst->GetOperandAs<spv::TensorAddressingOperandsMask>(
tensor_operands_index);
if (inst->operands().size() <
tensor_operands_index +
TensorAddressingOperandsNumWords(tensor_operands)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " not enough tensor addressing operands.";
}
uint32_t tensor_operand_index = tensor_operands_index + 1;
if ((tensor_operands & spv::TensorAddressingOperandsMask::TensorView) !=
spv::TensorAddressingOperandsMask::MaskNone) {
const auto tensor_view_id =
inst->GetOperandAs<uint32_t>(tensor_operand_index);
const auto tensor_view = _.FindDef(tensor_view_id);
if (!tensor_view || _.FindDef(tensor_view->type_id())->opcode() !=
spv::Op::OpTypeTensorViewNV) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " TensorView <id> " << _.getIdName(tensor_view_id)
<< " does not have a tensor view type.";
}
tensor_operand_index++;
}
if ((tensor_operands & spv::TensorAddressingOperandsMask::DecodeFunc) !=
spv::TensorAddressingOperandsMask::MaskNone) {
if (inst->opcode() == spv::Op::OpCooperativeMatrixStoreTensorNV) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpCooperativeMatrixStoreTensorNV does not support DecodeFunc.";
}
const auto decode_func_id =
inst->GetOperandAs<uint32_t>(tensor_operand_index);
const auto decode_func = _.FindDef(decode_func_id);
if (!decode_func || decode_func->opcode() != spv::Op::OpFunction) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " DecodeFunc <id> " << _.getIdName(decode_func_id)
<< " is not a function.";
}
const auto component_type_index = 1;
const auto component_type_id =
matrix_type->GetOperandAs<uint32_t>(component_type_index);
const auto function_type =
_.FindDef(decode_func->GetOperandAs<uint32_t>(3));
if (function_type->GetOperandAs<uint32_t>(1) != component_type_id) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " DecodeFunc <id> " << _.getIdName(decode_func_id)
<< " return type must match matrix component type.";
}
const auto decode_ptr_type_id = function_type->GetOperandAs<uint32_t>(2);
const auto decode_ptr_type = _.FindDef(decode_ptr_type_id);
auto decode_storage_class =
decode_ptr_type->GetOperandAs<spv::StorageClass>(storage_class_index);
if (decode_storage_class != spv::StorageClass::PhysicalStorageBuffer) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " DecodeFunc <id> " << _.getIdName(decode_func_id)
<< " first parameter must be pointer to PhysicalStorageBuffer.";
}
const auto tensor_layout_type = _.FindDef(tensor_layout->type_id());
for (uint32_t param = 3; param < 5; ++param) {
const auto param_type_id = function_type->GetOperandAs<uint32_t>(param);
const auto param_type = _.FindDef(param_type_id);
if (param_type->opcode() != spv::Op::OpTypeArray) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " DecodeFunc <id> " << _.getIdName(decode_func_id)
<< " second/third parameter must be array of 32-bit integer "
"with "
<< " dimension equal to the tensor dimension.";
}
const auto length_index = 2u;
uint64_t array_length;
if (_.EvalConstantValUint64(
param_type->GetOperandAs<uint32_t>(length_index),
&array_length)) {
const auto tensor_layout_dim_id =
tensor_layout_type->GetOperandAs<uint32_t>(1);
uint64_t dim_value;
if (_.EvalConstantValUint64(tensor_layout_dim_id, &dim_value)) {
if (array_length != dim_value) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< opname << " DecodeFunc <id> "
<< _.getIdName(decode_func_id)
<< " second/third parameter must be array of 32-bit integer "
"with "
<< " dimension equal to the tensor dimension.";
}
}
}
}
tensor_operand_index++;
}
return SPV_SUCCESS;
}
spv_result_t ValidatePtrComparison(ValidationState_t& _,
const Instruction* inst) {
if (_.addressing_model() == spv::AddressingModel::Logical &&
@@ -2284,6 +2506,11 @@ spv_result_t MemoryPass(ValidationState_t& _, const Instruction* inst) {
if (auto error = ValidateCooperativeMatrixLoadStoreKHR(_, inst))
return error;
break;
case spv::Op::OpCooperativeMatrixLoadTensorNV:
case spv::Op::OpCooperativeMatrixStoreTensorNV:
if (auto error = ValidateCooperativeMatrixLoadStoreTensorNV(_, inst))
return error;
break;
case spv::Op::OpPtrEqual:
case spv::Op::OpPtrNotEqual:
case spv::Op::OpPtrDiff:

View File

@@ -390,9 +390,8 @@ spv_result_t ValidateGroupNonUniformRotateKHR(ValidationState_t& _,
if (inst->words().size() > 6) {
const uint32_t cluster_size_op_id = inst->GetOperandAs<uint32_t>(5);
const Instruction* cluster_size_inst = _.FindDef(cluster_size_op_id);
const uint32_t cluster_size_type =
cluster_size_inst ? cluster_size_inst->type_id() : 0;
if (!_.IsUnsignedIntScalarType(cluster_size_type)) {
if (!cluster_size_inst ||
!_.IsUnsignedIntScalarType(cluster_size_inst->type_id())) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "ClusterSize must be a scalar of integer type, whose "
"Signedness operand is 0.";

View File

@@ -0,0 +1,184 @@
// Copyright (c) 2024 NVIDIA Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Validate instructions that manipulate tensor layout and view objects
#include "source/opcode.h"
#include "source/spirv_target_env.h"
#include "source/val/instruction.h"
#include "source/val/validate.h"
#include "source/val/validation_state.h"
namespace spvtools {
namespace val {
namespace {
spv_result_t ValidateTensorLayoutResultTypeNV(ValidationState_t& _,
const Instruction* inst) {
const auto result_type_index = 0;
const auto result_type_id = inst->GetOperandAs<uint32_t>(result_type_index);
const auto result_type = _.FindDef(result_type_id);
if (!result_type || spv::Op::OpTypeTensorLayoutNV != result_type->opcode()) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " Result Type <id> "
<< _.getIdName(result_type_id) << " is not a tensor layout type.";
}
return SPV_SUCCESS;
}
spv_result_t ValidateTensorViewResultTypeNV(ValidationState_t& _,
const Instruction* inst) {
const auto result_type_index = 0;
const auto result_type_id = inst->GetOperandAs<uint32_t>(result_type_index);
const auto result_type = _.FindDef(result_type_id);
if (!result_type || spv::Op::OpTypeTensorViewNV != result_type->opcode()) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " Result Type <id> "
<< _.getIdName(result_type_id) << " is not a tensor view type.";
}
return SPV_SUCCESS;
}
spv_result_t ValidateCreateTensorLayoutNV(ValidationState_t& _,
const Instruction* inst) {
if (auto error = ValidateTensorLayoutResultTypeNV(_, inst)) return error;
return SPV_SUCCESS;
}
spv_result_t ValidateCreateTensorViewNV(ValidationState_t& _,
const Instruction* inst) {
if (auto error = ValidateTensorViewResultTypeNV(_, inst)) return error;
return SPV_SUCCESS;
}
enum ExpectedNumValues {
DIM,
DIMx2,
ONE,
FOUR,
};
spv_result_t ValidateTensorTypeWithDimValuesNV(ValidationState_t& _,
const Instruction* inst,
ExpectedNumValues expected,
bool is_view) {
std::string type_str;
if (is_view) {
if (auto error = ValidateTensorViewResultTypeNV(_, inst)) return error;
type_str = "TensorView";
} else {
if (auto error = ValidateTensorLayoutResultTypeNV(_, inst)) return error;
type_str = "TensorLayout";
}
const auto result_type_id = inst->GetOperandAs<uint32_t>(0);
const auto tensor_id = inst->GetOperandAs<uint32_t>(2);
const auto tensor = _.FindDef(tensor_id);
if (!tensor || result_type_id != tensor->type_id()) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " Result Type <id> "
<< _.getIdName(result_type_id) << " does not match " << type_str
<< " type.";
}
const auto num_values = inst->operands().size() - 3;
const auto result_type = _.FindDef(result_type_id);
const auto dim_index = 1;
const auto dim_id = result_type->GetOperandAs<uint32_t>(dim_index);
uint64_t dim_value;
if (_.EvalConstantValUint64(dim_id, &dim_value)) {
uint64_t expected_num_values = 0;
switch (expected) {
case DIM:
expected_num_values = dim_value;
break;
case DIMx2:
expected_num_values = dim_value * 2;
break;
case ONE:
expected_num_values = 1;
break;
case FOUR:
expected_num_values = 4;
break;
}
if (num_values != expected_num_values) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode())
<< " unexpected number of operands.";
}
}
for (uint32_t i = 0; i < num_values; ++i) {
const auto val_id = inst->GetOperandAs<uint32_t>(i + 3);
const auto val = _.FindDef(val_id);
if (!val || !_.IsIntScalarType(val->type_id()) ||
_.GetBitWidth(val->type_id()) != 32) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " operand <id> "
<< _.getIdName(val_id) << " is not a 32-bit integer.";
}
}
return SPV_SUCCESS;
}
} // namespace
spv_result_t TensorLayoutPass(ValidationState_t& _, const Instruction* inst) {
switch (inst->opcode()) {
case spv::Op::OpCreateTensorLayoutNV:
if (auto error = ValidateCreateTensorLayoutNV(_, inst)) return error;
break;
case spv::Op::OpCreateTensorViewNV:
if (auto error = ValidateCreateTensorViewNV(_, inst)) return error;
break;
case spv::Op::OpTensorLayoutSetBlockSizeNV:
case spv::Op::OpTensorLayoutSetDimensionNV:
case spv::Op::OpTensorLayoutSetStrideNV:
if (auto error = ValidateTensorTypeWithDimValuesNV(_, inst, DIM, false))
return error;
break;
case spv::Op::OpTensorLayoutSliceNV:
if (auto error = ValidateTensorTypeWithDimValuesNV(_, inst, DIMx2, false))
return error;
break;
case spv::Op::OpTensorLayoutSetClampValueNV:
if (auto error = ValidateTensorTypeWithDimValuesNV(_, inst, ONE, false))
return error;
break;
case spv::Op::OpTensorViewSetDimensionNV:
case spv::Op::OpTensorViewSetStrideNV:
if (auto error = ValidateTensorTypeWithDimValuesNV(_, inst, DIM, true))
return error;
break;
case spv::Op::OpTensorViewSetClipNV:
if (auto error = ValidateTensorTypeWithDimValuesNV(_, inst, FOUR, true))
return error;
break;
default:
break;
}
return SPV_SUCCESS;
}
} // namespace val
} // namespace spvtools

View File

@@ -1,4 +1,5 @@
// Copyright (c) 2018 Google LLC.
// Copyright (c) 2024 NVIDIA Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -582,6 +583,37 @@ spv_result_t ValidateTypeCooperativeMatrix(ValidationState_t& _,
}
}
uint64_t scope_value;
if (_.EvalConstantValUint64(scope_id, &scope_value)) {
if (scope_value == static_cast<uint32_t>(spv::Scope::Workgroup)) {
for (auto entry_point_id : _.entry_points()) {
if (!_.EntryPointHasLocalSizeOrId(entry_point_id)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpTypeCooperativeMatrixKHR with ScopeWorkgroup "
<< "used without specifying LocalSize or LocalSizeId "
<< "for entry point <id> " << _.getIdName(entry_point_id);
}
const auto local_size = _.EntryPointLocalSizeOrId(entry_point_id);
const auto mode = local_size->GetOperandAs<spv::ExecutionMode>(1);
if (mode == spv::ExecutionMode::LocalSizeId) {
uint32_t local_size_ids[3] = {
local_size->GetOperandAs<uint32_t>(2),
local_size->GetOperandAs<uint32_t>(3),
local_size->GetOperandAs<uint32_t>(4),
};
for (auto id : local_size_ids) {
if (_.FindDef(id) > inst) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpTypeCooperativeMatrixKHR with ScopeWorkgroup "
<< "used before LocalSizeId constant value <id> "
<< _.getIdName(id) << " is defined.";
}
}
}
}
}
}
return SPV_SUCCESS;
}
@@ -611,6 +643,115 @@ spv_result_t ValidateTypeUntypedPointerKHR(ValidationState_t& _,
}
return SPV_SUCCESS;
}
spv_result_t ValidateTensorDim(ValidationState_t& _, const Instruction* inst) {
const auto dim_index = 1;
const auto dim_id = inst->GetOperandAs<uint32_t>(dim_index);
const auto dim = _.FindDef(dim_id);
if (!dim || !_.IsIntScalarType(dim->type_id()) ||
_.GetBitWidth(dim->type_id()) != 32) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " Dim <id> "
<< _.getIdName(dim_id) << " is not a 32-bit integer.";
}
constexpr uint32_t max_tensor_dim = 5;
uint64_t dim_value;
if (_.EvalConstantValUint64(dim_id, &dim_value)) {
if (dim_value == 0 || dim_value > max_tensor_dim) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " Dim <id> "
<< _.getIdName(dim_id) << " must be between 1 and "
<< max_tensor_dim << ".";
}
}
return SPV_SUCCESS;
}
spv_result_t ValidateTypeTensorLayoutNV(ValidationState_t& _,
const Instruction* inst) {
if (auto error = ValidateTensorDim(_, inst)) return error;
const auto clamp_index = 2;
const auto clamp_id = inst->GetOperandAs<uint32_t>(clamp_index);
const auto clamp = _.FindDef(clamp_id);
if (!clamp || !_.IsIntScalarType(clamp->type_id()) ||
_.GetBitWidth(clamp->type_id()) != 32) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " ClampMode <id> "
<< _.getIdName(clamp_id) << " is not a 32-bit integer.";
}
uint64_t clamp_value;
if (_.EvalConstantValUint64(clamp_id, &clamp_value)) {
if (clamp_value >
static_cast<uint32_t>(spv::TensorClampMode::RepeatMirrored)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " ClampMode <id> "
<< _.getIdName(clamp_id) << " must be a valid TensorClampMode.";
}
}
return SPV_SUCCESS;
}
spv_result_t ValidateTypeTensorViewNV(ValidationState_t& _,
const Instruction* inst) {
if (auto error = ValidateTensorDim(_, inst)) return error;
const auto has_dim_index = 2;
const auto has_dim_id = inst->GetOperandAs<uint32_t>(has_dim_index);
const auto has_dim = _.FindDef(has_dim_id);
if (!has_dim || !_.IsBoolScalarType(has_dim->type_id())) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " HasDimensions <id> "
<< _.getIdName(has_dim_id) << " is not a boolean value.";
}
uint32_t permutation_mask = 0;
bool all_constant = true;
const auto num_dim = inst->operands().size() - 3;
for (size_t p_index = 3; p_index < inst->operands().size(); ++p_index) {
auto p_id = inst->GetOperandAs<uint32_t>(p_index);
const auto p = _.FindDef(p_id);
if (!p || !_.IsIntScalarType(p->type_id()) ||
_.GetBitWidth(p->type_id()) != 32) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " Permutation <id> "
<< _.getIdName(p_id) << " is not a 32-bit integer.";
}
uint64_t p_value;
if (_.EvalConstantValUint64(p_id, &p_value)) {
if (p_value >= num_dim) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode()) << " Permutation <id> "
<< _.getIdName(p_id) << " must be a valid dimension.";
}
permutation_mask |= 1 << p_value;
} else {
all_constant = false;
}
}
if (all_constant && permutation_mask != (1U << num_dim) - 1U) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode())
<< " Permutation values don't form a valid permutation.";
}
uint64_t dim_value;
if (_.EvalConstantValUint64(inst->GetOperandAs<uint32_t>(1), &dim_value)) {
if (dim_value != num_dim) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< spvOpcodeString(inst->opcode())
<< " Incorrect number of permutation values.";
}
}
return SPV_SUCCESS;
}
} // namespace
spv_result_t TypePass(ValidationState_t& _, const Instruction* inst) {
@@ -659,6 +800,12 @@ spv_result_t TypePass(ValidationState_t& _, const Instruction* inst) {
case spv::Op::OpTypeUntypedPointerKHR:
if (auto error = ValidateTypeUntypedPointerKHR(_, inst)) return error;
break;
case spv::Op::OpTypeTensorLayoutNV:
if (auto error = ValidateTypeTensorLayoutNV(_, inst)) return error;
break;
case spv::Op::OpTypeTensorViewNV:
if (auto error = ValidateTypeTensorViewNV(_, inst)) return error;
break;
default:
break;
}

View File

@@ -1290,8 +1290,9 @@ bool ValidationState_t::IsUnsigned64BitHandle(uint32_t id) const {
}
spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
const Instruction* inst, uint32_t m1, uint32_t m2) {
const auto m1_type = FindDef(m1);
const Instruction* inst, uint32_t result_type_id, uint32_t m2,
bool is_conversion, bool swap_row_col) {
const auto m1_type = FindDef(result_type_id);
const auto m2_type = FindDef(m2);
if (m1_type->opcode() != m2_type->opcode()) {
@@ -1307,6 +1308,10 @@ spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
uint32_t m2_rows_id = m2_type->GetOperandAs<uint32_t>(3);
uint32_t m2_cols_id = m2_type->GetOperandAs<uint32_t>(4);
if (swap_row_col) {
std::swap(m1_rows_id, m1_cols_id);
}
bool m1_is_int32 = false, m1_is_const_int32 = false, m2_is_int32 = false,
m2_is_const_int32 = false;
uint32_t m1_value = 0, m2_value = 0;
@@ -1330,7 +1335,7 @@ spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
return diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected rows of Matrix type and Result Type to be "
<< "identical";
<< (swap_row_col ? "swapped with columns" : "identical");
}
std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
@@ -1341,7 +1346,7 @@ spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
return diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected columns of Matrix type and Result Type to be "
<< "identical";
<< (swap_row_col ? "swapped with rows" : "identical");
}
if (m1_type->opcode() == spv::Op::OpTypeCooperativeMatrixKHR) {
@@ -1352,7 +1357,12 @@ spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
EvalInt32IfConst(m2_use_id);
if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value &&
// CooperativeMatrixConversionsNV allows conversions from Acc->A/B
!(is_conversion &&
HasCapability(spv::Capability::CooperativeMatrixConversionsNV) &&
m2_value ==
(uint32_t)spv::CooperativeMatrixUse::MatrixAccumulatorKHR)) {
return diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Use of Matrix type and Result Type to be "
<< "identical";

View File

@@ -240,6 +240,21 @@ class ValidationState_t {
entry_point_to_execution_modes_[entry_point].insert(execution_mode);
}
/// Registers that the entry point declares its local size
void RegisterEntryPointLocalSize(uint32_t entry_point,
const Instruction* inst) {
entry_point_to_local_size_or_id_[entry_point] = inst;
}
/// Returns whether the entry point declares its local size
bool EntryPointHasLocalSizeOrId(uint32_t entry_point) const {
return entry_point_to_local_size_or_id_.find(entry_point) !=
entry_point_to_local_size_or_id_.end();
}
/// Returns the id of the local size
const Instruction* EntryPointLocalSizeOrId(uint32_t entry_point) const {
return entry_point_to_local_size_or_id_.find(entry_point)->second;
}
/// Returns the interface descriptions of a given entry point.
const std::vector<EntryPointDescription>& entry_point_descriptions(
uint32_t entry_point) {
@@ -759,11 +774,14 @@ class ValidationState_t {
return SpvDecorationString(uint32_t(decoration));
}
// Returns whether type m1 and type m2 are cooperative matrices with
// the same "shape" (matching scope, rows, cols). If any are specialization
// constants, we assume they can match because we can't prove they don't.
// Returns whether type result_type_id and type m2 are cooperative matrices
// with the same "shape" (matching scope, rows, cols). If any are
// specialization constants, we assume they can match because we can't prove
// they don't.
spv_result_t CooperativeMatrixShapesMatch(const Instruction* inst,
uint32_t m1, uint32_t m2);
uint32_t result_type_id,
uint32_t m2, bool is_conversion,
bool swap_row_col = false);
// Returns true if |lhs| and |rhs| logically match and, if the decorations of
// |rhs| are a subset of |lhs|.
@@ -949,6 +967,10 @@ class ValidationState_t {
std::unordered_map<uint32_t, std::set<spv::ExecutionMode>>
entry_point_to_execution_modes_;
// Mapping entry point -> local size execution mode instruction
std::unordered_map<uint32_t, const Instruction*>
entry_point_to_local_size_or_id_;
/// Mapping function -> array of entry points inside this
/// module which can (indirectly) call the function.
std::unordered_map<uint32_t, std::vector<uint32_t>> function_to_entry_points_;