From 1e978cc3db5c9197b1bc04b97497441d9de82921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Sat, 5 Mar 2022 17:40:54 -0800 Subject: [PATCH] Updated spirv-tools. --- .../include/generated/build-version.inc | 2 +- .../include/generated/core.insts-unified1.inc | 7 +- .../include/generated/enum_string_mapping.inc | 8 +- .../include/generated/extension_enum.inc | 1 + .../generated/operand.kinds-unified1.inc | 4 +- .../source/opt/def_use_manager.cpp | 204 +++++++++------ .../spirv-tools/source/opt/def_use_manager.h | 90 ++----- .../spirv-tools/source/opt/ir_context.cpp | 2 + 3rdparty/spirv-tools/source/opt/ir_context.h | 3 +- 3rdparty/spirv-tools/source/opt/ir_loader.cpp | 3 +- .../source/opt/merge_return_pass.cpp | 1 + 3rdparty/spirv-tools/source/opt/types.cpp | 158 +++++------- 3rdparty/spirv-tools/source/opt/types.h | 105 ++++---- .../spirv-tools/source/util/hash_combine.h | 53 ++++ .../source/util/pooled_linked_list.h | 236 ++++++++++++++++++ .../spirv-tools/source/util/small_vector.h | 9 + .../source/val/validate_extensions.cpp | 110 ++++++++ .../source/val/validate_memory.cpp | 20 +- .../source/val/validation_state.cpp | 2 + 19 files changed, 705 insertions(+), 313 deletions(-) create mode 100644 3rdparty/spirv-tools/source/util/hash_combine.h create mode 100644 3rdparty/spirv-tools/source/util/pooled_linked_list.h diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index dd370e9b8..02ed4cfc5 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2022.2-dev", "SPIRV-Tools v2022.2-dev 8f96b8ade7aed1a3448c9cd0294449e7a41b91f7" +"v2022.2-dev", "SPIRV-Tools v2022.2-dev da9e2f0400ece7d68b44d7c7126cac808dfcf5c3" diff --git a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc index 4eab18abc..cf6b2c663 100644 --- a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc @@ -56,6 +56,7 @@ static const SpvCapability pygen_variable_caps_Shader[] = {SpvCapabilityShader}; static const SpvCapability pygen_variable_caps_ShaderBitInstructions[] = {SpvCapabilityShader, SpvCapabilityBitInstructions}; static const SpvCapability pygen_variable_caps_ShaderClockKHR[] = {SpvCapabilityShaderClockKHR}; static const SpvCapability pygen_variable_caps_SparseResidency[] = {SpvCapabilitySparseResidency}; +static const SpvCapability pygen_variable_caps_SplitBarrierINTEL[] = {SpvCapabilitySplitBarrierINTEL}; static const SpvCapability pygen_variable_caps_SubgroupAvcMotionEstimationINTEL[] = {SpvCapabilitySubgroupAvcMotionEstimationINTEL}; static const SpvCapability pygen_variable_caps_SubgroupAvcMotionEstimationINTELSubgroupAvcMotionEstimationChromaINTEL[] = {SpvCapabilitySubgroupAvcMotionEstimationINTEL, SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL}; static const SpvCapability pygen_variable_caps_SubgroupAvcMotionEstimationINTELSubgroupAvcMotionEstimationIntraINTEL[] = {SpvCapabilitySubgroupAvcMotionEstimationINTEL, SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL}; @@ -509,7 +510,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"BeginInvocationInterlockEXT", SpvOpBeginInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu}, {"EndInvocationInterlockEXT", SpvOpEndInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu}, {"DemoteToHelperInvocation", SpvOpDemoteToHelperInvocation, 1, pygen_variable_caps_DemoteToHelperInvocation, 0, {}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu}, - {"DemoteToHelperInvocationEXT", SpvOpDemoteToHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocation, 0, {}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu}, + {"DemoteToHelperInvocationEXT", SpvOpDemoteToHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocationEXT, 0, {}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu}, {"IsHelperInvocationEXT", SpvOpIsHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocationEXT, 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}, {"ConvertUToImageNV", SpvOpConvertUToImageNV, 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", SpvOpConvertUToSamplerNV, 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}, @@ -758,5 +759,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"TypeBufferSurfaceINTEL", SpvOpTypeBufferSurfaceINTEL, 1, pygen_variable_caps_VectorComputeINTEL, 2, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ACCESS_QUALIFIER}, 1, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"TypeStructContinuedINTEL", SpvOpTypeStructContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"ConstantCompositeContinuedINTEL", SpvOpConstantCompositeContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, - {"SpecConstantCompositeContinuedINTEL", SpvOpSpecConstantCompositeContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu} + {"SpecConstantCompositeContinuedINTEL", SpvOpSpecConstantCompositeContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"ControlBarrierArriveINTEL", SpvOpControlBarrierArriveINTEL, 1, pygen_variable_caps_SplitBarrierINTEL, 3, {SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"ControlBarrierWaitINTEL", SpvOpControlBarrierWaitINTEL, 1, pygen_variable_caps_SplitBarrierINTEL, 3, {SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu} }; \ No newline at end of file diff --git a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc index 59a738387..958d2d3cc 100644 --- a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc +++ b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc @@ -98,6 +98,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_INTEL_optnone"; case Extension::kSPV_INTEL_shader_integer_functions2: return "SPV_INTEL_shader_integer_functions2"; + case Extension::kSPV_INTEL_split_barrier: + return "SPV_INTEL_split_barrier"; case Extension::kSPV_INTEL_subgroups: return "SPV_INTEL_subgroups"; case Extension::kSPV_INTEL_unstructured_loop_controls: @@ -205,8 +207,8 @@ const char* ExtensionToString(Extension extension) { bool GetExtensionFromString(const char* str, Extension* extension) { - static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_atomic_float16_add", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_shader_atomic_float_min_max", "SPV_EXT_shader_image_int64", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_arbitrary_precision_fixed_point", "SPV_INTEL_arbitrary_precision_floating_point", "SPV_INTEL_arbitrary_precision_integers", "SPV_INTEL_blocking_pipes", "SPV_INTEL_debug_module", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_float_controls2", "SPV_INTEL_fp_fast_math_mode", "SPV_INTEL_fpga_buffer_location", "SPV_INTEL_fpga_cluster_attributes", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_accesses", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_inline_assembly", "SPV_INTEL_io_pipes", "SPV_INTEL_kernel_attributes", "SPV_INTEL_long_constant_composite", "SPV_INTEL_loop_fuse", "SPV_INTEL_media_block_io", "SPV_INTEL_memory_access_aliasing", "SPV_INTEL_optnone", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_INTEL_usm_storage_classes", "SPV_INTEL_variable_length_array", "SPV_INTEL_vector_compute", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_bit_instructions", "SPV_KHR_device_group", "SPV_KHR_expect_assume", "SPV_KHR_float_controls", "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_fragment_shading_rate", "SPV_KHR_integer_dot_product", "SPV_KHR_linkonce_odr", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_non_semantic_info", "SPV_KHR_physical_storage_buffer", "SPV_KHR_post_depth_coverage", "SPV_KHR_ray_query", "SPV_KHR_ray_tracing", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_clock", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_KHR_workgroup_memory_explicit_layout", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_bindless_texture", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_ray_tracing_motion_blur", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" }; - static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_atomic_float16_add, Extension::kSPV_EXT_shader_atomic_float_add, Extension::kSPV_EXT_shader_atomic_float_min_max, Extension::kSPV_EXT_shader_image_int64, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_arbitrary_precision_fixed_point, Extension::kSPV_INTEL_arbitrary_precision_floating_point, Extension::kSPV_INTEL_arbitrary_precision_integers, Extension::kSPV_INTEL_blocking_pipes, Extension::kSPV_INTEL_debug_module, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_float_controls2, Extension::kSPV_INTEL_fp_fast_math_mode, Extension::kSPV_INTEL_fpga_buffer_location, Extension::kSPV_INTEL_fpga_cluster_attributes, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_accesses, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_inline_assembly, Extension::kSPV_INTEL_io_pipes, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_long_constant_composite, Extension::kSPV_INTEL_loop_fuse, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_memory_access_aliasing, Extension::kSPV_INTEL_optnone, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_INTEL_usm_storage_classes, Extension::kSPV_INTEL_variable_length_array, Extension::kSPV_INTEL_vector_compute, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_bit_instructions, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_expect_assume, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_fragment_shader_barycentric, Extension::kSPV_KHR_fragment_shading_rate, Extension::kSPV_KHR_integer_dot_product, Extension::kSPV_KHR_linkonce_odr, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_non_semantic_info, Extension::kSPV_KHR_physical_storage_buffer, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_ray_query, Extension::kSPV_KHR_ray_tracing, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_clock, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_KHR_workgroup_memory_explicit_layout, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_bindless_texture, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_ray_tracing_motion_blur, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique }; + static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_atomic_float16_add", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_shader_atomic_float_min_max", "SPV_EXT_shader_image_int64", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_arbitrary_precision_fixed_point", "SPV_INTEL_arbitrary_precision_floating_point", "SPV_INTEL_arbitrary_precision_integers", "SPV_INTEL_blocking_pipes", "SPV_INTEL_debug_module", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_float_controls2", "SPV_INTEL_fp_fast_math_mode", "SPV_INTEL_fpga_buffer_location", "SPV_INTEL_fpga_cluster_attributes", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_accesses", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_inline_assembly", "SPV_INTEL_io_pipes", "SPV_INTEL_kernel_attributes", "SPV_INTEL_long_constant_composite", "SPV_INTEL_loop_fuse", "SPV_INTEL_media_block_io", "SPV_INTEL_memory_access_aliasing", "SPV_INTEL_optnone", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_split_barrier", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_INTEL_usm_storage_classes", "SPV_INTEL_variable_length_array", "SPV_INTEL_vector_compute", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_bit_instructions", "SPV_KHR_device_group", "SPV_KHR_expect_assume", "SPV_KHR_float_controls", "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_fragment_shading_rate", "SPV_KHR_integer_dot_product", "SPV_KHR_linkonce_odr", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_non_semantic_info", "SPV_KHR_physical_storage_buffer", "SPV_KHR_post_depth_coverage", "SPV_KHR_ray_query", "SPV_KHR_ray_tracing", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_clock", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_KHR_workgroup_memory_explicit_layout", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_bindless_texture", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_ray_tracing_motion_blur", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" }; + static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_atomic_float16_add, Extension::kSPV_EXT_shader_atomic_float_add, Extension::kSPV_EXT_shader_atomic_float_min_max, Extension::kSPV_EXT_shader_image_int64, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_arbitrary_precision_fixed_point, Extension::kSPV_INTEL_arbitrary_precision_floating_point, Extension::kSPV_INTEL_arbitrary_precision_integers, Extension::kSPV_INTEL_blocking_pipes, Extension::kSPV_INTEL_debug_module, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_float_controls2, Extension::kSPV_INTEL_fp_fast_math_mode, Extension::kSPV_INTEL_fpga_buffer_location, Extension::kSPV_INTEL_fpga_cluster_attributes, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_accesses, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_inline_assembly, Extension::kSPV_INTEL_io_pipes, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_long_constant_composite, Extension::kSPV_INTEL_loop_fuse, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_memory_access_aliasing, Extension::kSPV_INTEL_optnone, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_split_barrier, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_INTEL_usm_storage_classes, Extension::kSPV_INTEL_variable_length_array, Extension::kSPV_INTEL_vector_compute, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_bit_instructions, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_expect_assume, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_fragment_shader_barycentric, Extension::kSPV_KHR_fragment_shading_rate, Extension::kSPV_KHR_integer_dot_product, Extension::kSPV_KHR_linkonce_odr, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_non_semantic_info, Extension::kSPV_KHR_physical_storage_buffer, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_ray_query, Extension::kSPV_KHR_ray_tracing, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_clock, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_KHR_workgroup_memory_explicit_layout, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_bindless_texture, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_ray_tracing_motion_blur, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique }; const auto b = std::begin(known_ext_strs); const auto e = std::end(known_ext_strs); const auto found = std::equal_range( @@ -612,6 +614,8 @@ const char* CapabilityToString(SpvCapability capability) { return "AtomicFloat16AddEXT"; case SpvCapabilityDebugInfoModuleINTEL: return "DebugInfoModuleINTEL"; + case SpvCapabilitySplitBarrierINTEL: + return "SplitBarrierINTEL"; case SpvCapabilityMax: assert(0 && "Attempting to convert SpvCapabilityMax to string"); return ""; diff --git a/3rdparty/spirv-tools/include/generated/extension_enum.inc b/3rdparty/spirv-tools/include/generated/extension_enum.inc index a56c003f3..a22ade3e3 100644 --- a/3rdparty/spirv-tools/include/generated/extension_enum.inc +++ b/3rdparty/spirv-tools/include/generated/extension_enum.inc @@ -47,6 +47,7 @@ kSPV_INTEL_media_block_io, kSPV_INTEL_memory_access_aliasing, kSPV_INTEL_optnone, kSPV_INTEL_shader_integer_functions2, +kSPV_INTEL_split_barrier, kSPV_INTEL_subgroups, kSPV_INTEL_unstructured_loop_controls, kSPV_INTEL_usm_storage_classes, diff --git a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc index 1aeab35de..17eda0f9e 100644 --- a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc @@ -164,6 +164,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_media_block_io[] static const spvtools::Extension pygen_variable_exts_SPV_INTEL_memory_access_aliasing[] = {spvtools::Extension::kSPV_INTEL_memory_access_aliasing}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_optnone[] = {spvtools::Extension::kSPV_INTEL_optnone}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_shader_integer_functions2[] = {spvtools::Extension::kSPV_INTEL_shader_integer_functions2}; +static const spvtools::Extension pygen_variable_exts_SPV_INTEL_split_barrier[] = {spvtools::Extension::kSPV_INTEL_split_barrier}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_subgroups[] = {spvtools::Extension::kSPV_INTEL_subgroups}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_unstructured_loop_controls[] = {spvtools::Extension::kSPV_INTEL_unstructured_loop_controls}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_usm_storage_classes[] = {spvtools::Extension::kSPV_INTEL_usm_storage_classes}; @@ -1155,7 +1156,8 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"LongConstantCompositeINTEL", 6089, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_long_constant_composite, {}, 0xffffffffu, 0xffffffffu}, {"OptNoneINTEL", 6094, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_optnone, {}, 0xffffffffu, 0xffffffffu}, {"AtomicFloat16AddEXT", 6095, 0, nullptr, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float16_add, {}, 0xffffffffu, 0xffffffffu}, - {"DebugInfoModuleINTEL", 6114, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_debug_module, {}, 0xffffffffu, 0xffffffffu} + {"DebugInfoModuleINTEL", 6114, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_debug_module, {}, 0xffffffffu, 0xffffffffu}, + {"SplitBarrierINTEL", 6141, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_split_barrier, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_RayQueryIntersectionEntries[] = { diff --git a/3rdparty/spirv-tools/source/opt/def_use_manager.cpp b/3rdparty/spirv-tools/source/opt/def_use_manager.cpp index d54fdb65d..e1e441e0e 100644 --- a/3rdparty/spirv-tools/source/opt/def_use_manager.cpp +++ b/3rdparty/spirv-tools/source/opt/def_use_manager.cpp @@ -13,11 +13,23 @@ // limitations under the License. #include "source/opt/def_use_manager.h" +#include "source/util/make_unique.h" namespace spvtools { namespace opt { namespace analysis { +// Don't compact before we have a reasonable number of ids allocated (~32kb). +static const size_t kCompactThresholdMinTotalIds = (8 * 1024); +// Compact when fewer than this fraction of the storage is used (should be 2^n +// for performance). +static const size_t kCompactThresholdFractionFreeIds = 8; + +DefUseManager::DefUseManager() { + use_pool_ = MakeUnique(); + used_id_pool_ = MakeUnique(); +} + void DefUseManager::AnalyzeInstDef(Instruction* inst) { const uint32_t def_id = inst->result_id(); if (def_id != 0) { @@ -34,15 +46,15 @@ void DefUseManager::AnalyzeInstDef(Instruction* inst) { } void DefUseManager::AnalyzeInstUse(Instruction* inst) { + // It might have existed before. + EraseUseRecordsOfOperandIds(inst); + // Create entry for the given instruction. Note that the instruction may // not have any in-operands. In such cases, we still need a entry for those // instructions so this manager knows it has seen the instruction later. - auto* used_ids = &inst_to_used_ids_[inst]; - if (used_ids->size()) { - EraseUseRecordsOfOperandIds(inst); - used_ids = &inst_to_used_ids_[inst]; - } - used_ids->clear(); // It might have existed before. + UsedIdList& used_ids = + inst_to_used_id_.insert({inst, UsedIdList(used_id_pool_.get())}) + .first->second; for (uint32_t i = 0; i < inst->NumOperands(); ++i) { switch (inst->GetOperand(i).type) { @@ -54,8 +66,17 @@ void DefUseManager::AnalyzeInstUse(Instruction* inst) { uint32_t use_id = inst->GetSingleWordOperand(i); Instruction* def = GetDef(use_id); assert(def && "Definition is not registered."); - id_to_users_.insert(UserEntry{def, inst}); - used_ids->push_back(use_id); + + // Add to inst's use records + used_ids.push_back(use_id); + + // Add to the users, taking care to avoid adding duplicates. We know + // the duplicate for this instruction will always be at the tail. + UseList& list = inst_to_users_.insert({def, UseList(use_pool_.get())}) + .first->second; + if (list.empty() || list.back() != inst) { + list.push_back(inst); + } } break; default: break; @@ -94,23 +115,6 @@ const Instruction* DefUseManager::GetDef(uint32_t id) const { return iter->second; } -DefUseManager::IdToUsersMap::const_iterator DefUseManager::UsersBegin( - const Instruction* def) const { - return id_to_users_.lower_bound( - UserEntry{const_cast(def), nullptr}); -} - -bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter, - const IdToUsersMap::const_iterator& cached_end, - const Instruction* inst) const { - return (iter != cached_end && iter->def == inst); -} - -bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter, - const Instruction* inst) const { - return UsersNotEnd(iter, id_to_users_.end(), inst); -} - bool DefUseManager::WhileEachUser( const Instruction* def, const std::function& f) const { // Ensure that |def| has been registered. @@ -118,9 +122,11 @@ bool DefUseManager::WhileEachUser( "Definition is not registered."); if (!def->HasResultId()) return true; - auto end = id_to_users_.end(); - for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) { - if (!f(iter->user)) return false; + auto iter = inst_to_users_.find(def); + if (iter != inst_to_users_.end()) { + for (Instruction* user : iter->second) { + if (!f(user)) return false; + } } return true; } @@ -151,14 +157,15 @@ bool DefUseManager::WhileEachUse( "Definition is not registered."); if (!def->HasResultId()) return true; - auto end = id_to_users_.end(); - for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) { - Instruction* user = iter->user; - for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) { - const Operand& op = user->GetOperand(idx); - if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) { - if (def->result_id() == op.words[0]) { - if (!f(user, idx)) return false; + auto iter = inst_to_users_.find(def); + if (iter != inst_to_users_.end()) { + for (Instruction* user : iter->second) { + for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) { + const Operand& op = user->GetOperand(idx); + if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) { + if (def->result_id() == op.words[0]) { + if (!f(user, idx)) return false; + } } } } @@ -230,17 +237,18 @@ void DefUseManager::AnalyzeDefUse(Module* module) { } void DefUseManager::ClearInst(Instruction* inst) { - auto iter = inst_to_used_ids_.find(inst); - if (iter != inst_to_used_ids_.end()) { + if (inst_to_used_id_.find(inst) != inst_to_used_id_.end()) { EraseUseRecordsOfOperandIds(inst); - if (inst->result_id() != 0) { - // Remove all uses of this inst. - auto users_begin = UsersBegin(inst); - auto end = id_to_users_.end(); - auto new_end = users_begin; - for (; UsersNotEnd(new_end, end, inst); ++new_end) { + uint32_t const result_id = inst->result_id(); + if (result_id != 0) { + // For each using instruction, remove result_id from their used ids. + auto iter = inst_to_users_.find(inst); + if (iter != inst_to_users_.end()) { + for (Instruction* use : iter->second) { + inst_to_used_id_.at(use).remove_first(result_id); + } + inst_to_users_.erase(iter); } - id_to_users_.erase(users_begin, new_end); id_to_def_.erase(inst->result_id()); } } @@ -249,16 +257,48 @@ void DefUseManager::ClearInst(Instruction* inst) { void DefUseManager::EraseUseRecordsOfOperandIds(const Instruction* inst) { // Go through all ids used by this instruction, remove this instruction's // uses of them. - auto iter = inst_to_used_ids_.find(inst); - if (iter != inst_to_used_ids_.end()) { - for (auto use_id : iter->second) { - id_to_users_.erase( - UserEntry{GetDef(use_id), const_cast(inst)}); + auto iter = inst_to_used_id_.find(inst); + if (iter != inst_to_used_id_.end()) { + const UsedIdList& used_ids = iter->second; + for (uint32_t def_id : used_ids) { + auto def_iter = inst_to_users_.find(GetDef(def_id)); + if (def_iter != inst_to_users_.end()) { + def_iter->second.remove_first(const_cast(inst)); + } + } + inst_to_used_id_.erase(inst); + + // If we're using only a fraction of the space in used_ids_, compact storage + // to prevent memory usage from being unbounded. + if (used_id_pool_->total_nodes() > kCompactThresholdMinTotalIds && + used_id_pool_->used_nodes() < + used_id_pool_->total_nodes() / kCompactThresholdFractionFreeIds) { + CompactStorage(); } - inst_to_used_ids_.erase(iter); } } +void DefUseManager::CompactStorage() { + CompactUseRecords(); + CompactUsedIds(); +} + +void DefUseManager::CompactUseRecords() { + std::unique_ptr new_pool = MakeUnique(); + for (auto& iter : inst_to_users_) { + iter.second.move_nodes(new_pool.get()); + } + use_pool_ = std::move(new_pool); +} + +void DefUseManager::CompactUsedIds() { + std::unique_ptr new_pool = MakeUnique(); + for (auto& iter : inst_to_used_id_) { + iter.second.move_nodes(new_pool.get()); + } + used_id_pool_ = std::move(new_pool); +} + bool CompareAndPrintDifferences(const DefUseManager& lhs, const DefUseManager& rhs) { bool same = true; @@ -277,34 +317,52 @@ bool CompareAndPrintDifferences(const DefUseManager& lhs, same = false; } - if (lhs.id_to_users_ != rhs.id_to_users_) { - for (auto p : lhs.id_to_users_) { - if (rhs.id_to_users_.count(p) == 0) { - printf("Diff in id_to_users: missing value in rhs\n"); - } + for (const auto& l : lhs.inst_to_used_id_) { + std::set ul, ur; + lhs.ForEachUse(l.first, + [&ul](Instruction*, uint32_t id) { ul.insert(id); }); + rhs.ForEachUse(l.first, + [&ur](Instruction*, uint32_t id) { ur.insert(id); }); + if (ul.size() != ur.size()) { + printf( + "Diff in inst_to_used_id_: different number of used ids (%zu != %zu)", + ul.size(), ur.size()); + same = false; + } else if (ul != ur) { + printf("Diff in inst_to_used_id_: different used ids\n"); + same = false; } - for (auto p : rhs.id_to_users_) { - if (lhs.id_to_users_.count(p) == 0) { - printf("Diff in id_to_users: missing value in lhs\n"); - } + } + for (const auto& r : rhs.inst_to_used_id_) { + auto iter_l = lhs.inst_to_used_id_.find(r.first); + if (r.second.empty() && + !(iter_l == lhs.inst_to_used_id_.end() || iter_l->second.empty())) { + printf("Diff in inst_to_used_id_: unexpected instr in rhs\n"); + same = false; } - same = false; } - if (lhs.inst_to_used_ids_ != rhs.inst_to_used_ids_) { - for (auto p : lhs.inst_to_used_ids_) { - if (rhs.inst_to_used_ids_.count(p.first) == 0) { - printf("Diff in inst_to_used_ids: missing value in rhs\n"); - } + for (const auto& l : lhs.inst_to_users_) { + std::set ul, ur; + lhs.ForEachUser(l.first, [&ul](Instruction* use) { ul.insert(use); }); + rhs.ForEachUser(l.first, [&ur](Instruction* use) { ur.insert(use); }); + if (ul.size() != ur.size()) { + printf("Diff in inst_to_users_: different number of users (%zu != %zu)", + ul.size(), ur.size()); + same = false; + } else if (ul != ur) { + printf("Diff in inst_to_users_: different users\n"); + same = false; + } + } + for (const auto& r : rhs.inst_to_users_) { + auto iter_l = lhs.inst_to_users_.find(r.first); + if (r.second.empty() && + !(iter_l == lhs.inst_to_users_.end() || iter_l->second.empty())) { + printf("Diff in inst_to_users_: unexpected instr in rhs\n"); + same = false; } - for (auto p : rhs.inst_to_used_ids_) { - if (lhs.inst_to_used_ids_.count(p.first) == 0) { - printf("Diff in inst_to_used_ids: missing value in lhs\n"); - } - } - same = false; } - return same; } diff --git a/3rdparty/spirv-tools/source/opt/def_use_manager.h b/3rdparty/spirv-tools/source/opt/def_use_manager.h index a8dbbc60b..cf6cbdf51 100644 --- a/3rdparty/spirv-tools/source/opt/def_use_manager.h +++ b/3rdparty/spirv-tools/source/opt/def_use_manager.h @@ -21,6 +21,7 @@ #include "source/opt/instruction.h" #include "source/opt/module.h" +#include "source/util/pooled_linked_list.h" #include "spirv-tools/libspirv.hpp" namespace spvtools { @@ -49,50 +50,6 @@ inline bool operator<(const Use& lhs, const Use& rhs) { return lhs.operand_index < rhs.operand_index; } -// Definition should never be null. User can be null, however, such an entry -// should be used only for searching (e.g. all users of a particular definition) -// and never stored in a container. -struct UserEntry { - Instruction* def; - Instruction* user; -}; - -inline bool operator==(const UserEntry& lhs, const UserEntry& rhs) { - return lhs.def == rhs.def && lhs.user == rhs.user; -} - -// Orders UserEntry for use in associative containers (i.e. less than ordering). -// -// The definition of an UserEntry is treated as the major key and the users as -// the minor key so that all the users of a particular definition are -// consecutive in a container. -// -// A null user always compares less than a real user. This is done to provide -// easy values to search for the beginning of the users of a particular -// definition (i.e. using {def, nullptr}). -struct UserEntryLess { - bool operator()(const UserEntry& lhs, const UserEntry& rhs) const { - // If lhs.def and rhs.def are both null, fall through to checking the - // second entries. - if (!lhs.def && rhs.def) return true; - if (lhs.def && !rhs.def) return false; - - // If neither definition is null, then compare unique ids. - if (lhs.def && rhs.def) { - if (lhs.def->unique_id() < rhs.def->unique_id()) return true; - if (rhs.def->unique_id() < lhs.def->unique_id()) return false; - } - - // Return false on equality. - if (!lhs.user && !rhs.user) return false; - if (!lhs.user) return true; - if (!rhs.user) return false; - - // If neither user is null then compare unique ids. - return lhs.user->unique_id() < rhs.user->unique_id(); - } -}; - // A class for analyzing and managing defs and uses in an Module. class DefUseManager { public: @@ -102,7 +59,7 @@ class DefUseManager { // will be communicated to the outside via the given message |consumer|. This // instance only keeps a reference to the |consumer|, so the |consumer| should // outlive this instance. - DefUseManager(Module* module) { AnalyzeDefUse(module); } + DefUseManager(Module* module) : DefUseManager() { AnalyzeDefUse(module); } DefUseManager(const DefUseManager&) = delete; DefUseManager(DefUseManager&&) = delete; @@ -214,35 +171,36 @@ class DefUseManager { // uses. void UpdateDefUse(Instruction* inst); + // Compacts any internal storage to save memory. + void CompactStorage(); + private: - using IdToUsersMap = std::set; - using InstToUsedIdsMap = - std::unordered_map>; + using UseList = spvtools::utils::PooledLinkedList; + using UseListPool = spvtools::utils::PooledLinkedListNodes; + // Stores linked lists of Instructions using a def. + using InstToUsersMap = std::unordered_map; - // Returns the first location that {|def|, nullptr} could be inserted into the - // users map without violating ordering. - IdToUsersMap::const_iterator UsersBegin(const Instruction* def) const; + using UsedIdList = spvtools::utils::PooledLinkedList; + using UsedIdListPool = spvtools::utils::PooledLinkedListNodes; + // Stores mapping from instruction to their UsedIdRange. + using InstToUsedIdMap = std::unordered_map; - // Returns true if |iter| has not reached the end of |def|'s users. - // - // In the first version |iter| is compared against the end of the map for - // validity before other checks. In the second version, |iter| is compared - // against |cached_end| for validity before other checks. This allows caching - // the map's end which is a performance improvement on some platforms. - bool UsersNotEnd(const IdToUsersMap::const_iterator& iter, - const Instruction* def) const; - bool UsersNotEnd(const IdToUsersMap::const_iterator& iter, - const IdToUsersMap::const_iterator& cached_end, - const Instruction* def) const; + DefUseManager(); // Analyzes the defs and uses in the given |module| and populates data // structures in this class. Does nothing if |module| is nullptr. void AnalyzeDefUse(Module* module); - IdToDefMap id_to_def_; // Mapping from ids to their definitions - IdToUsersMap id_to_users_; // Mapping from ids to their users - // Mapping from instructions to the ids used in the instruction. - InstToUsedIdsMap inst_to_used_ids_; + // Removes unused entries in used_records_ and used_ids_. + void CompactUseRecords(); + void CompactUsedIds(); + + IdToDefMap id_to_def_; // Mapping from ids to their definitions + InstToUsersMap inst_to_users_; // Map from def to uses. + std::unique_ptr use_pool_; + + std::unique_ptr used_id_pool_; + InstToUsedIdMap inst_to_used_id_; // Map from instruction to used ids. }; } // namespace analysis diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index 5b0beeb2a..a80d4f2de 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -41,6 +41,8 @@ namespace spvtools { namespace opt { void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) { + set = Analysis(set & ~valid_analyses_); + if (set & kAnalysisDefUse) { BuildDefUseManager(); } diff --git a/3rdparty/spirv-tools/source/opt/ir_context.h b/3rdparty/spirv-tools/source/opt/ir_context.h index 274dd14e2..946f9e9d0 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.h +++ b/3rdparty/spirv-tools/source/opt/ir_context.h @@ -867,8 +867,7 @@ inline IRContext::Analysis operator|(IRContext::Analysis lhs, inline IRContext::Analysis& operator|=(IRContext::Analysis& lhs, IRContext::Analysis rhs) { - lhs = static_cast(static_cast(lhs) | - static_cast(rhs)); + lhs = lhs | rhs; return lhs; } diff --git a/3rdparty/spirv-tools/source/opt/ir_loader.cpp b/3rdparty/spirv-tools/source/opt/ir_loader.cpp index a82b530e6..97db9d8f7 100644 --- a/3rdparty/spirv-tools/source/opt/ir_loader.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_loader.cpp @@ -189,7 +189,8 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { module_->SetMemoryModel(std::move(spv_inst)); } else if (opcode == SpvOpEntryPoint) { module_->AddEntryPoint(std::move(spv_inst)); - } else if (opcode == SpvOpExecutionMode) { + } else if (opcode == SpvOpExecutionMode || + opcode == SpvOpExecutionModeId) { module_->AddExecutionMode(std::move(spv_inst)); } else if (IsDebug1Inst(opcode)) { module_->AddDebug1Inst(std::move(spv_inst)); diff --git a/3rdparty/spirv-tools/source/opt/merge_return_pass.cpp b/3rdparty/spirv-tools/source/opt/merge_return_pass.cpp index a962a7ccb..7710deae2 100644 --- a/3rdparty/spirv-tools/source/opt/merge_return_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/merge_return_pass.cpp @@ -431,6 +431,7 @@ bool MergeReturnPass::BreakFromConstruct( std::list* order, Instruction* break_merge_inst) { // Make sure the CFG is build here. If we don't then it becomes very hard // to know which new blocks need to be updated. + context()->InvalidateAnalyses(IRContext::kAnalysisCFG); context()->BuildInvalidAnalyses(IRContext::kAnalysisCFG); // When predicating, be aware of whether this block is a header block, a diff --git a/3rdparty/spirv-tools/source/opt/types.cpp b/3rdparty/spirv-tools/source/opt/types.cpp index ea4baadbd..47abd4137 100644 --- a/3rdparty/spirv-tools/source/opt/types.cpp +++ b/3rdparty/spirv-tools/source/opt/types.cpp @@ -21,6 +21,7 @@ #include #include +#include "source/util/hash_combine.h" #include "source/util/make_unique.h" #include "spirv/unified1/spirv.h" @@ -28,6 +29,7 @@ namespace spvtools { namespace opt { namespace analysis { +using spvtools::utils::hash_combine; using U32VecVec = std::vector>; namespace { @@ -182,23 +184,26 @@ bool Type::operator==(const Type& other) const { } } -void Type::GetHashWords(std::vector* words, - std::unordered_set* seen) const { - if (!seen->insert(this).second) { - return; +size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const { + // Linear search through a dense, cache coherent vector is faster than O(log + // n) search in a complex data structure (eg std::set) for the generally small + // number of nodes. It also skips the overhead of an new/delete per Type + // (when inserting/removing from a set). + if (std::find(seen->begin(), seen->end(), this) != seen->end()) { + return hash; } - words->push_back(kind_); + seen->push_back(this); + + hash = hash_combine(hash, uint32_t(kind_)); for (const auto& d : decorations_) { - for (auto w : d) { - words->push_back(w); - } + hash = hash_combine(hash, d); } switch (kind_) { -#define DeclareKindCase(type) \ - case k##type: \ - As##type()->GetExtraHashWords(words, seen); \ +#define DeclareKindCase(type) \ + case k##type: \ + hash = As##type()->ComputeExtraStateHash(hash, seen); \ break DeclareKindCase(Void); DeclareKindCase(Bool); @@ -232,18 +237,13 @@ void Type::GetHashWords(std::vector* words, break; } - seen->erase(this); + seen->pop_back(); + return hash; } size_t Type::HashValue() const { - std::u32string h; - std::vector words; - GetHashWords(&words); - for (auto w : words) { - h.push_back(w); - } - - return std::hash()(h); + SeenTypes seen; + return ComputeHashValue(0, &seen); } bool Integer::IsSameImpl(const Type* that, IsSameCache*) const { @@ -258,10 +258,8 @@ std::string Integer::str() const { return oss.str(); } -void Integer::GetExtraHashWords(std::vector* words, - std::unordered_set*) const { - words->push_back(width_); - words->push_back(signed_); +size_t Integer::ComputeExtraStateHash(size_t hash, SeenTypes*) const { + return hash_combine(hash, width_, signed_); } bool Float::IsSameImpl(const Type* that, IsSameCache*) const { @@ -275,9 +273,8 @@ std::string Float::str() const { return oss.str(); } -void Float::GetExtraHashWords(std::vector* words, - std::unordered_set*) const { - words->push_back(width_); +size_t Float::ComputeExtraStateHash(size_t hash, SeenTypes*) const { + return hash_combine(hash, width_); } Vector::Vector(const Type* type, uint32_t count) @@ -299,10 +296,11 @@ std::string Vector::str() const { return oss.str(); } -void Vector::GetExtraHashWords(std::vector* words, - std::unordered_set* seen) const { - element_type_->GetHashWords(words, seen); - words->push_back(count_); +size_t Vector::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { + // prefer form that doesn't require push/pop from stack: add state and + // make tail call. + hash = hash_combine(hash, count_); + return element_type_->ComputeHashValue(hash, seen); } Matrix::Matrix(const Type* type, uint32_t count) @@ -324,10 +322,9 @@ std::string Matrix::str() const { return oss.str(); } -void Matrix::GetExtraHashWords(std::vector* words, - std::unordered_set* seen) const { - element_type_->GetHashWords(words, seen); - words->push_back(count_); +size_t Matrix::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { + hash = hash_combine(hash, count_); + return element_type_->ComputeHashValue(hash, seen); } Image::Image(Type* type, SpvDim dimen, uint32_t d, bool array, bool multisample, @@ -362,16 +359,10 @@ std::string Image::str() const { return oss.str(); } -void Image::GetExtraHashWords(std::vector* words, - std::unordered_set* seen) const { - sampled_type_->GetHashWords(words, seen); - words->push_back(dim_); - words->push_back(depth_); - words->push_back(arrayed_); - words->push_back(ms_); - words->push_back(sampled_); - words->push_back(format_); - words->push_back(access_qualifier_); +size_t Image::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { + hash = hash_combine(hash, uint32_t(dim_), depth_, arrayed_, ms_, sampled_, + uint32_t(format_), uint32_t(access_qualifier_)); + return sampled_type_->ComputeHashValue(hash, seen); } bool SampledImage::IsSameImpl(const Type* that, IsSameCache* seen) const { @@ -387,9 +378,8 @@ std::string SampledImage::str() const { return oss.str(); } -void SampledImage::GetExtraHashWords( - std::vector* words, std::unordered_set* seen) const { - image_type_->GetHashWords(words, seen); +size_t SampledImage::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { + return image_type_->ComputeHashValue(hash, seen); } Array::Array(const Type* type, const Array::LengthInfo& length_info_arg) @@ -422,11 +412,9 @@ std::string Array::str() const { return oss.str(); } -void Array::GetExtraHashWords(std::vector* words, - std::unordered_set* seen) const { - element_type_->GetHashWords(words, seen); - words->insert(words->end(), length_info_.words.begin(), - length_info_.words.end()); +size_t Array::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { + hash = hash_combine(hash, length_info_.words); + return element_type_->ComputeHashValue(hash, seen); } void Array::ReplaceElementType(const Type* type) { element_type_ = type; } @@ -449,9 +437,8 @@ std::string RuntimeArray::str() const { return oss.str(); } -void RuntimeArray::GetExtraHashWords( - std::vector* words, std::unordered_set* seen) const { - element_type_->GetHashWords(words, seen); +size_t RuntimeArray::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { + return element_type_->ComputeHashValue(hash, seen); } void RuntimeArray::ReplaceElementType(const Type* type) { @@ -508,19 +495,14 @@ std::string Struct::str() const { return oss.str(); } -void Struct::GetExtraHashWords(std::vector* words, - std::unordered_set* seen) const { +size_t Struct::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { for (auto* t : element_types_) { - t->GetHashWords(words, seen); + hash = t->ComputeHashValue(hash, seen); } for (const auto& pair : element_decorations_) { - words->push_back(pair.first); - for (const auto& d : pair.second) { - for (auto w : d) { - words->push_back(w); - } - } + hash = hash_combine(hash, pair.first, pair.second); } + return hash; } bool Opaque::IsSameImpl(const Type* that, IsSameCache*) const { @@ -535,11 +517,8 @@ std::string Opaque::str() const { return oss.str(); } -void Opaque::GetExtraHashWords(std::vector* words, - std::unordered_set*) const { - for (auto c : name_) { - words->push_back(static_cast(c)); - } +size_t Opaque::ComputeExtraStateHash(size_t hash, SeenTypes*) const { + return hash_combine(hash, name_); } Pointer::Pointer(const Type* type, SpvStorageClass sc) @@ -568,10 +547,9 @@ std::string Pointer::str() const { return os.str(); } -void Pointer::GetExtraHashWords(std::vector* words, - std::unordered_set* seen) const { - pointee_type_->GetHashWords(words, seen); - words->push_back(storage_class_); +size_t Pointer::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { + hash = hash_combine(hash, uint32_t(storage_class_)); + return pointee_type_->ComputeHashValue(hash, seen); } void Pointer::SetPointeeType(const Type* type) { pointee_type_ = type; } @@ -605,12 +583,11 @@ std::string Function::str() const { return oss.str(); } -void Function::GetExtraHashWords(std::vector* words, - std::unordered_set* seen) const { - return_type_->GetHashWords(words, seen); +size_t Function::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { for (const auto* t : param_types_) { - t->GetHashWords(words, seen); + hash = t->ComputeHashValue(hash, seen); } + return return_type_->ComputeHashValue(hash, seen); } void Function::SetReturnType(const Type* type) { return_type_ = type; } @@ -627,9 +604,8 @@ std::string Pipe::str() const { return oss.str(); } -void Pipe::GetExtraHashWords(std::vector* words, - std::unordered_set*) const { - words->push_back(access_qualifier_); +size_t Pipe::ComputeExtraStateHash(size_t hash, SeenTypes*) const { + return hash_combine(hash, uint32_t(access_qualifier_)); } bool ForwardPointer::IsSameImpl(const Type* that, IsSameCache*) const { @@ -652,11 +628,11 @@ std::string ForwardPointer::str() const { return oss.str(); } -void ForwardPointer::GetExtraHashWords( - std::vector* words, std::unordered_set* seen) const { - words->push_back(target_id_); - words->push_back(storage_class_); - if (pointer_) pointer_->GetHashWords(words, seen); +size_t ForwardPointer::ComputeExtraStateHash(size_t hash, + SeenTypes* seen) const { + hash = hash_combine(hash, target_id_, uint32_t(storage_class_)); + if (pointer_) hash = pointer_->ComputeHashValue(hash, seen); + return hash; } CooperativeMatrixNV::CooperativeMatrixNV(const Type* type, const uint32_t scope, @@ -680,12 +656,10 @@ std::string CooperativeMatrixNV::str() const { return oss.str(); } -void CooperativeMatrixNV::GetExtraHashWords( - std::vector* words, std::unordered_set* pSet) const { - component_type_->GetHashWords(words, pSet); - words->push_back(scope_id_); - words->push_back(rows_id_); - words->push_back(columns_id_); +size_t CooperativeMatrixNV::ComputeExtraStateHash(size_t hash, + SeenTypes* seen) const { + hash = hash_combine(hash, scope_id_, rows_id_, columns_id_); + return component_type_->ComputeHashValue(hash, seen); } bool CooperativeMatrixNV::IsSameImpl(const Type* that, diff --git a/3rdparty/spirv-tools/source/opt/types.h b/3rdparty/spirv-tools/source/opt/types.h index d68da2222..01e8f3cd5 100644 --- a/3rdparty/spirv-tools/source/opt/types.h +++ b/3rdparty/spirv-tools/source/opt/types.h @@ -28,6 +28,7 @@ #include "source/latest_version_spirv_header.h" #include "source/opt/instruction.h" +#include "source/util/small_vector.h" #include "spirv-tools/libspirv.h" namespace spvtools { @@ -67,6 +68,8 @@ class Type { public: typedef std::set> IsSameCache; + using SeenTypes = spvtools::utils::SmallVector; + // Available subtypes. // // When adding a new derived class of Type, please add an entry to the enum. @@ -155,21 +158,7 @@ class Type { // Returns the hash value of this type. size_t HashValue() const; - // Adds the necessary words to compute a hash value of this type to |words|. - void GetHashWords(std::vector* words) const { - std::unordered_set seen; - GetHashWords(words, &seen); - } - - // Adds the necessary words to compute a hash value of this type to |words|. - void GetHashWords(std::vector* words, - std::unordered_set* seen) const; - - // Adds necessary extra words for a subtype to calculate a hash value into - // |words|. - virtual void GetExtraHashWords( - std::vector* words, - std::unordered_set* pSet) const = 0; + size_t ComputeHashValue(size_t hash, SeenTypes* seen) const; // A bunch of methods for casting this type to a given type. Returns this if the // cast can be done, nullptr otherwise. @@ -205,6 +194,10 @@ class Type { DeclareCastMethod(RayQueryKHR) #undef DeclareCastMethod +protected: + // Add any type-specific state to |hash| and returns new hash. + virtual size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const = 0; + protected: // Decorations attached to this type. Each decoration is encoded as a vector // of uint32_t numbers. The first uint32_t number is the decoration value, @@ -233,8 +226,7 @@ class Integer : public Type { uint32_t width() const { return width_; } bool IsSigned() const { return signed_; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -254,8 +246,7 @@ class Float : public Type { const Float* AsFloat() const override { return this; } uint32_t width() const { return width_; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -275,8 +266,7 @@ class Vector : public Type { Vector* AsVector() override { return this; } const Vector* AsVector() const override { return this; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -297,8 +287,7 @@ class Matrix : public Type { Matrix* AsMatrix() override { return this; } const Matrix* AsMatrix() const override { return this; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -328,8 +317,7 @@ class Image : public Type { SpvImageFormat format() const { return format_; } SpvAccessQualifier access_qualifier() const { return access_qualifier_; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -356,8 +344,7 @@ class SampledImage : public Type { const Type* image_type() const { return image_type_; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -400,8 +387,7 @@ class Array : public Type { Array* AsArray() override { return this; } const Array* AsArray() const override { return this; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; void ReplaceElementType(const Type* element_type); @@ -423,8 +409,7 @@ class RuntimeArray : public Type { RuntimeArray* AsRuntimeArray() override { return this; } const RuntimeArray* AsRuntimeArray() const override { return this; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; void ReplaceElementType(const Type* element_type); @@ -460,8 +445,7 @@ class Struct : public Type { Struct* AsStruct() override { return this; } const Struct* AsStruct() const override { return this; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -492,8 +476,7 @@ class Opaque : public Type { const std::string& name() const { return name_; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -513,8 +496,7 @@ class Pointer : public Type { Pointer* AsPointer() override { return this; } const Pointer* AsPointer() const override { return this; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; void SetPointeeType(const Type* type); @@ -540,8 +522,7 @@ class Function : public Type { const std::vector& param_types() const { return param_types_; } std::vector& param_types() { return param_types_; } - void GetExtraHashWords(std::vector* words, - std::unordered_set*) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; void SetReturnType(const Type* type); @@ -565,8 +546,7 @@ class Pipe : public Type { SpvAccessQualifier access_qualifier() const { return access_qualifier_; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -593,8 +573,7 @@ class ForwardPointer : public Type { ForwardPointer* AsForwardPointer() override { return this; } const ForwardPointer* AsForwardPointer() const override { return this; } - void GetExtraHashWords(std::vector* words, - std::unordered_set* pSet) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; private: bool IsSameImpl(const Type* that, IsSameCache*) const override; @@ -617,8 +596,7 @@ class CooperativeMatrixNV : public Type { return this; } - void GetExtraHashWords(std::vector*, - std::unordered_set*) const override; + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; const Type* component_type() const { return component_type_; } uint32_t scope_id() const { return scope_id_; } @@ -634,24 +612,25 @@ class CooperativeMatrixNV : public Type { const uint32_t columns_id_; }; -#define DefineParameterlessType(type, name) \ - class type : public Type { \ - public: \ - type() : Type(k##type) {} \ - type(const type&) = default; \ - \ - std::string str() const override { return #name; } \ - \ - type* As##type() override { return this; } \ - const type* As##type() const override { return this; } \ - \ - void GetExtraHashWords(std::vector*, \ - std::unordered_set*) const override {} \ - \ - private: \ - bool IsSameImpl(const Type* that, IsSameCache*) const override { \ - return that->As##type() && HasSameDecorations(that); \ - } \ +#define DefineParameterlessType(type, name) \ + class type : public Type { \ + public: \ + type() : Type(k##type) {} \ + type(const type&) = default; \ + \ + std::string str() const override { return #name; } \ + \ + type* As##type() override { return this; } \ + const type* As##type() const override { return this; } \ + \ + size_t ComputeExtraStateHash(size_t hash, SeenTypes*) const override { \ + return hash; \ + } \ + \ + private: \ + bool IsSameImpl(const Type* that, IsSameCache*) const override { \ + return that->As##type() && HasSameDecorations(that); \ + } \ } DefineParameterlessType(Void, void); DefineParameterlessType(Bool, bool); diff --git a/3rdparty/spirv-tools/source/util/hash_combine.h b/3rdparty/spirv-tools/source/util/hash_combine.h new file mode 100644 index 000000000..1a2dbc332 --- /dev/null +++ b/3rdparty/spirv-tools/source/util/hash_combine.h @@ -0,0 +1,53 @@ +// Copyright (c) 2022 The Khronos Group Inc. +// +// 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. + +#ifndef SOURCE_UTIL_HASH_COMBINE_H_ +#define SOURCE_UTIL_HASH_COMBINE_H_ + +#include +#include +#include + +namespace spvtools { +namespace utils { + +// Helpers for incrementally computing hashes. +// For reference, see +// http://open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf + +template +inline size_t hash_combine(std::size_t seed, const T& val) { + return seed ^ (std::hash()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); +} + +template +inline size_t hash_combine(std::size_t hash, const std::vector& vals) { + for (const T& val : vals) { + hash = hash_combine(hash, val); + } + return hash; +} + +inline size_t hash_combine(std::size_t hash) { return hash; } + +template +inline size_t hash_combine(std::size_t hash, const T& val, + const Types&... args) { + return hash_combine(hash_combine(hash, val), args...); +} + +} // namespace utils +} // namespace spvtools + +#endif // SOURCE_UTIL_HASH_COMBINE_H_ diff --git a/3rdparty/spirv-tools/source/util/pooled_linked_list.h b/3rdparty/spirv-tools/source/util/pooled_linked_list.h new file mode 100644 index 000000000..faaa4c44e --- /dev/null +++ b/3rdparty/spirv-tools/source/util/pooled_linked_list.h @@ -0,0 +1,236 @@ +// Copyright (c) 2021 The Khronos Group Inc. +// +// 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. + +#ifndef SOURCE_UTIL_POOLED_LINKED_LIST_H_ +#define SOURCE_UTIL_POOLED_LINKED_LIST_H_ + +#include +#include + +namespace spvtools { +namespace utils { + +// Shared storage of nodes for PooledLinkedList. +template +class PooledLinkedListNodes { + public: + struct Node { + Node(T e, int32_t n = -1) : element(e), next(n) {} + + T element = {}; + int32_t next = -1; + }; + + PooledLinkedListNodes() = default; + PooledLinkedListNodes(const PooledLinkedListNodes&) = delete; + PooledLinkedListNodes& operator=(const PooledLinkedListNodes&) = delete; + + PooledLinkedListNodes(PooledLinkedListNodes&& that) { + *this = std::move(that); + } + + PooledLinkedListNodes& operator=(PooledLinkedListNodes&& that) { + vec_ = std::move(that.vec_); + free_nodes_ = that.free_nodes_; + return *this; + } + + size_t total_nodes() { return vec_.size(); } + size_t free_nodes() { return free_nodes_; } + size_t used_nodes() { return total_nodes() - free_nodes(); } + + private: + template + friend class PooledLinkedList; + + Node& at(int32_t index) { return vec_[index]; } + const Node& at(int32_t index) const { return vec_[index]; } + + int32_t insert(T element) { + int32_t index = int32_t(vec_.size()); + vec_.emplace_back(element); + return index; + } + + std::vector vec_; + size_t free_nodes_ = 0; +}; + +// Implements a linked-list where list nodes come from a shared pool. This is +// meant to be used in scenarios where it is desirable to avoid many small +// allocations. +// +// Instead of pointers, the list uses indices to allow the underlying storage +// to be modified without needing to modify the list. When removing elements +// from the list, nodes are not deleted or recycled: to reclaim unused space, +// perform a sequence of |move_nodes| operations into a temporary pool, which +// then is moved into the old pool. +// +// This does *not* attempt to implement a full stl-compatible interface. +template +class PooledLinkedList { + public: + using NodePool = PooledLinkedListNodes; + using Node = typename NodePool::Node; + + PooledLinkedList() = delete; + PooledLinkedList(NodePool* nodes) : nodes_(nodes) {} + + // Shared iterator implementation (for iterator and const_iterator). + template + class iterator_base { + public: + iterator_base(const iterator_base& i) + : nodes_(i.nodes_), index_(i.index_) {} + + iterator_base& operator++() { + index_ = nodes_->at(index_).next; + return *this; + } + + iterator_base& operator=(const iterator_base& i) { + nodes_ = i.nodes_; + index_ = i.index_; + return *this; + } + + ElementT& operator*() const { return nodes_->at(index_).element; } + ElementT* operator->() const { return &nodes_->at(index_).element; } + + friend inline bool operator==(const iterator_base& lhs, + const iterator_base& rhs) { + return lhs.nodes_ == rhs.nodes_ && lhs.index_ == rhs.index_; + } + friend inline bool operator!=(const iterator_base& lhs, + const iterator_base& rhs) { + return lhs.nodes_ != rhs.nodes_ || lhs.index_ != rhs.index_; + } + + // Define standard iterator types needs so this class can be + // used with . + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = ElementT; + using pointer = ElementT*; + using const_pointer = const ElementT*; + using reference = ElementT&; + using const_reference = const ElementT&; + using size_type = size_t; + + private: + friend PooledLinkedList; + + iterator_base(PoolT* pool, int32_t index) : nodes_(pool), index_(index) {} + + PoolT* nodes_; + int32_t index_ = -1; + }; + + using iterator = iterator_base>; + using const_iterator = iterator_base>; + + bool empty() const { return head_ == -1; } + + T& front() { return nodes_->at(head_).element; } + T& back() { return nodes_->at(tail_).element; } + const T& front() const { return nodes_->at(head_).element; } + const T& back() const { return nodes_->at(tail_).element; } + + iterator begin() { return iterator(&nodes_->vec_, head_); } + iterator end() { return iterator(&nodes_->vec_, -1); } + const_iterator begin() const { return const_iterator(&nodes_->vec_, head_); } + const_iterator end() const { return const_iterator(&nodes_->vec_, -1); } + + // Inserts |element| at the back of the list. + void push_back(T element) { + int32_t new_tail = nodes_->insert(element); + if (head_ == -1) { + head_ = new_tail; + tail_ = new_tail; + } else { + nodes_->at(tail_).next = new_tail; + tail_ = new_tail; + } + } + + // Removes the first occurrence of |element| from the list. + // Returns if |element| was removed. + bool remove_first(T element) { + int32_t* prev_next = &head_; + for (int32_t prev_index = -1, index = head_; index != -1; /**/) { + auto& node = nodes_->at(index); + if (node.element == element) { + // Snip from of the list, optionally fixing up tail pointer. + if (tail_ == index) { + assert(node.next == -1); + tail_ = prev_index; + } + *prev_next = node.next; + nodes_->free_nodes_++; + return true; + } else { + prev_next = &node.next; + } + prev_index = index; + index = node.next; + } + return false; + } + + // Returns the PooledLinkedListNodes that owns this list's nodes. + NodePool* pool() { return nodes_; } + + // Moves the nodes in this list into |new_pool|, providing a way to compact + // storage and reclaim unused space. + // + // Upon completing a sequence of |move_nodes| calls, you must ensure you + // retain ownership of the new storage your lists point to. Example usage: + // + // unique_ptr new_pool = ...; + // for (PooledLinkedList& list : lists) { + // list.move_to(new_pool); + // } + // my_pool_ = std::move(new_pool); + void move_nodes(NodePool* new_pool) { + // Be sure to construct the list in the same order, instead of simply + // doing a sequence of push_backs. + int32_t prev_entry = -1; + int32_t nodes_freed = 0; + for (int32_t index = head_; index != -1; nodes_freed++) { + const auto& node = nodes_->at(index); + int32_t this_entry = new_pool->insert(node.element); + index = node.next; + if (prev_entry == -1) { + head_ = this_entry; + } else { + new_pool->at(prev_entry).next = this_entry; + } + prev_entry = this_entry; + } + tail_ = prev_entry; + // Update our old pool's free count, now we're a member of the new pool. + nodes_->free_nodes_ += nodes_freed; + nodes_ = new_pool; + } + + private: + NodePool* nodes_; + int32_t head_ = -1; + int32_t tail_ = -1; +}; + +} // namespace utils +} // namespace spvtools + +#endif // SOURCE_UTIL_POOLED_LINKED_LIST_H_ \ No newline at end of file diff --git a/3rdparty/spirv-tools/source/util/small_vector.h b/3rdparty/spirv-tools/source/util/small_vector.h index 4e8e0fd04..648a34824 100644 --- a/3rdparty/spirv-tools/source/util/small_vector.h +++ b/3rdparty/spirv-tools/source/util/small_vector.h @@ -333,6 +333,15 @@ class SmallVector { ++size_; } + void pop_back() { + if (large_data_) { + large_data_->pop_back(); + } else { + --size_; + small_data_[size_].~T(); + } + } + template iterator insert(iterator pos, InputIt first, InputIt last) { size_t element_idx = (pos - begin()); diff --git a/3rdparty/spirv-tools/source/val/validate_extensions.cpp b/3rdparty/spirv-tools/source/val/validate_extensions.cpp index f1e0ab999..fcf04e207 100644 --- a/3rdparty/spirv-tools/source/val/validate_extensions.cpp +++ b/3rdparty/spirv-tools/source/val/validate_extensions.cpp @@ -147,6 +147,24 @@ bool DoesDebugInfoOperandMatchExpectation( return true; } +// Overload for NonSemanticShaderDebugInfo100Instructions. +bool DoesDebugInfoOperandMatchExpectation( + const ValidationState_t& _, + const std::function& + expectation, + const Instruction* inst, uint32_t word_index) { + if (inst->words().size() <= word_index) return false; + auto* debug_inst = _.FindDef(inst->word(word_index)); + if (debug_inst->opcode() != SpvOpExtInst || + (debug_inst->ext_inst_type() != + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) || + !expectation( + NonSemanticShaderDebugInfo100Instructions(debug_inst->word(4)))) { + return false; + } + return true; +} + // Check that the operand of a debug info instruction |inst| at |word_index| // is a result id of an debug info instruction whose debug instruction type // is |expected_debug_inst|. @@ -223,6 +241,18 @@ spv_result_t ValidateOperandDebugType( const Instruction* inst, uint32_t word_index, const std::function& ext_inst_name, bool allow_template_param) { + // Check for NonSemanticShaderDebugInfo100 specific types. + if (inst->ext_inst_type() == + SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { + std::function expectation = + [](NonSemanticShaderDebugInfo100Instructions dbg_inst) { + return dbg_inst == NonSemanticShaderDebugInfo100DebugTypeMatrix; + }; + if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index)) + return SPV_SUCCESS; + } + + // Check for common types. std::function expectation = [&allow_template_param](CommonDebugInfoInstructions dbg_inst) { if (allow_template_param && @@ -2719,6 +2749,86 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { auto num_words = inst->words().size(); + // Handle any non-common NonSemanticShaderDebugInfo instructions. + if (vulkanDebugInfo) { + const NonSemanticShaderDebugInfo100Instructions ext_inst_key = + NonSemanticShaderDebugInfo100Instructions(ext_inst_index); + switch (ext_inst_key) { + // The following block of instructions will be handled by the common + // validation. + case NonSemanticShaderDebugInfo100DebugInfoNone: + case NonSemanticShaderDebugInfo100DebugCompilationUnit: + case NonSemanticShaderDebugInfo100DebugTypeBasic: + case NonSemanticShaderDebugInfo100DebugTypePointer: + case NonSemanticShaderDebugInfo100DebugTypeQualifier: + case NonSemanticShaderDebugInfo100DebugTypeArray: + case NonSemanticShaderDebugInfo100DebugTypeVector: + case NonSemanticShaderDebugInfo100DebugTypedef: + case NonSemanticShaderDebugInfo100DebugTypeFunction: + case NonSemanticShaderDebugInfo100DebugTypeEnum: + case NonSemanticShaderDebugInfo100DebugTypeComposite: + case NonSemanticShaderDebugInfo100DebugTypeMember: + case NonSemanticShaderDebugInfo100DebugTypeInheritance: + case NonSemanticShaderDebugInfo100DebugTypePtrToMember: + case NonSemanticShaderDebugInfo100DebugTypeTemplate: + case NonSemanticShaderDebugInfo100DebugTypeTemplateParameter: + case NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter: + case NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack: + case NonSemanticShaderDebugInfo100DebugGlobalVariable: + case NonSemanticShaderDebugInfo100DebugFunctionDeclaration: + case NonSemanticShaderDebugInfo100DebugFunction: + case NonSemanticShaderDebugInfo100DebugLexicalBlock: + case NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator: + case NonSemanticShaderDebugInfo100DebugScope: + case NonSemanticShaderDebugInfo100DebugNoScope: + case NonSemanticShaderDebugInfo100DebugInlinedAt: + case NonSemanticShaderDebugInfo100DebugLocalVariable: + case NonSemanticShaderDebugInfo100DebugInlinedVariable: + case NonSemanticShaderDebugInfo100DebugDeclare: + case NonSemanticShaderDebugInfo100DebugValue: + case NonSemanticShaderDebugInfo100DebugOperation: + case NonSemanticShaderDebugInfo100DebugExpression: + case NonSemanticShaderDebugInfo100DebugMacroDef: + case NonSemanticShaderDebugInfo100DebugMacroUndef: + case NonSemanticShaderDebugInfo100DebugImportedEntity: + case NonSemanticShaderDebugInfo100DebugSource: + break; + case NonSemanticShaderDebugInfo100DebugTypeMatrix: { + CHECK_DEBUG_OPERAND("Vector Type", CommonDebugInfoDebugTypeVector, 5); + + CHECK_CONST_UINT_OPERAND("Vector Count", 6); + + uint32_t vector_count = inst->word(6); + uint64_t const_val; + if (!_.GetConstantValUint64(vector_count, &const_val)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() + << ": Vector Count must be 32-bit integer OpConstant"; + } + + vector_count = const_val & 0xffffffff; + if (!vector_count || vector_count > 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": Vector Count must be positive " + << "integer less than or equal to 4"; + } + break; + } + // TODO: Add validation rules for remaining cases as well. + case NonSemanticShaderDebugInfo100DebugFunctionDefinition: + case NonSemanticShaderDebugInfo100DebugSourceContinued: + case NonSemanticShaderDebugInfo100DebugLine: + case NonSemanticShaderDebugInfo100DebugNoLine: + case NonSemanticShaderDebugInfo100DebugBuildIdentifier: + case NonSemanticShaderDebugInfo100DebugStoragePath: + case NonSemanticShaderDebugInfo100DebugEntryPoint: + break; + case NonSemanticShaderDebugInfo100InstructionsMax: + assert(0); + break; + } + } + // Handle any non-common OpenCL insts, then common if (ext_inst_type != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || OpenCLDebugInfo100Instructions(ext_inst_index) != diff --git a/3rdparty/spirv-tools/source/val/validate_memory.cpp b/3rdparty/spirv-tools/source/val/validate_memory.cpp index 93b180004..4f3d9cdb7 100644 --- a/3rdparty/spirv-tools/source/val/validate_memory.cpp +++ b/3rdparty/spirv-tools/source/val/validate_memory.cpp @@ -596,23 +596,23 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } } - } - // Vulkan Appendix A: Check that if contains initializer, then - // storage class is Output, Private, or Function. - if (inst->operands().size() > 3 && storage_class != SpvStorageClassOutput && - storage_class != SpvStorageClassPrivate && - storage_class != SpvStorageClassFunction) { - if (spvIsVulkanEnv(_.context()->target_env)) { + // Initializers in Vulkan are only allowed in some storage clases + if (inst->operands().size() > 3) { if (storage_class == SpvStorageClassWorkgroup) { auto init_id = inst->GetOperandAs(3); auto init = _.FindDef(init_id); if (init->opcode() != SpvOpConstantNull) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Variable initializers in Workgroup storage class are " - "limited to OpConstantNull"; + << _.VkErrorID(4734) << "OpVariable, '" + << _.getIdName(inst->id()) + << "', initializers are limited to OpConstantNull in " + "Workgroup " + "storage class"; } - } else { + } else if (storage_class != SpvStorageClassOutput && + storage_class != SpvStorageClassPrivate && + storage_class != SpvStorageClassFunction) { return _.diag(SPV_ERROR_INVALID_ID, inst) << _.VkErrorID(4651) << "OpVariable, '" << _.getIdName(inst->id()) diff --git a/3rdparty/spirv-tools/source/val/validation_state.cpp b/3rdparty/spirv-tools/source/val/validation_state.cpp index 6f97321f2..6c170760f 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.cpp +++ b/3rdparty/spirv-tools/source/val/validation_state.cpp @@ -1882,6 +1882,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04732); case 4733: return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733); + case 4734: + return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04734); case 4780: return VUID_WRAP(VUID-StandaloneSpirv-Result-04780); case 4915: