diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 7252aa274..80a13df1e 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2021.3-dev", "SPIRV-Tools v2021.3-dev 25ef0e5c8566c2abe88852e3b72e0facccbbbcb9" +"v2021.3-dev", "SPIRV-Tools v2021.3-dev 39e3d51fa1194e78df5376072164455270154b39" diff --git a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc index 77fdff6ec..88c578b20 100644 --- a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc @@ -44,6 +44,7 @@ static const SpvCapability pygen_variable_caps_Pipes[] = {SpvCapabilityPipes}; static const SpvCapability pygen_variable_caps_RayQueryKHR[] = {SpvCapabilityRayQueryKHR}; static const SpvCapability pygen_variable_caps_RayTracingKHR[] = {SpvCapabilityRayTracingKHR}; static const SpvCapability pygen_variable_caps_RayTracingKHRRayQueryKHR[] = {SpvCapabilityRayTracingKHR, SpvCapabilityRayQueryKHR}; +static const SpvCapability pygen_variable_caps_RayTracingMotionBlurNV[] = {SpvCapabilityRayTracingMotionBlurNV}; static const SpvCapability pygen_variable_caps_RayTracingNV[] = {SpvCapabilityRayTracingNV}; static const SpvCapability pygen_variable_caps_RayTracingNVRayTracingKHR[] = {SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR}; static const SpvCapability pygen_variable_caps_RayTracingNVRayTracingKHRRayQueryKHR[] = {SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR, SpvCapabilityRayQueryKHR}; @@ -90,6 +91,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shader[] = {spv static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing}; static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing, spvtools::Extension::kSPV_KHR_ray_tracing}; static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query[] = {spvtools::Extension::kSPV_NV_ray_tracing, spvtools::Extension::kSPV_KHR_ray_tracing, spvtools::Extension::kSPV_KHR_ray_query}; +static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing_motion_blur[] = {spvtools::Extension::kSPV_NV_ray_tracing_motion_blur}; static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_image_footprint[] = {spvtools::Extension::kSPV_NV_shader_image_footprint}; static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_subgroup_partitioned[] = {spvtools::Extension::kSPV_NV_shader_subgroup_partitioned}; @@ -482,6 +484,8 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"IgnoreIntersectionNV", SpvOpIgnoreIntersectionNV, 1, pygen_variable_caps_RayTracingNV, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu}, {"TerminateRayNV", SpvOpTerminateRayNV, 1, pygen_variable_caps_RayTracingNV, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu}, {"TraceNV", SpvOpTraceNV, 1, pygen_variable_caps_RayTracingNV, 11, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu}, + {"TraceMotionNV", SpvOpTraceMotionNV, 1, pygen_variable_caps_RayTracingMotionBlurNV, 12, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, 0xffffffffu, 0xffffffffu}, + {"TraceRayMotionNV", SpvOpTraceRayMotionNV, 1, pygen_variable_caps_RayTracingMotionBlurNV, 12, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, 0xffffffffu, 0xffffffffu}, {"TypeAccelerationStructureKHR", SpvOpTypeAccelerationStructureKHR, 3, pygen_variable_caps_RayTracingNVRayTracingKHRRayQueryKHR, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 3, pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query, 0xffffffffu, 0xffffffffu}, {"TypeAccelerationStructureNV", SpvOpTypeAccelerationStructureNV, 3, pygen_variable_caps_RayTracingNVRayTracingKHRRayQueryKHR, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 3, pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query, 0xffffffffu, 0xffffffffu}, {"ExecuteCallableNV", SpvOpExecuteCallableNV, 1, pygen_variable_caps_RayTracingNV, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu}, @@ -693,7 +697,6 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"ArbitraryFloatPowINTEL", SpvOpArbitraryFloatPowINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 10, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"ArbitraryFloatPowRINTEL", SpvOpArbitraryFloatPowRINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 10, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"ArbitraryFloatPowNINTEL", SpvOpArbitraryFloatPowNINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, - {"ArbitraryFloatPowNINTEL", SpvOpArbitraryFloatPowNINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"LoopControlINTEL", SpvOpLoopControlINTEL, 1, pygen_variable_caps_UnstructuredLoopControlsINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER}, 0, 0, 1, pygen_variable_exts_SPV_INTEL_unstructured_loop_controls, 0xffffffffu, 0xffffffffu}, {"FixedSqrtINTEL", SpvOpFixedSqrtINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"FixedRecipINTEL", SpvOpFixedRecipINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, diff --git a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc index ec3226f80..9b7aba927 100644 --- a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc +++ b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc @@ -174,6 +174,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_NV_mesh_shader"; case Extension::kSPV_NV_ray_tracing: return "SPV_NV_ray_tracing"; + case Extension::kSPV_NV_ray_tracing_motion_blur: + return "SPV_NV_ray_tracing_motion_blur"; case Extension::kSPV_NV_sample_mask_override_coverage: return "SPV_NV_sample_mask_override_coverage"; case Extension::kSPV_NV_shader_image_footprint: @@ -197,8 +199,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_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_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_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_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_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_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_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_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_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_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_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_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_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_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( @@ -476,6 +478,8 @@ const char* CapabilityToString(SpvCapability capability) { return "StorageTexelBufferArrayNonUniformIndexing"; case SpvCapabilityRayTracingNV: return "RayTracingNV"; + case SpvCapabilityRayTracingMotionBlurNV: + return "RayTracingMotionBlurNV"; case SpvCapabilityVulkanMemoryModel: return "VulkanMemoryModel"; case SpvCapabilityVulkanMemoryModelDeviceScope: diff --git a/3rdparty/spirv-tools/include/generated/extension_enum.inc b/3rdparty/spirv-tools/include/generated/extension_enum.inc index 399471bf2..8499ab6fa 100644 --- a/3rdparty/spirv-tools/include/generated/extension_enum.inc +++ b/3rdparty/spirv-tools/include/generated/extension_enum.inc @@ -85,6 +85,7 @@ kSPV_NV_fragment_shader_barycentric, kSPV_NV_geometry_shader_passthrough, kSPV_NV_mesh_shader, kSPV_NV_ray_tracing, +kSPV_NV_ray_tracing_motion_blur, kSPV_NV_sample_mask_override_coverage, kSPV_NV_shader_image_footprint, kSPV_NV_shader_sm_builtins, diff --git a/3rdparty/spirv-tools/include/generated/generators.inc b/3rdparty/spirv-tools/include/generated/generators.inc index 43ed6e9ab..91fc0922e 100644 --- a/3rdparty/spirv-tools/include/generated/generators.inc +++ b/3rdparty/spirv-tools/include/generated/generators.inc @@ -17,7 +17,7 @@ {16, "X-LEGEND", "Mesa-IR/SPIR-V Translator", "X-LEGEND Mesa-IR/SPIR-V Translator"}, {17, "Khronos", "SPIR-V Tools Linker", "Khronos SPIR-V Tools Linker"}, {18, "Wine", "VKD3D Shader Compiler", "Wine VKD3D Shader Compiler"}, -{19, "Clay", "Clay Shader Compiler", "Clay Clay Shader Compiler"}, +{19, "Tellusim", "Clay Shader Compiler", "Tellusim Clay Shader Compiler"}, {20, "W3C WebGPU Group", "WHLSL Shader Translator", "W3C WebGPU Group WHLSL Shader Translator"}, {21, "Google", "Clspv", "Google Clspv"}, {22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"}, diff --git a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc index fc09e2d81..dfce4a2e3 100644 --- a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc @@ -64,12 +64,14 @@ static const SpvCapability pygen_variable_caps_MinLod[] = {SpvCapabilityMinLod}; static const SpvCapability pygen_variable_caps_MultiView[] = {SpvCapabilityMultiView}; static const SpvCapability pygen_variable_caps_MultiViewport[] = {SpvCapabilityMultiViewport}; static const SpvCapability pygen_variable_caps_MultiViewportShaderViewportIndexShaderViewportIndexLayerEXTMeshShadingNV[] = {SpvCapabilityMultiViewport, SpvCapabilityShaderViewportIndex, SpvCapabilityShaderViewportIndexLayerEXT, SpvCapabilityMeshShadingNV}; +static const SpvCapability pygen_variable_caps_OptNoneINTEL[] = {SpvCapabilityOptNoneINTEL}; static const SpvCapability pygen_variable_caps_PerViewAttributesNVMeshShadingNV[] = {SpvCapabilityPerViewAttributesNV, SpvCapabilityMeshShadingNV}; static const SpvCapability pygen_variable_caps_PhysicalStorageBufferAddresses[] = {SpvCapabilityPhysicalStorageBufferAddresses}; static const SpvCapability pygen_variable_caps_Pipes[] = {SpvCapabilityPipes}; static const SpvCapability pygen_variable_caps_RayQueryKHR[] = {SpvCapabilityRayQueryKHR}; static const SpvCapability pygen_variable_caps_RayQueryKHRRayTracingKHR[] = {SpvCapabilityRayQueryKHR, SpvCapabilityRayTracingKHR}; static const SpvCapability pygen_variable_caps_RayTracingKHR[] = {SpvCapabilityRayTracingKHR}; +static const SpvCapability pygen_variable_caps_RayTracingMotionBlurNV[] = {SpvCapabilityRayTracingMotionBlurNV}; static const SpvCapability pygen_variable_caps_RayTracingNV[] = {SpvCapabilityRayTracingNV}; static const SpvCapability pygen_variable_caps_RayTracingNVRayTracingKHR[] = {SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR}; static const SpvCapability pygen_variable_caps_RayTraversalPrimitiveCullingKHR[] = {SpvCapabilityRayTraversalPrimitiveCullingKHR}; @@ -199,6 +201,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_geometry_shader_pass static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shader[] = {spvtools::Extension::kSPV_NV_mesh_shader}; static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shaderSPV_NV_viewport_array2[] = {spvtools::Extension::kSPV_NV_mesh_shader, spvtools::Extension::kSPV_NV_viewport_array2}; static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing}; +static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing_motion_blur[] = {spvtools::Extension::kSPV_NV_ray_tracing_motion_blur}; static const spvtools::Extension pygen_variable_exts_SPV_NV_sample_mask_override_coverage[] = {spvtools::Extension::kSPV_NV_sample_mask_override_coverage}; static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_image_footprint[] = {spvtools::Extension::kSPV_NV_shader_image_footprint}; static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_sm_builtins[] = {spvtools::Extension::kSPV_NV_shader_sm_builtins}; @@ -272,7 +275,7 @@ static const spv_operand_desc_t pygen_variable_FunctionControlEntries[] = { {"DontInline", 0x0002, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Pure", 0x0004, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Const", 0x0008, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"OptNoneINTEL", 0x10000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"OptNoneINTEL", 0x10000, 1, pygen_variable_caps_OptNoneINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_MemorySemanticsEntries[] = { @@ -876,6 +879,7 @@ static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = { {"HitTNV", 5332, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, {"HitKindNV", 5333, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, {"HitKindKHR", 5333, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"CurrentRayTimeNV", 5334, 1, pygen_variable_caps_RayTracingMotionBlurNV, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, {}, 0xffffffffu, 0xffffffffu}, {"IncomingRayFlagsNV", 5351, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, {"IncomingRayFlagsKHR", 5351, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, {"RayGeometryIndexKHR", 5352, 1, pygen_variable_caps_RayTracingKHR, 1, pygen_variable_exts_SPV_KHR_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, @@ -1060,6 +1064,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"StorageTexelBufferArrayNonUniformIndexing", 5312, 2, pygen_variable_caps_ImageBufferShaderNonUniform, 1, pygen_variable_exts_SPV_EXT_descriptor_indexing, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, {"StorageTexelBufferArrayNonUniformIndexingEXT", 5312, 2, pygen_variable_caps_ImageBufferShaderNonUniform, 1, pygen_variable_exts_SPV_EXT_descriptor_indexing, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, {"RayTracingNV", 5340, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"RayTracingMotionBlurNV", 5341, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, {}, 0xffffffffu, 0xffffffffu}, {"VulkanMemoryModel", 5345, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, {"VulkanMemoryModelKHR", 5345, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, {"VulkanMemoryModelDeviceScope", 5346, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index 700f59f70..b1442dcf0 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "libspirv.hpp" @@ -27,6 +28,7 @@ namespace spvtools { namespace opt { class Pass; +struct DescriptorSetAndBinding; } // C++ interface for SPIR-V optimization functionalities. It wraps the context @@ -854,6 +856,16 @@ Optimizer::PassToken CreateAmdExtToKhrPass(); // propagated into their final positions. Optimizer::PassToken CreateInterpolateFixupPass(); +// Creates a convert-to-sampled-image pass to convert images and/or +// samplers with given pairs of descriptor set and binding to sampled image. +// If a pair of an image and a sampler have the same pair of descriptor set and +// binding that is one of the given pairs, they will be converted to a sampled +// image. In addition, if only an image has the descriptor set and binding that +// is one of the given pairs, it will be converted to a sampled image as well. +Optimizer::PassToken CreateConvertToSampledImagePass( + const std::vector& + descriptor_set_binding_pairs); + } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp b/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp index d262a7eca..515a3ed5d 100644 --- a/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp +++ b/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp @@ -1002,7 +1002,7 @@ const analysis::Constant* FoldClamp1( "Expecting a GLSLstd450 extended instruction."); // Make sure all Clamp operands are constants. - for (uint32_t i = 1; i < 3; i++) { + for (uint32_t i = 1; i < 4; i++) { if (constants[i] == nullptr) { return nullptr; } @@ -1017,7 +1017,7 @@ const analysis::Constant* FoldClamp1( context); } -// Fold a clamp instruction when |x >= min_val|. +// Fold a clamp instruction when |x <= min_val|. const analysis::Constant* FoldClamp2( IRContext* context, Instruction* inst, const std::vector& constants) { diff --git a/3rdparty/spirv-tools/source/opt/constants.cpp b/3rdparty/spirv-tools/source/opt/constants.cpp index 19ca6008d..a3dac5d77 100644 --- a/3rdparty/spirv-tools/source/opt/constants.cpp +++ b/3rdparty/spirv-tools/source/opt/constants.cpp @@ -432,6 +432,12 @@ uint32_t ConstantManager::GetSIntConst(int32_t val) { return GetDefiningInstruction(c)->result_id(); } +uint32_t ConstantManager::GetUIntConst(uint32_t val) { + Type* uint_type = context()->get_type_mgr()->GetUIntType(); + const Constant* c = GetConstant(uint_type, {val}); + return GetDefiningInstruction(c)->result_id(); +} + std::vector Constant::GetVectorComponents( analysis::ConstantManager* const_mgr) const { std::vector components; diff --git a/3rdparty/spirv-tools/source/opt/constants.h b/3rdparty/spirv-tools/source/opt/constants.h index 7b41ae27b..acc64cd2d 100644 --- a/3rdparty/spirv-tools/source/opt/constants.h +++ b/3rdparty/spirv-tools/source/opt/constants.h @@ -642,6 +642,9 @@ class ConstantManager { // Returns the id of a 32-bit signed integer constant with value |val|. uint32_t GetSIntConst(int32_t val); + // Returns the id of a 32-bit unsigned integer constant with value |val|. + uint32_t GetUIntConst(uint32_t val); + private: // Creates a Constant instance with the given type and a vector of constant // defining words. Returns a unique pointer to the created Constant instance diff --git a/3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp b/3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp new file mode 100644 index 000000000..e84d3578a --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp @@ -0,0 +1,437 @@ +// Copyright (c) 2021 Google LLC +// +// 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. + +#include "source/opt/convert_to_sampled_image_pass.h" + +#include +#include +#include + +#include "source/opt/ir_builder.h" +#include "source/util/make_unique.h" +#include "source/util/parse_number.h" + +namespace spvtools { +namespace opt { + +using VectorOfDescriptorSetAndBindingPairs = + std::vector; +using DescriptorSetBindingToInstruction = + ConvertToSampledImagePass::DescriptorSetBindingToInstruction; + +namespace { + +using utils::ParseNumber; + +// Returns true if the given char is ':', '\0' or considered as blank space +// (i.e.: '\n', '\r', '\v', '\t', '\f' and ' '). +bool IsSeparator(char ch) { + return std::strchr(":\0", ch) || std::isspace(ch) != 0; +} + +// Reads characters starting from |str| until it meets a separator. Parses a +// number from the characters and stores it into |number|. Returns the pointer +// to the separator if it succeeds. Otherwise, returns nullptr. +const char* ParseNumberUntilSeparator(const char* str, uint32_t* number) { + const char* number_begin = str; + while (!IsSeparator(*str)) str++; + const char* number_end = str; + std::string number_in_str(number_begin, number_end - number_begin); + if (!utils::ParseNumber(number_in_str.c_str(), number)) { + // The descriptor set is not a valid uint32 number. + return nullptr; + } + return str; +} + +// Returns id of the image type used for the sampled image type of +// |sampled_image|. +uint32_t GetImageTypeOfSampledImage(analysis::TypeManager* type_mgr, + Instruction* sampled_image) { + auto* sampled_image_type = + type_mgr->GetType(sampled_image->type_id())->AsSampledImage(); + return type_mgr->GetTypeInstruction(sampled_image_type->image_type()); +} + +// Finds the instruction whose id is |inst_id|. Follows the operand of +// OpCopyObject recursively if the opcode of the instruction is OpCopyObject +// and returns the first instruction that does not have OpCopyObject as opcode. +Instruction* GetNonCopyObjectDef(analysis::DefUseManager* def_use_mgr, + uint32_t inst_id) { + Instruction* inst = def_use_mgr->GetDef(inst_id); + while (inst->opcode() == SpvOpCopyObject) { + inst_id = inst->GetSingleWordInOperand(0u); + inst = def_use_mgr->GetDef(inst_id); + } + return inst; +} + +} // namespace + +bool ConvertToSampledImagePass::GetDescriptorSetBinding( + const Instruction& inst, + DescriptorSetAndBinding* descriptor_set_binding) const { + auto* decoration_manager = context()->get_decoration_mgr(); + bool found_descriptor_set_to_convert = false; + bool found_binding_to_convert = false; + for (auto decorate : + decoration_manager->GetDecorationsFor(inst.result_id(), false)) { + uint32_t decoration = decorate->GetSingleWordInOperand(1u); + if (decoration == SpvDecorationDescriptorSet) { + if (found_descriptor_set_to_convert) { + assert(false && "A resource has two OpDecorate for the descriptor set"); + return false; + } + descriptor_set_binding->descriptor_set = + decorate->GetSingleWordInOperand(2u); + found_descriptor_set_to_convert = true; + } else if (decoration == SpvDecorationBinding) { + if (found_binding_to_convert) { + assert(false && "A resource has two OpDecorate for the binding"); + return false; + } + descriptor_set_binding->binding = decorate->GetSingleWordInOperand(2u); + found_binding_to_convert = true; + } + } + return found_descriptor_set_to_convert && found_binding_to_convert; +} + +bool ConvertToSampledImagePass::ShouldResourceBeConverted( + const DescriptorSetAndBinding& descriptor_set_binding) const { + return descriptor_set_binding_pairs_.find(descriptor_set_binding) != + descriptor_set_binding_pairs_.end(); +} + +const analysis::Type* ConvertToSampledImagePass::GetVariableType( + const Instruction& variable) const { + if (variable.opcode() != SpvOpVariable) return nullptr; + auto* type = context()->get_type_mgr()->GetType(variable.type_id()); + auto* pointer_type = type->AsPointer(); + if (!pointer_type) return nullptr; + + return pointer_type->pointee_type(); +} + +SpvStorageClass ConvertToSampledImagePass::GetStorageClass( + const Instruction& variable) const { + assert(variable.opcode() == SpvOpVariable); + auto* type = context()->get_type_mgr()->GetType(variable.type_id()); + auto* pointer_type = type->AsPointer(); + if (!pointer_type) return SpvStorageClassMax; + + return pointer_type->storage_class(); +} + +bool ConvertToSampledImagePass::CollectResourcesToConvert( + DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler, + DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image) + const { + for (auto& inst : context()->types_values()) { + const auto* variable_type = GetVariableType(inst); + if (variable_type == nullptr) continue; + + DescriptorSetAndBinding descriptor_set_binding; + if (!GetDescriptorSetBinding(inst, &descriptor_set_binding)) continue; + + if (!ShouldResourceBeConverted(descriptor_set_binding)) { + continue; + } + + if (variable_type->AsImage()) { + if (!descriptor_set_binding_pair_to_image + ->insert({descriptor_set_binding, &inst}) + .second) { + return false; + } + } else if (variable_type->AsSampler()) { + if (!descriptor_set_binding_pair_to_sampler + ->insert({descriptor_set_binding, &inst}) + .second) { + return false; + } + } + } + return true; +} + +Pass::Status ConvertToSampledImagePass::Process() { + Status status = Status::SuccessWithoutChange; + + DescriptorSetBindingToInstruction descriptor_set_binding_pair_to_sampler, + descriptor_set_binding_pair_to_image; + if (!CollectResourcesToConvert(&descriptor_set_binding_pair_to_sampler, + &descriptor_set_binding_pair_to_image)) { + return Status::Failure; + } + + for (auto& image : descriptor_set_binding_pair_to_image) { + status = CombineStatus( + status, UpdateImageVariableToSampledImage(image.second, image.first)); + if (status == Status::Failure) { + return status; + } + } + + for (const auto& sampler : descriptor_set_binding_pair_to_sampler) { + // Converting only a Sampler to Sampled Image is not allowed. It must have a + // corresponding image to combine the sampler with. + auto image_itr = descriptor_set_binding_pair_to_image.find(sampler.first); + if (image_itr == descriptor_set_binding_pair_to_image.end() || + image_itr->second == nullptr) { + return Status::Failure; + } + + status = CombineStatus( + status, CheckUsesOfSamplerVariable(sampler.second, image_itr->second)); + if (status == Status::Failure) { + return status; + } + } + + return status; +} + +void ConvertToSampledImagePass::FindUses(const Instruction* inst, + std::vector* uses, + uint32_t user_opcode) const { + auto* def_use_mgr = context()->get_def_use_mgr(); + def_use_mgr->ForEachUser(inst, [uses, user_opcode, this](Instruction* user) { + if (user->opcode() == user_opcode) { + uses->push_back(user); + } else if (user->opcode() == SpvOpCopyObject) { + FindUses(user, uses, user_opcode); + } + }); +} + +void ConvertToSampledImagePass::FindUsesOfImage( + const Instruction* image, std::vector* uses) const { + auto* def_use_mgr = context()->get_def_use_mgr(); + def_use_mgr->ForEachUser(image, [uses, this](Instruction* user) { + switch (user->opcode()) { + case SpvOpImageFetch: + case SpvOpImageRead: + case SpvOpImageWrite: + case SpvOpImageQueryFormat: + case SpvOpImageQueryOrder: + case SpvOpImageQuerySizeLod: + case SpvOpImageQuerySize: + case SpvOpImageQueryLevels: + case SpvOpImageQuerySamples: + case SpvOpImageSparseFetch: + uses->push_back(user); + default: + break; + } + if (user->opcode() == SpvOpCopyObject) { + FindUsesOfImage(user, uses); + } + }); +} + +Instruction* ConvertToSampledImagePass::CreateImageExtraction( + Instruction* sampled_image) { + InstructionBuilder builder( + context(), sampled_image->NextNode(), + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + return builder.AddUnaryOp( + GetImageTypeOfSampledImage(context()->get_type_mgr(), sampled_image), + SpvOpImage, sampled_image->result_id()); +} + +uint32_t ConvertToSampledImagePass::GetSampledImageTypeForImage( + Instruction* image_variable) { + const auto* variable_type = GetVariableType(*image_variable); + if (variable_type == nullptr) return 0; + const auto* image_type = variable_type->AsImage(); + if (image_type == nullptr) return 0; + + analysis::Image image_type_for_sampled_image(*image_type); + analysis::SampledImage sampled_image_type(&image_type_for_sampled_image); + return context()->get_type_mgr()->GetTypeInstruction(&sampled_image_type); +} + +Instruction* ConvertToSampledImagePass::UpdateImageUses( + Instruction* sampled_image_load) { + std::vector uses_of_load; + FindUsesOfImage(sampled_image_load, &uses_of_load); + if (uses_of_load.empty()) return nullptr; + + auto* extracted_image = CreateImageExtraction(sampled_image_load); + for (auto* user : uses_of_load) { + user->SetInOperand(0, {extracted_image->result_id()}); + context()->get_def_use_mgr()->AnalyzeInstUse(user); + } + return extracted_image; +} + +bool ConvertToSampledImagePass:: + IsSamplerOfSampledImageDecoratedByDescriptorSetBinding( + Instruction* sampled_image_inst, + const DescriptorSetAndBinding& descriptor_set_binding) { + auto* def_use_mgr = context()->get_def_use_mgr(); + uint32_t sampler_id = sampled_image_inst->GetSingleWordInOperand(1u); + auto* sampler_load = def_use_mgr->GetDef(sampler_id); + if (sampler_load->opcode() != SpvOpLoad) return false; + auto* sampler = def_use_mgr->GetDef(sampler_load->GetSingleWordInOperand(0u)); + DescriptorSetAndBinding sampler_descriptor_set_binding; + return GetDescriptorSetBinding(*sampler, &sampler_descriptor_set_binding) && + sampler_descriptor_set_binding == descriptor_set_binding; +} + +void ConvertToSampledImagePass::UpdateSampledImageUses( + Instruction* image_load, Instruction* image_extraction, + const DescriptorSetAndBinding& image_descriptor_set_binding) { + std::vector sampled_image_users; + FindUses(image_load, &sampled_image_users, SpvOpSampledImage); + + auto* def_use_mgr = context()->get_def_use_mgr(); + for (auto* sampled_image_inst : sampled_image_users) { + if (IsSamplerOfSampledImageDecoratedByDescriptorSetBinding( + sampled_image_inst, image_descriptor_set_binding)) { + context()->ReplaceAllUsesWith(sampled_image_inst->result_id(), + image_load->result_id()); + def_use_mgr->AnalyzeInstUse(image_load); + context()->KillInst(sampled_image_inst); + } else { + if (!image_extraction) + image_extraction = CreateImageExtraction(image_load); + sampled_image_inst->SetInOperand(0, {image_extraction->result_id()}); + def_use_mgr->AnalyzeInstUse(sampled_image_inst); + } + } +} + +void ConvertToSampledImagePass::MoveInstructionNextToType(Instruction* inst, + uint32_t type_id) { + auto* type_inst = context()->get_def_use_mgr()->GetDef(type_id); + inst->SetResultType(type_id); + inst->RemoveFromList(); + inst->InsertAfter(type_inst); +} + +bool ConvertToSampledImagePass::ConvertImageVariableToSampledImage( + Instruction* image_variable, uint32_t sampled_image_type_id) { + auto* sampled_image_type = + context()->get_type_mgr()->GetType(sampled_image_type_id); + if (sampled_image_type == nullptr) return false; + auto storage_class = GetStorageClass(*image_variable); + if (storage_class == SpvStorageClassMax) return false; + analysis::Pointer sampled_image_pointer(sampled_image_type, storage_class); + + // Make sure |image_variable| is behind its type i.e., avoid the forward + // reference. + uint32_t type_id = + context()->get_type_mgr()->GetTypeInstruction(&sampled_image_pointer); + MoveInstructionNextToType(image_variable, type_id); + return true; +} + +Pass::Status ConvertToSampledImagePass::UpdateImageVariableToSampledImage( + Instruction* image_variable, + const DescriptorSetAndBinding& descriptor_set_binding) { + std::vector image_variable_loads; + FindUses(image_variable, &image_variable_loads, SpvOpLoad); + if (image_variable_loads.empty()) return Status::SuccessWithoutChange; + + const uint32_t sampled_image_type_id = + GetSampledImageTypeForImage(image_variable); + if (!sampled_image_type_id) return Status::Failure; + + for (auto* load : image_variable_loads) { + load->SetResultType(sampled_image_type_id); + auto* image_extraction = UpdateImageUses(load); + UpdateSampledImageUses(load, image_extraction, descriptor_set_binding); + } + + return ConvertImageVariableToSampledImage(image_variable, + sampled_image_type_id) + ? Status::SuccessWithChange + : Status::Failure; +} + +bool ConvertToSampledImagePass::DoesSampledImageReferenceImage( + Instruction* sampled_image_inst, Instruction* image_variable) { + if (sampled_image_inst->opcode() != SpvOpSampledImage) return false; + auto* def_use_mgr = context()->get_def_use_mgr(); + auto* image_load = GetNonCopyObjectDef( + def_use_mgr, sampled_image_inst->GetSingleWordInOperand(0u)); + if (image_load->opcode() != SpvOpLoad) return false; + auto* image = + GetNonCopyObjectDef(def_use_mgr, image_load->GetSingleWordInOperand(0u)); + return image->opcode() == SpvOpVariable && + image->result_id() == image_variable->result_id(); +} + +Pass::Status ConvertToSampledImagePass::CheckUsesOfSamplerVariable( + const Instruction* sampler_variable, + Instruction* image_to_be_combined_with) { + if (image_to_be_combined_with == nullptr) return Status::Failure; + + std::vector sampler_variable_loads; + FindUses(sampler_variable, &sampler_variable_loads, SpvOpLoad); + for (auto* load : sampler_variable_loads) { + std::vector sampled_image_users; + FindUses(load, &sampled_image_users, SpvOpSampledImage); + for (auto* sampled_image_inst : sampled_image_users) { + if (!DoesSampledImageReferenceImage(sampled_image_inst, + image_to_be_combined_with)) { + return Status::Failure; + } + } + } + return Status::SuccessWithoutChange; +} + +std::unique_ptr +ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString( + const char* str) { + if (!str) return nullptr; + + auto descriptor_set_binding_pairs = + MakeUnique(); + + while (std::isspace(*str)) str++; // skip leading spaces. + + // The parsing loop, break when points to the end. + while (*str) { + // Parse the descriptor set. + uint32_t descriptor_set = 0; + str = ParseNumberUntilSeparator(str, &descriptor_set); + if (str == nullptr) return nullptr; + + // Find the ':', spaces between the descriptor set and the ':' are not + // allowed. + if (*str++ != ':') { + // ':' not found + return nullptr; + } + + // Parse the binding. + uint32_t binding = 0; + str = ParseNumberUntilSeparator(str, &binding); + if (str == nullptr) return nullptr; + + descriptor_set_binding_pairs->push_back({descriptor_set, binding}); + + // Skip trailing spaces. + while (std::isspace(*str)) str++; + } + + return descriptor_set_binding_pairs; +} + +} // namespace opt +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.h b/3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.h new file mode 100644 index 000000000..d3938af7d --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.h @@ -0,0 +1,207 @@ +// Copyright (c) 2021 Google LLC +// +// 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_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_ +#define SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_ + +#include +#include +#include + +#include "source/opt/pass.h" +#include "source/opt/types.h" + +namespace spvtools { +namespace opt { + +// A struct for a pair of descriptor set and binding. +struct DescriptorSetAndBinding { + uint32_t descriptor_set; + uint32_t binding; + + bool operator==(const DescriptorSetAndBinding& descriptor_set_binding) const { + return descriptor_set_binding.descriptor_set == descriptor_set && + descriptor_set_binding.binding == binding; + } +}; + +// See optimizer.hpp for documentation. +class ConvertToSampledImagePass : public Pass { + public: + // Hashing functor for the pair of descriptor set and binding. + struct DescriptorSetAndBindingHash { + size_t operator()( + const DescriptorSetAndBinding& descriptor_set_binding) const { + return std::hash()(descriptor_set_binding.descriptor_set) ^ + std::hash()(descriptor_set_binding.binding); + } + }; + + using SetOfDescriptorSetAndBindingPairs = + std::unordered_set; + using DescriptorSetBindingToInstruction = + std::unordered_map; + + explicit ConvertToSampledImagePass( + const std::vector& descriptor_set_binding_pairs) + : descriptor_set_binding_pairs_(descriptor_set_binding_pairs.begin(), + descriptor_set_binding_pairs.end()) {} + + const char* name() const override { return "convert-to-sampled-image"; } + Status Process() override; + + // Parses the given null-terminated C string to get a vector of descriptor set + // and binding pairs. Returns a unique pointer to the vector of descriptor set + // and binding pairs built from the given |str| on success. Returns a nullptr + // if the given string is not valid for building the vector of pairs. + // A valid string for building the vector of pairs should follow the rule + // below: + // + // ": : ..." + // Example: + // "3:5 2:1 0:4" + // + // Entries are separated with blank spaces (i.e.:' ', '\n', '\r', '\t', + // '\f', '\v'). Each entry corresponds to a descriptor set and binding pair. + // Multiple spaces between, before or after entries are allowed. However, + // spaces are not allowed within a descriptor set or binding. + // + // In each entry, the descriptor set and binding are separated by ':'. + // Missing ':' in any entry is invalid. And it is invalid to have blank + // spaces in between the descriptor set and ':' or ':' and the binding. + // + // : the descriptor set. + // The text must represent a valid uint32_t number. + // + // : the binding. + // The text must represent a valid uint32_t number. + static std::unique_ptr> + ParseDescriptorSetBindingPairsString(const char* str); + + private: + // Collects resources to convert to sampled image and saves them in + // |descriptor_set_binding_pair_to_sampler| if the resource is a sampler and + // saves them in |descriptor_set_binding_pair_to_image| if the resource is an + // image. Returns false if two samplers or two images have the same descriptor + // set and binding. Otherwise, returns true. + bool CollectResourcesToConvert( + DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler, + DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image) + const; + + // Finds an OpDecorate with DescriptorSet decorating |inst| and another + // OpDecorate with Binding decorating |inst|. Stores the descriptor set and + // binding in |descriptor_set_binding|. Returns whether it successfully finds + // the descriptor set and binding or not. + bool GetDescriptorSetBinding( + const Instruction& inst, + DescriptorSetAndBinding* descriptor_set_binding) const; + + // Returns whether |descriptor_set_binding| is a pair of a descriptor set + // and a binding that we have to convert resources with it to a sampled image + // or not. + bool ShouldResourceBeConverted( + const DescriptorSetAndBinding& descriptor_set_binding) const; + + // Returns the pointee type of the type of variable |variable|. If |variable| + // is not an OpVariable instruction, just returns nullptr. + const analysis::Type* GetVariableType(const Instruction& variable) const; + + // Returns the storage class of |variable|. + SpvStorageClass GetStorageClass(const Instruction& variable) const; + + // Finds |inst|'s users whose opcode is |user_opcode| or users of OpCopyObject + // instructions of |inst| whose opcode is |user_opcode| and puts them in + // |uses|. + void FindUses(const Instruction* inst, std::vector* uses, + uint32_t user_opcode) const; + + // Finds OpImage* instructions using |image| or OpCopyObject instructions that + // copy |image| and puts them in |uses|. + void FindUsesOfImage(const Instruction* image, + std::vector* uses) const; + + // Creates an OpImage instruction that extracts the image from the sampled + // image |sampled_image|. + Instruction* CreateImageExtraction(Instruction* sampled_image); + + // Converts |image_variable| whose type is an image pointer to sampled image + // type. Updates users of |image_variable| accordingly. If some instructions + // e.g., OpImageRead use |image_variable| as an Image operand, creates an + // image extracted from the sampled image using OpImage and replace the Image + // operands of the users with the extracted image. If some OpSampledImage + // instructions use |image_variable| and sampler whose descriptor set and + // binding are the same with |image_variable|, just combines |image_variable| + // and the sampler to a sampled image. + Pass::Status UpdateImageVariableToSampledImage( + Instruction* image_variable, + const DescriptorSetAndBinding& descriptor_set_binding); + + // Returns the id of type sampled image type whose image type is the one of + // |image_variable|. + uint32_t GetSampledImageTypeForImage(Instruction* image_variable); + + // Moves |inst| next to the OpType* instruction with |type_id|. + void MoveInstructionNextToType(Instruction* inst, uint32_t type_id); + + // Converts |image_variable| whose type is an image pointer to sampled image + // with the type id |sampled_image_type_id|. Returns whether it successfully + // converts the type of |image_variable| or not. + bool ConvertImageVariableToSampledImage(Instruction* image_variable, + uint32_t sampled_image_type_id); + + // Replaces |sampled_image_load| instruction used by OpImage* with the image + // extracted from |sampled_image_load|. Returns the extracted image or nullptr + // if it does not have uses. + Instruction* UpdateImageUses(Instruction* sampled_image_load); + + // Returns true if the sampler of |sampled_image_inst| is decorated by a + // descriptor set and a binding |descriptor_set_binding|. + bool IsSamplerOfSampledImageDecoratedByDescriptorSetBinding( + Instruction* sampled_image_inst, + const DescriptorSetAndBinding& descriptor_set_binding); + + // Replaces OpSampledImage instructions using |image_load| with |image_load| + // if the sampler of the OpSampledImage instruction has descriptor set and + // binding |image_descriptor_set_binding|. Otherwise, replaces |image_load| + // with |image_extraction|. + void UpdateSampledImageUses( + Instruction* image_load, Instruction* image_extraction, + const DescriptorSetAndBinding& image_descriptor_set_binding); + + // Checks the uses of |sampler_variable|. When a sampler is used by + // OpSampledImage instruction, the corresponding image must be + // |image_to_be_combined_with| that should be already converted to a sampled + // image by UpdateImageVariableToSampledImage() method. + Pass::Status CheckUsesOfSamplerVariable( + const Instruction* sampler_variable, + Instruction* image_to_be_combined_with); + + // Returns true if Image operand of |sampled_image_inst| is the image of + // |image_variable|. + bool DoesSampledImageReferenceImage(Instruction* sampled_image_inst, + Instruction* image_variable); + + // A set of pairs of descriptor set and binding. If an image and/or a sampler + // have a pair of descriptor set and binding that is an element of + // |descriptor_set_binding_pairs_|, they/it will be converted to a sampled + // image by this pass. + const SetOfDescriptorSetAndBindingPairs descriptor_set_binding_pairs_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_ diff --git a/3rdparty/spirv-tools/source/opt/dataflow.cpp b/3rdparty/spirv-tools/source/opt/dataflow.cpp new file mode 100644 index 000000000..c91fad08e --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/dataflow.cpp @@ -0,0 +1,91 @@ +// Copyright (c) 2021 Google LLC. +// +// 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. + +#include "source/opt/dataflow.h" + +#include +#include + +namespace spvtools { +namespace opt { + +bool DataFlowAnalysis::Enqueue(Instruction* inst) { + bool& is_enqueued = on_worklist_[inst]; + if (is_enqueued) return false; + is_enqueued = true; + worklist_.push(inst); + return true; +} + +DataFlowAnalysis::VisitResult DataFlowAnalysis::RunOnce( + Function* function, bool is_first_iteration) { + InitializeWorklist(function, is_first_iteration); + VisitResult ret = VisitResult::kResultFixed; + while (!worklist_.empty()) { + Instruction* top = worklist_.front(); + worklist_.pop(); + on_worklist_[top] = false; + VisitResult result = Visit(top); + if (result == VisitResult::kResultChanged) { + EnqueueSuccessors(top); + ret = VisitResult::kResultChanged; + } + } + return ret; +} + +void DataFlowAnalysis::Run(Function* function) { + VisitResult result = RunOnce(function, true); + while (result == VisitResult::kResultChanged) { + result = RunOnce(function, false); + } +} + +void ForwardDataFlowAnalysis::InitializeWorklist(Function* function, + bool /*is_first_iteration*/) { + context().cfg()->ForEachBlockInReversePostOrder( + function->entry().get(), [this](BasicBlock* bb) { + if (label_position_ == LabelPosition::kLabelsOnly) { + Enqueue(bb->GetLabelInst()); + return; + } + if (label_position_ == LabelPosition::kLabelsAtBeginning) { + Enqueue(bb->GetLabelInst()); + } + for (Instruction& inst : *bb) { + Enqueue(&inst); + } + if (label_position_ == LabelPosition::kLabelsAtEnd) { + Enqueue(bb->GetLabelInst()); + } + }); +} + +void ForwardDataFlowAnalysis::EnqueueUsers(Instruction* inst) { + context().get_def_use_mgr()->ForEachUser( + inst, [this](Instruction* user) { Enqueue(user); }); +} + +void ForwardDataFlowAnalysis::EnqueueBlockSuccessors(Instruction* inst) { + if (inst->opcode() != SpvOpLabel) return; + context() + .cfg() + ->block(inst->result_id()) + ->ForEachSuccessorLabel([this](uint32_t* label) { + Enqueue(context().cfg()->block(*label)->GetLabelInst()); + }); +} + +} // namespace opt +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/dataflow.h b/3rdparty/spirv-tools/source/opt/dataflow.h new file mode 100644 index 000000000..be07415db --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/dataflow.h @@ -0,0 +1,148 @@ +// Copyright (c) 2021 Google LLC. +// +// 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_OPT_DATAFLOW_H_ +#define SOURCE_OPT_DATAFLOW_H_ + +#include +#include +#include + +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +// Generic data-flow analysis. +// Maintains a worklist of instructions to process and processes them in a +// specified order. See also ForwardDataFlowAnalysis, which is specialized for +// forward data-flow analysis. +class DataFlowAnalysis { + public: + // The result of a |Visit| operation on an instruction. + // This is used to determine when analysis has reached a fixpoint. + enum class VisitResult { + // The analysis result for this instruction has changed. + // This means that any instructions that depend on it (its successors) must + // be recomputed. + kResultChanged, + // The analysis result for this instruction has not changed. + // When all visit operations return |kResultFixed|, the analysis has reached + // a fixpoint (converged). + kResultFixed, + }; + + virtual ~DataFlowAnalysis() {} + + // Run this analysis on a given function. + // For analyses which work interprocedurally, |function| may be ignored. + void Run(Function* function); + + protected: + DataFlowAnalysis(IRContext& context) : context_(context) {} + + // Initialize the worklist for a given function. + // |is_first_iteration| is true on the first call to |Run| and false + // afterwards. All subsequent runs are only necessary to check if the analysis + // has converged; if |EnqueueSuccessors| is complete, |InitializeWorklist| + // should do nothing after the first iteration. + virtual void InitializeWorklist(Function* function, + bool is_first_iteration) = 0; + + // Enqueues the successors (instructions which use the analysis result) of + // |inst|. This is not required to be complete, but convergence is faster when + // it is. This is called whenever |Visit| returns |kResultChanged|. + virtual void EnqueueSuccessors(Instruction* inst) = 0; + + // Visits the given instruction, recomputing the analysis result. This is + // called once per instruction queued in |InitializeWorklist| and afterward + // when a predecessor is changed, through |EnqueueSuccessors|. + virtual VisitResult Visit(Instruction* inst) = 0; + + // Enqueues the given instruction to be visited. Ignored if already in the + // worklist. + bool Enqueue(Instruction* inst); + + IRContext& context() { return context_; } + + private: + // Runs one pass, calling |InitializeWorklist| and then iterating through the + // worklist until all fixed. + VisitResult RunOnce(Function* function, bool is_first_iteration); + + IRContext& context_; + std::unordered_map on_worklist_; + // The worklist, which contains the list of instructions to be visited. + // + // The choice of data structure was influenced by the data in "Iterative + // Data-flow Analysis, Revisited" (Cooper et al, 2002). + // https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.125.1549&rep=rep1&type=pdf + // The paper shows that the overall performance benefit of a priority queue + // over a regular queue or stack is relatively small (or negative). + // + // A queue has the advantage that nodes are visited in the same order they are + // enqueued, which relieves the analysis from inserting nodes "backwards", for + // example in worklist initialization. Also, as the paper claims that sorting + // successors does not improve runtime, we can use a single queue which is + // modified during iteration. + std::queue worklist_; +}; + +// A generic data flow analysis, specialized for forward analysis. +class ForwardDataFlowAnalysis : public DataFlowAnalysis { + public: + // Indicates where labels should be in the worklist RPO ordering. + enum class LabelPosition { + // Labels should be placed at the beginning of their blocks. + kLabelsAtBeginning, + // Labels should be placed at the end of their blocks. + kLabelsAtEnd, + // Labels should not be in the worklist. + kNoLabels, + // Only labels should be placed in the worklist. + kLabelsOnly, + }; + + ForwardDataFlowAnalysis(IRContext& context, LabelPosition label_position) + : DataFlowAnalysis(context), label_position_(label_position) {} + + protected: + // Initializes the worklist in reverse postorder, regardless of + // |is_first_iteration|. Labels are placed according to the label position + // specified in the constructor. + void InitializeWorklist(Function* function, bool is_first_iteration) override; + + // Enqueues the users and block successors of the given instruction. + // See |EnqueueUsers| and |EnqueueBlockSuccessors|. + void EnqueueSuccessors(Instruction* inst) override { + EnqueueUsers(inst); + EnqueueBlockSuccessors(inst); + } + + // Enqueues the users of the given instruction. + void EnqueueUsers(Instruction* inst); + + // Enqueues the labels of the successors of the block corresponding to the + // given label instruction. Does nothing for other instructions. + void EnqueueBlockSuccessors(Instruction* inst); + + private: + LabelPosition label_position_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_DATAFLOW_H_ diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp index e782641f2..2e8e13279 100644 --- a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp @@ -18,12 +18,15 @@ #include "source/opt/ir_context.h" -// Constants for OpenCL.DebugInfo.100 extension instructions. +// Constants for OpenCL.DebugInfo.100 & NonSemantic.Vulkan.DebugInfo.100 +// extension instructions. static const uint32_t kOpLineOperandLineIndex = 1; static const uint32_t kLineOperandIndexDebugFunction = 7; static const uint32_t kLineOperandIndexDebugLexicalBlock = 5; static const uint32_t kDebugFunctionOperandFunctionIndex = 13; +static const uint32_t kDebugFunctionDefinitionOperandDebugFunctionIndex = 4; +static const uint32_t kDebugFunctionDefinitionOperandOpFunctionIndex = 5; static const uint32_t kDebugFunctionOperandParentIndex = 9; static const uint32_t kDebugTypeCompositeOperandParentIndex = 9; static const uint32_t kDebugLexicalBlockOperandParentIndex = 7; @@ -46,8 +49,8 @@ namespace { void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) { assert(dbg_inlined_at); - assert(dbg_inlined_at->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugInlinedAt); + assert(dbg_inlined_at->GetCommonDebugOpcode() == + CommonDebugInfoDebugInlinedAt); if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) { dbg_inlined_at->AddOperand( {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inlined_operand}}); @@ -59,8 +62,8 @@ void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) { uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) { assert(dbg_inlined_at); - assert(dbg_inlined_at->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugInlinedAt); + assert(dbg_inlined_at->GetCommonDebugOpcode() == + CommonDebugInfoDebugInlinedAt); if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) return kNoInlinedAt; return dbg_inlined_at->GetSingleWordOperand( @@ -68,8 +71,7 @@ uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) { } bool IsEmptyDebugExpression(Instruction* instr) { - return instr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugExpression && + return (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression) && instr->NumOperands() == kDebugExpressOperandOperationIndex; } @@ -79,43 +81,63 @@ DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) { AnalyzeDebugInsts(*c->module()); } +uint32_t DebugInfoManager::GetDbgSetImportId() { + uint32_t setId = + context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo(); + if (setId == 0) { + setId = + context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo(); + } + return setId; +} + Instruction* DebugInfoManager::GetDbgInst(uint32_t id) { auto dbg_inst_it = id_to_dbg_inst_.find(id); return dbg_inst_it == id_to_dbg_inst_.end() ? nullptr : dbg_inst_it->second; } void DebugInfoManager::RegisterDbgInst(Instruction* inst) { - assert( - inst->NumInOperands() != 0 && - context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() == - inst->GetInOperand(0).words[0] && - "Given instruction is not a debug instruction"); + assert(inst->NumInOperands() != 0 && + (GetDbgSetImportId() == inst->GetInOperand(0).words[0]) && + "Given instruction is not a debug instruction"); id_to_dbg_inst_[inst->result_id()] = inst; } void DebugInfoManager::RegisterDbgFunction(Instruction* inst) { - assert(inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction && - "inst is not a DebugFunction"); - auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex); - // Do not register function that has been optimized away - auto fn_inst = GetDbgInst(fn_id); - if (fn_inst != nullptr) { - assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugInfoNone); - return; + if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) { + auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex); + // Do not register function that has been optimized away. + auto fn_inst = GetDbgInst(fn_id); + if (fn_inst != nullptr) { + assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() == + OpenCLDebugInfo100DebugInfoNone); + return; + } + assert( + fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() && + "Register DebugFunction for a function that already has DebugFunction"); + fn_id_to_dbg_fn_[fn_id] = inst; + } else if (inst->GetVulkan100DebugOpcode() == + NonSemanticVulkanDebugInfo100DebugFunctionDefinition) { + auto fn_id = inst->GetSingleWordOperand( + kDebugFunctionDefinitionOperandOpFunctionIndex); + auto fn_inst = GetDbgInst(inst->GetSingleWordOperand( + kDebugFunctionDefinitionOperandDebugFunctionIndex)); + assert(fn_inst && fn_inst->GetVulkan100DebugOpcode() == + NonSemanticVulkanDebugInfo100DebugFunction); + assert(fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() && + "Register DebugFunctionDefinition for a function that already has " + "DebugFunctionDefinition"); + fn_id_to_dbg_fn_[fn_id] = fn_inst; + } else { + assert(false && "inst is not a DebugFunction"); } - assert( - fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() && - "Register DebugFunction for a function that already has DebugFunction"); - fn_id_to_dbg_fn_[fn_id] = inst; } void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id, Instruction* dbg_declare) { - assert(dbg_declare->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugDeclare || - dbg_declare->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugValue); + assert(dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare || + dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugValue); auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_id); if (dbg_decl_itr == var_id_to_dbg_decl_.end()) { var_id_to_dbg_decl_[var_id] = {dbg_declare}; @@ -126,27 +148,36 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id, uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line, const DebugScope& scope) { - if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() == - 0) - return kNoInlinedAt; + uint32_t setId = GetDbgSetImportId(); + + if (setId == 0) return kNoInlinedAt; + + spv_operand_type_t line_number_type = + spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER; + + // In NonSemantic.Vulkan.DebugInfo.100, all constants are IDs of OpConstant, + // not literals. + if (setId == + context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo()) + line_number_type = spv_operand_type_t::SPV_OPERAND_TYPE_ID; uint32_t line_number = 0; if (line == nullptr) { auto* lexical_scope_inst = GetDbgInst(scope.GetLexicalScope()); if (lexical_scope_inst == nullptr) return kNoInlinedAt; - OpenCLDebugInfo100Instructions debug_opcode = - lexical_scope_inst->GetOpenCL100DebugOpcode(); + CommonDebugInfoInstructions debug_opcode = + lexical_scope_inst->GetCommonDebugOpcode(); switch (debug_opcode) { - case OpenCLDebugInfo100DebugFunction: + case CommonDebugInfoDebugFunction: line_number = lexical_scope_inst->GetSingleWordOperand( kLineOperandIndexDebugFunction); break; - case OpenCLDebugInfo100DebugLexicalBlock: + case CommonDebugInfoDebugLexicalBlock: line_number = lexical_scope_inst->GetSingleWordOperand( kLineOperandIndexDebugLexicalBlock); break; - case OpenCLDebugInfo100DebugTypeComposite: - case OpenCLDebugInfo100DebugCompilationUnit: + case CommonDebugInfoDebugTypeComposite: + case CommonDebugInfoDebugCompilationUnit: assert(false && "DebugTypeComposite and DebugCompilationUnit are lexical " "scopes, but we inline functions into a function or a block " @@ -161,6 +192,13 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line, } } else { line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex); + + // If we need the line number as an ID, generate that constant now. + if (line_number_type == spv_operand_type_t::SPV_OPERAND_TYPE_ID) { + uint32_t line_id = + context()->get_constant_mgr()->GetUIntConst(line_number); + line_number = line_id; + } } uint32_t result_id = context()->TakeNextId(); @@ -168,13 +206,10 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line, context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), result_id, { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {setId}}, {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugInlinedAt)}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}}, + {static_cast(CommonDebugInfoDebugInlinedAt)}}, + {line_number_type, {line_number}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetLexicalScope()}}, })); // |scope| already has DebugInlinedAt. We put the existing DebugInlinedAt @@ -257,19 +292,34 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() { if (deref_operation_ != nullptr) return deref_operation_; uint32_t result_id = context()->TakeNextId(); - std::unique_ptr deref_operation(new Instruction( - context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), - result_id, - { - {SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, - {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugOperation)}}, - {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION, - {static_cast(OpenCLDebugInfo100Deref)}}, - })); + std::unique_ptr deref_operation; + + if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) { + deref_operation = std::unique_ptr(new Instruction( + context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), + result_id, + { + {SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, + {static_cast(OpenCLDebugInfo100DebugOperation)}}, + {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION, + {static_cast(OpenCLDebugInfo100Deref)}}, + })); + } else { + uint32_t deref_id = context()->get_constant_mgr()->GetUIntConst( + NonSemanticVulkanDebugInfo100Deref); + + deref_operation = std::unique_ptr( + new Instruction(context(), SpvOpExtInst, + context()->get_type_mgr()->GetVoidTypeId(), result_id, + { + {SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, + {static_cast( + NonSemanticVulkanDebugInfo100DebugOperation)}}, + {SPV_OPERAND_TYPE_ID, {deref_id}}, + })); + } // Add to the front of |ext_inst_debuginfo_|. deref_operation_ = @@ -283,8 +333,7 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() { } Instruction* DebugInfoManager::DerefDebugExpression(Instruction* dbg_expr) { - assert(dbg_expr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugExpression); + assert(dbg_expr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression); std::unique_ptr deref_expr(dbg_expr->Clone(context())); deref_expr->SetResultId(context()->TakeNextId()); deref_expr->InsertOperand( @@ -306,12 +355,9 @@ Instruction* DebugInfoManager::GetDebugInfoNone() { context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), result_id, { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugInfoNone)}}, + {static_cast(CommonDebugInfoDebugInfoNone)}}, })); // Add to the front of |ext_inst_debuginfo_|. @@ -333,12 +379,9 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() { context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), result_id, { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugExpression)}}, + {static_cast(CommonDebugInfoDebugExpression)}}, })); // Add to the front of |ext_inst_debuginfo_|. @@ -355,8 +398,7 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() { Instruction* DebugInfoManager::GetDebugInlinedAt(uint32_t dbg_inlined_at_id) { auto* inlined_at = GetDbgInst(dbg_inlined_at_id); if (inlined_at == nullptr) return nullptr; - if (inlined_at->GetOpenCL100DebugOpcode() != - OpenCLDebugInfo100DebugInlinedAt) { + if (inlined_at->GetCommonDebugOpcode() != CommonDebugInfoDebugInlinedAt) { return nullptr; } return inlined_at; @@ -403,23 +445,23 @@ bool DebugInfoManager::KillDebugDeclares(uint32_t variable_id) { uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) { auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope); assert(dbg_scope_itr != id_to_dbg_inst_.end()); - OpenCLDebugInfo100Instructions debug_opcode = - dbg_scope_itr->second->GetOpenCL100DebugOpcode(); + CommonDebugInfoInstructions debug_opcode = + dbg_scope_itr->second->GetCommonDebugOpcode(); uint32_t parent_scope = kNoDebugScope; switch (debug_opcode) { - case OpenCLDebugInfo100DebugFunction: + case CommonDebugInfoDebugFunction: parent_scope = dbg_scope_itr->second->GetSingleWordOperand( kDebugFunctionOperandParentIndex); break; - case OpenCLDebugInfo100DebugLexicalBlock: + case CommonDebugInfoDebugLexicalBlock: parent_scope = dbg_scope_itr->second->GetSingleWordOperand( kDebugLexicalBlockOperandParentIndex); break; - case OpenCLDebugInfo100DebugTypeComposite: + case CommonDebugInfoDebugTypeComposite: parent_scope = dbg_scope_itr->second->GetSingleWordOperand( kDebugTypeCompositeOperandParentIndex); break; - case OpenCLDebugInfo100DebugCompilationUnit: + case CommonDebugInfoDebugCompilationUnit: // DebugCompilationUnit does not have a parent scope. break; default: @@ -513,8 +555,7 @@ Instruction* DebugInfoManager::AddDebugValueForDecl( std::unique_ptr dbg_val(dbg_decl->Clone(context())); dbg_val->SetResultId(context()->TakeNextId()); - dbg_val->SetInOperand(kExtInstInstructionInIdx, - {OpenCLDebugInfo100DebugValue}); + dbg_val->SetInOperand(kExtInstInstructionInIdx, {CommonDebugInfoDebugValue}); dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id}); dbg_val->SetOperand(kDebugValueOperandExpressionIndex, {GetEmptyDebugExpression()->result_id()}); @@ -532,9 +573,20 @@ Instruction* DebugInfoManager::AddDebugValueForDecl( return added_dbg_val; } +uint32_t DebugInfoManager::GetVulkanDebugOperation(Instruction* inst) { + assert(inst->GetVulkan100DebugOpcode() == + NonSemanticVulkanDebugInfo100DebugOperation && + "inst must be Vulkan DebugOperation"); + return context() + ->get_constant_mgr() + ->GetConstantFromInst(context()->get_def_use_mgr()->GetDef( + inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex))) + ->GetU32(); +} + uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare( Instruction* inst) { - if (inst->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugValue) return 0; + if (inst->GetCommonDebugOpcode() != CommonDebugInfoDebugValue) return 0; auto* expr = GetDbgInst(inst->GetSingleWordOperand(kDebugValueOperandExpressionIndex)); @@ -544,9 +596,19 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare( auto* operation = GetDbgInst( expr->GetSingleWordOperand(kDebugExpressOperandOperationIndex)); if (operation == nullptr) return 0; - if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) != - OpenCLDebugInfo100Deref) { - return 0; + + // OpenCL.DebugInfo.100 contains a literal for the operation, Vulkan uses an + // OpConstant. + if (inst->IsOpenCL100DebugInstr()) { + if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) != + OpenCLDebugInfo100Deref) { + return 0; + } + } else { + uint32_t operation_const = GetVulkanDebugOperation(operation); + if (operation_const != NonSemanticVulkanDebugInfo100Deref) { + return 0; + } } uint32_t var_id = @@ -567,8 +629,8 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare( } bool DebugInfoManager::IsDebugDeclare(Instruction* instr) { - if (!instr->IsOpenCL100DebugInstr()) return false; - return instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare || + if (!instr->IsCommonDebugInstr()) return false; + return instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare || GetVariableIdOfDebugValueUsedForDeclare(instr) != 0; } @@ -615,14 +677,13 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { users.insert(inst); } - if (!inst->IsOpenCL100DebugInstr()) return; + if (!inst->IsCommonDebugInstr()) return; RegisterDbgInst(inst); - if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) { - assert(GetDebugFunction(inst->GetSingleWordOperand( - kDebugFunctionOperandFunctionIndex)) == nullptr && - "Two DebugFunction instruction exists for a single OpFunction."); + if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction || + inst->GetVulkan100DebugOpcode() == + NonSemanticVulkanDebugInfo100DebugFunctionDefinition) { RegisterDbgFunction(inst); } @@ -633,8 +694,17 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { deref_operation_ = inst; } + if (deref_operation_ == nullptr && + inst->GetVulkan100DebugOpcode() == + NonSemanticVulkanDebugInfo100DebugOperation) { + uint32_t operation_const = GetVulkanDebugOperation(inst); + if (operation_const == NonSemanticVulkanDebugInfo100Deref) { + deref_operation_ = inst; + } + } + if (debug_info_none_inst_ == nullptr && - inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) { + inst->GetCommonDebugOpcode() == CommonDebugInfoDebugInfoNone) { debug_info_none_inst_ = inst; } @@ -642,7 +712,7 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { empty_debug_expr_inst_ = inst; } - if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) { + if (inst->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) { uint32_t var_id = inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex); RegisterDbgDeclare(var_id, inst); @@ -655,8 +725,8 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) { void DebugInfoManager::ConvertDebugGlobalToLocalVariable( Instruction* dbg_global_var, Instruction* local_var) { - if (dbg_global_var->GetOpenCL100DebugOpcode() != - OpenCLDebugInfo100DebugGlobalVariable) { + if (dbg_global_var->GetCommonDebugOpcode() != + CommonDebugInfoDebugGlobalVariable) { return; } assert(local_var->opcode() == SpvOpVariable || @@ -664,7 +734,7 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable( // Convert |dbg_global_var| to DebugLocalVariable dbg_global_var->SetInOperand(kExtInstInstructionInIdx, - {OpenCLDebugInfo100DebugLocalVariable}); + {CommonDebugInfoDebugLocalVariable}); auto flags = dbg_global_var->GetSingleWordOperand( kDebugGlobalVariableOperandFlagsIndex); for (uint32_t i = dbg_global_var->NumInOperands() - 1; @@ -680,12 +750,9 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable( context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(), context()->TakeNextId(), { - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {context() - ->get_feature_mgr() - ->GetExtInstImportId_OpenCL100DebugInfo()}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, - {static_cast(OpenCLDebugInfo100DebugDeclare)}}, + {static_cast(CommonDebugInfoDebugDeclare)}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {dbg_global_var->result_id()}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {local_var->result_id()}}, @@ -713,7 +780,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) { // list. if (empty_debug_expr_inst_ != nullptr && empty_debug_expr_inst_->PreviousNode() != nullptr && - empty_debug_expr_inst_->PreviousNode()->IsOpenCL100DebugInstr()) { + empty_debug_expr_inst_->PreviousNode()->IsCommonDebugInstr()) { empty_debug_expr_inst_->InsertBefore( &*context()->module()->ext_inst_debuginfo_begin()); } @@ -722,7 +789,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) { // list. if (debug_info_none_inst_ != nullptr && debug_info_none_inst_->PreviousNode() != nullptr && - debug_info_none_inst_->PreviousNode()->IsOpenCL100DebugInstr()) { + debug_info_none_inst_->PreviousNode()->IsCommonDebugInstr()) { debug_info_none_inst_->InsertBefore( &*context()->module()->ext_inst_debuginfo_begin()); } @@ -740,7 +807,7 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { inlinedat_id_to_users_itr->second.erase(instr); } - if (instr == nullptr || !instr->IsOpenCL100DebugInstr()) { + if (instr == nullptr || !instr->IsCommonDebugInstr()) { return; } @@ -751,9 +818,15 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { instr->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex); fn_id_to_dbg_fn_.erase(fn_id); } + if (instr->GetVulkan100DebugOpcode() == + NonSemanticVulkanDebugInfo100DebugFunction) { + auto fn_id = instr->GetSingleWordOperand( + kDebugFunctionDefinitionOperandOpFunctionIndex); + fn_id_to_dbg_fn_.erase(fn_id); + } - if (instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare || - instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue) { + if (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare || + instr->GetCommonDebugOpcode() == CommonDebugInfoDebugValue) { auto var_or_value_id = instr->GetSingleWordOperand(kDebugDeclareOperandVariableIndex); auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_or_value_id); @@ -767,6 +840,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin(); dbg_instr_itr != context()->module()->ext_inst_debuginfo_end(); ++dbg_instr_itr) { + // OpenCL.DebugInfo.100 contains the operation as a literal operand, in + // Vulkan it's referenced as an OpConstant. if (instr != &*dbg_instr_itr && dbg_instr_itr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation && @@ -775,6 +850,15 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { OpenCLDebugInfo100Deref) { deref_operation_ = &*dbg_instr_itr; break; + } else if (instr != &*dbg_instr_itr && + dbg_instr_itr->GetVulkan100DebugOpcode() == + NonSemanticVulkanDebugInfo100DebugOperation) { + uint32_t operation_const = GetVulkanDebugOperation(&*dbg_instr_itr); + + if (operation_const == NonSemanticVulkanDebugInfo100Deref) { + deref_operation_ = &*dbg_instr_itr; + break; + } } } } @@ -784,9 +868,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) { for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin(); dbg_instr_itr != context()->module()->ext_inst_debuginfo_end(); ++dbg_instr_itr) { - if (instr != &*dbg_instr_itr && - dbg_instr_itr->GetOpenCL100DebugOpcode() == - OpenCLDebugInfo100DebugInfoNone) { + if (instr != &*dbg_instr_itr && dbg_instr_itr->GetCommonDebugOpcode() == + CommonDebugInfoDebugInfoNone) { debug_info_none_inst_ = &*dbg_instr_itr; break; } diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.h b/3rdparty/spirv-tools/source/opt/debug_info_manager.h index 776e9baab..679ae138e 100644 --- a/3rdparty/spirv-tools/source/opt/debug_info_manager.h +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.h @@ -67,8 +67,8 @@ class DebugInlinedAtContext { std::unordered_map callee_inlined_at2chain_; }; -// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 extension -// instructions. +// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 and +// NonSemantic.Vulkan.DebugInfo.100 extension instructions. class DebugInfoManager { public: // Constructs a debug information manager from the given |context|. @@ -85,7 +85,7 @@ class DebugInfoManager { return !(lhs == rhs); } - // Analyzes OpenCL.DebugInfo.100 instruction |dbg_inst|. + // Analyzes DebugInfo instruction |dbg_inst|. void AnalyzeDebugInst(Instruction* dbg_inst); // Creates new DebugInlinedAt and returns its id. Its line operand is the @@ -164,6 +164,9 @@ class DebugInfoManager { // Erases |instr| from data structures of this class. void ClearDebugInfo(Instruction* instr); + // Return the opcode for the Vulkan DebugOperation inst + uint32_t GetVulkanDebugOperation(Instruction* inst); + // Returns the id of Value operand if |inst| is DebugValue who has Deref // operation and its Value operand is a result id of OpVariable with // Function storage class. Otherwise, returns 0. @@ -190,10 +193,13 @@ class DebugInfoManager { private: IRContext* context() { return context_; } - // Analyzes OpenCL.DebugInfo.100 instructions in the given |module| and + // Analyzes DebugInfo instructions in the given |module| and // populates data structures in this class. void AnalyzeDebugInsts(Module& module); + // Get the DebugInfo ExtInstImport Id, or 0 if no DebugInfo is available. + uint32_t GetDbgSetImportId(); + // Returns the debug instruction whose id is |id|. Returns |nullptr| if one // does not exists. Instruction* GetDbgInst(uint32_t id); @@ -230,7 +236,7 @@ class DebugInfoManager { IRContext* context_; - // Mapping from ids of OpenCL.DebugInfo.100 extension instructions + // Mapping from ids of DebugInfo extension instructions. // to their Instruction instances. std::unordered_map id_to_dbg_inst_; diff --git a/3rdparty/spirv-tools/source/opt/folding_rules.cpp b/3rdparty/spirv-tools/source/opt/folding_rules.cpp index e3e926c3a..6ae078fb8 100644 --- a/3rdparty/spirv-tools/source/opt/folding_rules.cpp +++ b/3rdparty/spirv-tools/source/opt/folding_rules.cpp @@ -967,12 +967,11 @@ FoldingRule MergeDivMulArithmetic() { // Fold divides of a constant and a negation. // Cases: // (-x) / 2 = x / -2 -// 2 / (-x) = 2 / -x +// 2 / (-x) = -2 / x FoldingRule MergeDivNegateArithmetic() { return [](IRContext* context, Instruction* inst, const std::vector& constants) { - assert(inst->opcode() == SpvOpFDiv || inst->opcode() == SpvOpSDiv || - inst->opcode() == SpvOpUDiv); + assert(inst->opcode() == SpvOpFDiv || inst->opcode() == SpvOpSDiv); analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); @@ -2572,8 +2571,6 @@ void FoldingRules::AddFoldingRules() { rules_[SpvOpStore].push_back(StoringUndef()); - rules_[SpvOpUDiv].push_back(MergeDivNegateArithmetic()); - rules_[SpvOpVectorShuffle].push_back(VectorShuffleFeedingShuffle()); rules_[SpvOpImageSampleImplicitLod].push_back(UpdateImageOperands()); diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 69103b26c..858c95eea 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -499,6 +499,26 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateAmdExtToKhrPass()); } else if (pass_name == "interpolate-fixup") { RegisterPass(CreateInterpolateFixupPass()); + } else if (pass_name == "convert-to-sampled-image") { + if (pass_args.size() > 0) { + auto descriptor_set_binding_pairs = + opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString( + pass_args.c_str()); + if (!descriptor_set_binding_pairs) { + Errorf(consumer(), nullptr, {}, + "Invalid argument for --convert-to-sampled-image: %s", + pass_args.c_str()); + return false; + } + RegisterPass(CreateConvertToSampledImagePass( + std::move(*descriptor_set_binding_pairs))); + } else { + Errorf(consumer(), nullptr, {}, + "Invalid pairs of descriptor set and binding '%s'. Expected a " + "string of : pairs.", + pass_args.c_str()); + return false; + } } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", @@ -940,4 +960,11 @@ Optimizer::PassToken CreateInterpolateFixupPass() { MakeUnique()); } +Optimizer::PassToken CreateConvertToSampledImagePass( + const std::vector& + descriptor_set_binding_pairs) { + return MakeUnique( + MakeUnique(descriptor_set_binding_pairs)); +} + } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/passes.h b/3rdparty/spirv-tools/source/opt/passes.h index aeae44494..da837f2ab 100644 --- a/3rdparty/spirv-tools/source/opt/passes.h +++ b/3rdparty/spirv-tools/source/opt/passes.h @@ -26,6 +26,7 @@ #include "source/opt/combine_access_chains.h" #include "source/opt/compact_ids_pass.h" #include "source/opt/convert_to_half_pass.h" +#include "source/opt/convert_to_sampled_image_pass.h" #include "source/opt/copy_prop_arrays.h" #include "source/opt/dead_branch_elim_pass.h" #include "source/opt/dead_insert_elim_pass.h" diff --git a/3rdparty/spirv-tools/source/val/validate_builtins.cpp b/3rdparty/spirv-tools/source/val/validate_builtins.cpp index 3c9df9fc2..a6e624f74 100644 --- a/3rdparty/spirv-tools/source/val/validate_builtins.cpp +++ b/3rdparty/spirv-tools/source/val/validate_builtins.cpp @@ -2846,7 +2846,7 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) - << " to be used only with GLCompute execution model. " + << " to be used only with GLCompute, MeshNV, or TaskNV execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); } @@ -2928,7 +2928,7 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) - << " to be used only with GLCompute execution model. " + << " to be used only with GLCompute, MeshNV, or TaskNV execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); } @@ -3070,14 +3070,16 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference( const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { for (const SpvExecutionModel execution_model : execution_models_) { - if (execution_model != SpvExecutionModelGLCompute) { + if (execution_model != SpvExecutionModelGLCompute && + execution_model != SpvExecutionModelTaskNV && + execution_model != SpvExecutionModelMeshNV) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(4425) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) - << " to be used only with GLCompute execution model. " + << " to be used only with GLCompute, MeshNV, or TaskNV execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); } @@ -4190,6 +4192,7 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInMeshViewIndicesNV: case SpvBuiltInBaryCoordNV: case SpvBuiltInBaryCoordNoPerspNV: + case SpvBuiltInCurrentRayTimeNV: // No validation rules (for the moment). break; diff --git a/3rdparty/spirv-tools/source/val/validate_decorations.cpp b/3rdparty/spirv-tools/source/val/validate_decorations.cpp index 615adc72a..c483635ba 100644 --- a/3rdparty/spirv-tools/source/val/validate_decorations.cpp +++ b/3rdparty/spirv-tools/source/val/validate_decorations.cpp @@ -506,12 +506,10 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, return recursive_status; // Check matrix stride. if (SpvOpTypeMatrix == opcode) { - for (auto& decoration : vstate.id_decorations(id)) { - if (SpvDecorationMatrixStride == decoration.dec_type() && - !IsAlignedTo(decoration.params()[0], alignment)) - return fail(memberIdx) - << "is a matrix with stride " << decoration.params()[0] - << " not satisfying alignment to " << alignment; + const auto stride = constraint.matrix_stride; + if (!IsAlignedTo(stride, alignment)) { + return fail(memberIdx) << "is a matrix with stride " << stride + << " not satisfying alignment to " << alignment; } } diff --git a/3rdparty/spirv-tools/source/val/validate_interfaces.cpp b/3rdparty/spirv-tools/source/val/validate_interfaces.cpp index d16d48e26..d3ef5386c 100644 --- a/3rdparty/spirv-tools/source/val/validate_interfaces.cpp +++ b/3rdparty/spirv-tools/source/val/validate_interfaces.cpp @@ -27,6 +27,10 @@ namespace spvtools { namespace val { namespace { +// Limit the number of checked locations to 4096. Multiplied by 4 to represent +// all the components. This limit is set to be well beyond practical use cases. +const uint32_t kMaxLocations = 4096 * 4; + // Returns true if \c inst is an input or output variable. bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) { if (is_spv_1_4) { @@ -347,6 +351,11 @@ spv_result_t GetLocationsForVariable( uint32_t num_components = NumConsumedComponents(_, sub_type); uint32_t array_location = location + (num_locations * array_idx); uint32_t start = array_location * 4; + if (kMaxLocations <= start) { + // Too many locations, give up. + break; + } + uint32_t end = (array_location + num_locations) * 4; if (num_components != 0) { start += component; @@ -416,6 +425,11 @@ spv_result_t GetLocationsForVariable( } uint32_t start = location * 4; + if (kMaxLocations <= start) { + // Too many locations, give up. + continue; + } + uint32_t end = (location + num_locations) * 4; if (num_components != 0) { start += component; @@ -454,6 +468,7 @@ spv_result_t ValidateLocations(ValidationState_t& _, std::unordered_set input_locations; std::unordered_set output_locations_index0; std::unordered_set output_locations_index1; + std::unordered_set seen; for (uint32_t i = 3; i < entry_point->operands().size(); ++i) { auto interface_id = entry_point->GetOperandAs(i); auto interface_var = _.FindDef(interface_id); @@ -462,6 +477,11 @@ spv_result_t ValidateLocations(ValidationState_t& _, storage_class != SpvStorageClassOutput) { continue; } + if (!seen.insert(interface_id).second) { + // Pre-1.4 an interface variable could be listed multiple times in an + // entry point. Validation for 1.4 or later is done elsewhere. + continue; + } auto locations = (storage_class == SpvStorageClassInput) ? &input_locations diff --git a/3rdparty/spirv-tools/source/val/validate_memory.cpp b/3rdparty/spirv-tools/source/val/validate_memory.cpp index a4bc0faba..a7b0f82d5 100644 --- a/3rdparty/spirv-tools/source/val/validate_memory.cpp +++ b/3rdparty/spirv-tools/source/val/validate_memory.cpp @@ -893,6 +893,12 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) { << "'s type."; } + if (!_.options()->before_hlsl_legalization && + _.ContainsRuntimeArray(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot load a runtime-sized array"; + } + if (auto error = CheckMemoryAccess(_, inst, 3)) return error; if (_.HasCapability(SpvCapabilityShader) && diff --git a/3rdparty/spirv-tools/source/val/validation_state.cpp b/3rdparty/spirv-tools/source/val/validation_state.cpp index 52821636b..c9ac3ae75 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.cpp +++ b/3rdparty/spirv-tools/source/val/validation_state.cpp @@ -1262,16 +1262,13 @@ const Instruction* ValidationState_t::TracePointer( return base_ptr; } -bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type, - uint32_t width) const { - if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false; - +bool ValidationState_t::ContainsType( + uint32_t id, const std::function& f, + bool traverse_all_types) const { const auto inst = FindDef(id); if (!inst) return false; - if (inst->opcode() == type) { - return inst->GetOperandAs(1u) == width; - } + if (f(inst)) return true; switch (inst->opcode()) { case SpvOpTypeArray: @@ -1281,24 +1278,45 @@ bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type, case SpvOpTypeImage: case SpvOpTypeSampledImage: case SpvOpTypeCooperativeMatrixNV: - return ContainsSizedIntOrFloatType(inst->GetOperandAs(1u), type, - width); + return ContainsType(inst->GetOperandAs(1u), f, + traverse_all_types); case SpvOpTypePointer: if (IsForwardPointer(id)) return false; - return ContainsSizedIntOrFloatType(inst->GetOperandAs(2u), type, - width); - case SpvOpTypeFunction: - case SpvOpTypeStruct: { - for (uint32_t i = 1; i < inst->operands().size(); ++i) { - if (ContainsSizedIntOrFloatType(inst->GetOperandAs(i), type, - width)) - return true; + if (traverse_all_types) { + return ContainsType(inst->GetOperandAs(2u), f, + traverse_all_types); } - return false; - } + break; + case SpvOpTypeFunction: + case SpvOpTypeStruct: + if (inst->opcode() == SpvOpTypeFunction && !traverse_all_types) { + return false; + } + for (uint32_t i = 1; i < inst->operands().size(); ++i) { + if (ContainsType(inst->GetOperandAs(i), f, + traverse_all_types)) { + return true; + } + } + break; default: - return false; + break; } + + return false; +} + +bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type, + uint32_t width) const { + if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false; + + const auto f = [type, width](const Instruction* inst) { + if (inst->opcode() == type) { + return inst->GetOperandAs(1u) == width; + } + return false; + }; + return ContainsType(id, f); } bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const { @@ -1313,6 +1331,13 @@ bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const { return false; } +bool ValidationState_t::ContainsRuntimeArray(uint32_t id) const { + const auto f = [](const Instruction* inst) { + return inst->opcode() == SpvOpTypeRuntimeArray; + }; + return ContainsType(id, f, /* traverse_all_types = */ false); +} + bool ValidationState_t::IsValidStorageClass( SpvStorageClass storage_class) const { if (spvIsVulkanEnv(context()->target_env)) { diff --git a/3rdparty/spirv-tools/source/val/validation_state.h b/3rdparty/spirv-tools/source/val/validation_state.h index 57634bf4a..2fe966215 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.h +++ b/3rdparty/spirv-tools/source/val/validation_state.h @@ -595,6 +595,17 @@ class ValidationState_t { // 16-bit float that is not generally enabled for use. bool ContainsLimitedUseIntOrFloatType(uint32_t id) const; + // Returns true if |id| is a type that contains a runtime-sized array. + // Does not consider a pointers as contains the array. + bool ContainsRuntimeArray(uint32_t id) const; + + // Generic type traversal. + // Only traverse pointers and functions if |traverse_all_types| is true. + // Recursively tests |f| against the type hierarchy headed by |id|. + bool ContainsType(uint32_t id, + const std::function& f, + bool traverse_all_types = true) const; + // Gets value from OpConstant and OpSpecConstant as uint64. // Returns false on failure (no instruction, wrong instruction, not int). bool GetConstantValUint64(uint32_t id, uint64_t* val) const;