diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 241b7bc8f..22af5e842 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2020.6", "SPIRV-Tools v2020.6 25b32b391d8d2cf07c95edd7d164911cb00b4bc5" +"v2020.6", "SPIRV-Tools v2020.6 fecfd7c6d825bb09bd025cbd64db0ecbef420f9a" diff --git a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc index 3e672245e..13d0f1886 100644 --- a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc +++ b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc @@ -34,6 +34,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_EXT_physical_storage_buffer"; case Extension::kSPV_EXT_shader_atomic_float_add: return "SPV_EXT_shader_atomic_float_add"; + case Extension::kSPV_EXT_shader_image_int64: + return "SPV_EXT_shader_image_int64"; case Extension::kSPV_EXT_shader_stencil_export: return "SPV_EXT_shader_stencil_export"; case Extension::kSPV_EXT_shader_viewport_index_layer: @@ -74,6 +76,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_KHR_device_group"; case Extension::kSPV_KHR_float_controls: return "SPV_KHR_float_controls"; + case Extension::kSPV_KHR_fragment_shading_rate: + return "SPV_KHR_fragment_shading_rate"; case Extension::kSPV_KHR_multiview: return "SPV_KHR_multiview"; case Extension::kSPV_KHR_no_integer_wrap_decoration: @@ -143,8 +147,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_float_add", "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_blocking_pipes", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_kernel_attributes", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "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_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "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_float_add, 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_blocking_pipes, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, 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_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, 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_float_add", "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_blocking_pipes", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_kernel_attributes", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_fragment_shading_rate", "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_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "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_float_add, 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_blocking_pipes, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_fragment_shading_rate, 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_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, 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 }; const auto b = std::begin(known_ext_strs); const auto e = std::end(known_ext_strs); const auto found = std::equal_range( @@ -298,6 +302,8 @@ const char* CapabilityToString(SpvCapability capability) { return "ShaderLayer"; case SpvCapabilityShaderViewportIndex: return "ShaderViewportIndex"; + case SpvCapabilityFragmentShadingRateKHR: + return "FragmentShadingRateKHR"; case SpvCapabilitySubgroupBallotKHR: return "SubgroupBallotKHR"; case SpvCapabilityDrawParameters: @@ -354,6 +360,8 @@ const char* CapabilityToString(SpvCapability capability) { return "StencilExportEXT"; case SpvCapabilityImageReadWriteLodAMD: return "ImageReadWriteLodAMD"; + case SpvCapabilityInt64ImageEXT: + return "Int64ImageEXT"; case SpvCapabilityShaderClockKHR: return "ShaderClockKHR"; case SpvCapabilitySampleMaskOverrideCoverageNV: diff --git a/3rdparty/spirv-tools/include/generated/extension_enum.inc b/3rdparty/spirv-tools/include/generated/extension_enum.inc index a5c14eedb..0dbb6f84a 100644 --- a/3rdparty/spirv-tools/include/generated/extension_enum.inc +++ b/3rdparty/spirv-tools/include/generated/extension_enum.inc @@ -15,6 +15,7 @@ kSPV_EXT_fragment_invocation_density, kSPV_EXT_fragment_shader_interlock, kSPV_EXT_physical_storage_buffer, kSPV_EXT_shader_atomic_float_add, +kSPV_EXT_shader_image_int64, kSPV_EXT_shader_stencil_export, kSPV_EXT_shader_viewport_index_layer, kSPV_GOOGLE_decorate_string, @@ -35,6 +36,7 @@ kSPV_KHR_16bit_storage, kSPV_KHR_8bit_storage, kSPV_KHR_device_group, kSPV_KHR_float_controls, +kSPV_KHR_fragment_shading_rate, kSPV_KHR_multiview, kSPV_KHR_no_integer_wrap_decoration, kSPV_KHR_non_semantic_info, diff --git a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc index f07003d8d..163f48e7e 100644 --- a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc @@ -19,6 +19,7 @@ static const SpvCapability pygen_variable_caps_FragmentFullyCoveredEXT[] = {SpvC static const SpvCapability pygen_variable_caps_FragmentShaderPixelInterlockEXT[] = {SpvCapabilityFragmentShaderPixelInterlockEXT}; static const SpvCapability pygen_variable_caps_FragmentShaderSampleInterlockEXT[] = {SpvCapabilityFragmentShaderSampleInterlockEXT}; static const SpvCapability pygen_variable_caps_FragmentShaderShadingRateInterlockEXT[] = {SpvCapabilityFragmentShaderShadingRateInterlockEXT}; +static const SpvCapability pygen_variable_caps_FragmentShadingRateKHR[] = {SpvCapabilityFragmentShadingRateKHR}; static const SpvCapability pygen_variable_caps_FunctionPointersINTEL[] = {SpvCapabilityFunctionPointersINTEL}; static const SpvCapability pygen_variable_caps_GenericPointer[] = {SpvCapabilityGenericPointer}; static const SpvCapability pygen_variable_caps_Geometry[] = {SpvCapabilityGeometry}; @@ -40,6 +41,7 @@ static const SpvCapability pygen_variable_caps_IndirectReferencesINTEL[] = {SpvC static const SpvCapability pygen_variable_caps_InputAttachment[] = {SpvCapabilityInputAttachment}; static const SpvCapability pygen_variable_caps_InputAttachmentShaderNonUniform[] = {SpvCapabilityInputAttachment, SpvCapabilityShaderNonUniform}; static const SpvCapability pygen_variable_caps_Int64[] = {SpvCapabilityInt64}; +static const SpvCapability pygen_variable_caps_Int64ImageEXT[] = {SpvCapabilityInt64ImageEXT}; static const SpvCapability pygen_variable_caps_Kernel[] = {SpvCapabilityKernel}; static const SpvCapability pygen_variable_caps_KernelGroupNonUniform[] = {SpvCapabilityKernel, SpvCapabilityGroupNonUniform}; static const SpvCapability pygen_variable_caps_KernelGroupNonUniformSubgroupBallotKHR[] = {SpvCapabilityKernel, SpvCapabilityGroupNonUniform, SpvCapabilitySubgroupBallotKHR}; @@ -109,6 +111,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_invocation static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_shader_interlock[] = {spvtools::Extension::kSPV_EXT_fragment_shader_interlock}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer[] = {spvtools::Extension::kSPV_EXT_physical_storage_buffer, spvtools::Extension::kSPV_KHR_physical_storage_buffer}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_atomic_float_add[] = {spvtools::Extension::kSPV_EXT_shader_atomic_float_add}; +static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_image_int64[] = {spvtools::Extension::kSPV_EXT_shader_image_int64}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_stencil_export[] = {spvtools::Extension::kSPV_EXT_shader_stencil_export}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_viewport_index_layerSPV_NV_viewport_array2[] = {spvtools::Extension::kSPV_EXT_shader_viewport_index_layer, spvtools::Extension::kSPV_NV_viewport_array2}; static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1}; @@ -128,6 +131,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_KHR_16bit_storage[] = { static const spvtools::Extension pygen_variable_exts_SPV_KHR_8bit_storage[] = {spvtools::Extension::kSPV_KHR_8bit_storage}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_device_group[] = {spvtools::Extension::kSPV_KHR_device_group}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_float_controls[] = {spvtools::Extension::kSPV_KHR_float_controls}; +static const spvtools::Extension pygen_variable_exts_SPV_KHR_fragment_shading_rate[] = {spvtools::Extension::kSPV_KHR_fragment_shading_rate}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_multiview[] = {spvtools::Extension::kSPV_KHR_multiview}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_no_integer_wrap_decoration[] = {spvtools::Extension::kSPV_KHR_no_integer_wrap_decoration}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_post_depth_coverage[] = {spvtools::Extension::kSPV_KHR_post_depth_coverage}; @@ -279,6 +283,13 @@ static const spv_operand_desc_t pygen_variable_RayFlagsEntries[] = { {"SkipAABBsKHR", 0x0200, 1, pygen_variable_caps_RayTraversalPrimitiveCullingProvisionalKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} }; +static const spv_operand_desc_t pygen_variable_FragmentShadingRateEntries[] = { + {"Vertical2Pixels", 0x0001, 1, pygen_variable_caps_FragmentShadingRateKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"Vertical4Pixels", 0x0002, 1, pygen_variable_caps_FragmentShadingRateKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"Horizontal2Pixels", 0x0004, 1, pygen_variable_caps_FragmentShadingRateKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"Horizontal4Pixels", 0x0008, 1, pygen_variable_caps_FragmentShadingRateKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} +}; + static const spv_operand_desc_t pygen_variable_SourceLanguageEntries[] = { {"Unknown", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"ESSL", 1, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, @@ -485,7 +496,9 @@ static const spv_operand_desc_t pygen_variable_ImageFormatEntries[] = { {"Rg16ui", 36, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Rg8ui", 37, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"R16ui", 38, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"R8ui", 39, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"R8ui", 39, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, + {"R64ui", 40, 1, pygen_variable_caps_Int64ImageEXT, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, + {"R64i", 41, 1, pygen_variable_caps_Int64ImageEXT, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_ImageChannelOrderEntries[] = { @@ -700,8 +713,10 @@ static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = { {"BaseVertex", 4424, 1, pygen_variable_caps_DrawParameters, 1, pygen_variable_exts_SPV_KHR_shader_draw_parameters, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu}, {"BaseInstance", 4425, 1, pygen_variable_caps_DrawParameters, 1, pygen_variable_exts_SPV_KHR_shader_draw_parameters, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu}, {"DrawIndex", 4426, 2, pygen_variable_caps_DrawParametersMeshShadingNV, 2, pygen_variable_exts_SPV_KHR_shader_draw_parametersSPV_NV_mesh_shader, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu}, + {"PrimitiveShadingRateKHR", 4432, 1, pygen_variable_caps_FragmentShadingRateKHR, 1, pygen_variable_exts_SPV_KHR_fragment_shading_rate, {}, 0xffffffffu, 0xffffffffu}, {"DeviceIndex", 4438, 1, pygen_variable_caps_DeviceGroup, 1, pygen_variable_exts_SPV_KHR_device_group, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu}, {"ViewIndex", 4440, 1, pygen_variable_caps_MultiView, 1, pygen_variable_exts_SPV_KHR_multiview, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu}, + {"ShadingRateKHR", 4444, 1, pygen_variable_caps_FragmentShadingRateKHR, 1, pygen_variable_exts_SPV_KHR_fragment_shading_rate, {}, 0xffffffffu, 0xffffffffu}, {"BaryCoordNoPerspAMD", 4992, 0, nullptr, 1, pygen_variable_exts_SPV_AMD_shader_explicit_vertex_parameter, {}, 0xffffffffu, 0xffffffffu}, {"BaryCoordNoPerspCentroidAMD", 4993, 0, nullptr, 1, pygen_variable_exts_SPV_AMD_shader_explicit_vertex_parameter, {}, 0xffffffffu, 0xffffffffu}, {"BaryCoordNoPerspSampleAMD", 4994, 0, nullptr, 1, pygen_variable_exts_SPV_AMD_shader_explicit_vertex_parameter, {}, 0xffffffffu, 0xffffffffu}, @@ -862,6 +877,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"GroupNonUniformQuad", 68, 1, pygen_variable_caps_GroupNonUniform, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu}, {"ShaderLayer", 69, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, {"ShaderViewportIndex", 70, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, + {"FragmentShadingRateKHR", 4422, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_fragment_shading_rate, {}, 0xffffffffu, 0xffffffffu}, {"SubgroupBallotKHR", 4423, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_shader_ballot, {}, 0xffffffffu, 0xffffffffu}, {"DrawParameters", 4427, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_shader_draw_parameters, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu}, {"SubgroupVoteKHR", 4431, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_subgroup_vote, {}, 0xffffffffu, 0xffffffffu}, @@ -892,6 +908,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"FragmentMaskAMD", 5010, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_AMD_shader_fragment_mask, {}, 0xffffffffu, 0xffffffffu}, {"StencilExportEXT", 5013, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_stencil_export, {}, 0xffffffffu, 0xffffffffu}, {"ImageReadWriteLodAMD", 5015, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_AMD_shader_image_load_store_lod, {}, 0xffffffffu, 0xffffffffu}, + {"Int64ImageEXT", 5016, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_image_int64, {}, 0xffffffffu, 0xffffffffu}, {"ShaderClockKHR", 5055, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_shader_clock, {}, 0xffffffffu, 0xffffffffu}, {"SampleMaskOverrideCoverageNV", 5249, 1, pygen_variable_caps_SampleRateShading, 1, pygen_variable_exts_SPV_NV_sample_mask_override_coverage, {}, 0xffffffffu, 0xffffffffu}, {"GeometryShaderPassthroughNV", 5251, 1, pygen_variable_caps_Geometry, 1, pygen_variable_exts_SPV_NV_geometry_shader_passthrough, {}, 0xffffffffu, 0xffffffffu}, @@ -1110,6 +1127,7 @@ static const spv_operand_desc_group_t pygen_variable_OperandInfoTable[] = { {SPV_OPERAND_TYPE_MEMORY_ACCESS, ARRAY_SIZE(pygen_variable_MemoryAccessEntries), pygen_variable_MemoryAccessEntries}, {SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO, ARRAY_SIZE(pygen_variable_KernelProfilingInfoEntries), pygen_variable_KernelProfilingInfoEntries}, {SPV_OPERAND_TYPE_RAY_FLAGS, ARRAY_SIZE(pygen_variable_RayFlagsEntries), pygen_variable_RayFlagsEntries}, + {SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, ARRAY_SIZE(pygen_variable_FragmentShadingRateEntries), pygen_variable_FragmentShadingRateEntries}, {SPV_OPERAND_TYPE_SOURCE_LANGUAGE, ARRAY_SIZE(pygen_variable_SourceLanguageEntries), pygen_variable_SourceLanguageEntries}, {SPV_OPERAND_TYPE_EXECUTION_MODEL, ARRAY_SIZE(pygen_variable_ExecutionModelEntries), pygen_variable_ExecutionModelEntries}, {SPV_OPERAND_TYPE_ADDRESSING_MODEL, ARRAY_SIZE(pygen_variable_AddressingModelEntries), pygen_variable_AddressingModelEntries}, diff --git a/3rdparty/spirv-tools/include/spirv-tools/libspirv.h b/3rdparty/spirv-tools/include/spirv-tools/libspirv.h index 6c7b5de57..a441d3573 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/libspirv.h +++ b/3rdparty/spirv-tools/include/spirv-tools/libspirv.h @@ -176,12 +176,13 @@ typedef enum spv_operand_type_t { // Set 5: Operands that are a single word bitmask. // Sometimes a set bit indicates the instruction requires still more operands. - SPV_OPERAND_TYPE_IMAGE, // SPIR-V Sec 3.14 - SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, // SPIR-V Sec 3.15 - SPV_OPERAND_TYPE_SELECTION_CONTROL, // SPIR-V Sec 3.22 - SPV_OPERAND_TYPE_LOOP_CONTROL, // SPIR-V Sec 3.23 - SPV_OPERAND_TYPE_FUNCTION_CONTROL, // SPIR-V Sec 3.24 - SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26 + SPV_OPERAND_TYPE_IMAGE, // SPIR-V Sec 3.14 + SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, // SPIR-V Sec 3.15 + SPV_OPERAND_TYPE_SELECTION_CONTROL, // SPIR-V Sec 3.22 + SPV_OPERAND_TYPE_LOOP_CONTROL, // SPIR-V Sec 3.23 + SPV_OPERAND_TYPE_FUNCTION_CONTROL, // SPIR-V Sec 3.24 + SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26 + SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, // SPIR-V Sec 3.FSR // The remaining operand types are only used internally by the assembler. // There are two categories: diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index d89d3b6fc..f12774d6d 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp @@ -536,28 +536,16 @@ Optimizer::PassToken CreateDeadInsertElimPass(); // eliminated with standard dead code elimination. Optimizer::PassToken CreateAggressiveDCEPass(); -// Create line propagation pass -// This pass propagates line information based on the rules for OpLine and -// OpNoline and clones an appropriate line instruction into every instruction -// which does not already have debug line instructions. -// -// This pass is intended to maximize preservation of source line information -// through passes which delete, move and clone instructions. Ideally it should -// be run before any such pass. It is a bookend pass with EliminateDeadLines -// which can be used to remove redundant line instructions at the end of a -// run of such passes and reduce final output file size. +// Creates an empty pass. +// This is deprecated and will be removed. +// TODO(jaebaek): remove this pass after handling glslang's broken unit tests. +// https://github.com/KhronosGroup/glslang/pull/2440 Optimizer::PassToken CreatePropagateLineInfoPass(); -// Create dead line elimination pass -// This pass eliminates redundant line instructions based on the rules for -// OpLine and OpNoline. Its main purpose is to reduce the size of the file -// need to store the SPIR-V without losing line information. -// -// This is a bookend pass with PropagateLines which attaches line instructions -// to every instruction to preserve line information during passes which -// delete, move and clone instructions. DeadLineElim should be run after -// PropagateLines and all such subsequent passes. Normally it would be one -// of the last passes to be run. +// Creates an empty pass. +// This is deprecated and will be removed. +// TODO(jaebaek): remove this pass after handling glslang's broken unit tests. +// https://github.com/KhronosGroup/glslang/pull/2440 Optimizer::PassToken CreateRedundantLineInfoElimPass(); // Creates a compact ids pass. diff --git a/3rdparty/spirv-tools/source/CMakeLists.txt b/3rdparty/spirv-tools/source/CMakeLists.txt index fa900e03e..65087f2c9 100644 --- a/3rdparty/spirv-tools/source/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/CMakeLists.txt @@ -346,58 +346,64 @@ set_source_files_properties( spvtools_pch(SPIRV_SOURCES pch_source) -add_library(${SPIRV_TOOLS}-static STATIC ${SPIRV_SOURCES}) -spvtools_default_compile_options(${SPIRV_TOOLS}-static) -target_include_directories(${SPIRV_TOOLS}-static - PUBLIC - $ - $ - PRIVATE ${spirv-tools_BINARY_DIR} - PRIVATE ${SPIRV_HEADER_INCLUDE_DIR} +# spirv_tools_default_target_options() sets the target options that are common +# for all ${SPIRV_TOOLS} targets. +function(spirv_tools_default_target_options target) + spvtools_default_compile_options(${target}) + target_include_directories(${target} + PUBLIC + $ + $ + PRIVATE ${spirv-tools_BINARY_DIR} + PRIVATE ${SPIRV_HEADER_INCLUDE_DIR} ) -set_property(TARGET ${SPIRV_TOOLS}-static PROPERTY FOLDER "SPIRV-Tools libraries") -spvtools_check_symbol_exports(${SPIRV_TOOLS}-static) -add_dependencies(${SPIRV_TOOLS}-static core_tables enum_string_mapping extinst_tables) - -# The static target does not have the '-static' suffix. -set_target_properties(${SPIRV_TOOLS}-static PROPERTIES OUTPUT_NAME "${SPIRV_TOOLS}") + set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools libraries") + spvtools_check_symbol_exports(${target}) + add_dependencies(${target} core_tables enum_string_mapping extinst_tables) +endfunction() +# Always build ${SPIRV_TOOLS}-shared. This is expected distro packages, and +# unlike the other SPIRV_TOOLS target, defaults to hidden symbol visibility. add_library(${SPIRV_TOOLS}-shared SHARED ${SPIRV_SOURCES}) -spvtools_default_compile_options(${SPIRV_TOOLS}-shared) -target_include_directories(${SPIRV_TOOLS}-shared - PUBLIC - $ - $ - PRIVATE ${spirv-tools_BINARY_DIR} - PRIVATE ${SPIRV_HEADER_INCLUDE_DIR} - ) +spirv_tools_default_target_options(${SPIRV_TOOLS}-shared) set_target_properties(${SPIRV_TOOLS}-shared PROPERTIES CXX_VISIBILITY_PRESET hidden) -set_property(TARGET ${SPIRV_TOOLS}-shared PROPERTY FOLDER "SPIRV-Tools libraries") -spvtools_check_symbol_exports(${SPIRV_TOOLS}-shared) target_compile_definitions(${SPIRV_TOOLS}-shared PRIVATE SPIRV_TOOLS_IMPLEMENTATION PUBLIC SPIRV_TOOLS_SHAREDLIB ) -add_dependencies(${SPIRV_TOOLS}-shared core_tables enum_string_mapping extinst_tables) -# Create the "${SPIRV_TOOLS}" target as an alias to either "${SPIRV_TOOLS}-static" -# or "${SPIRV_TOOLS}-shared" depending on the value of BUILD_SHARED_LIBS. -if(BUILD_SHARED_LIBS) +if(SPIRV_TOOLS_BUILD_STATIC) + add_library(${SPIRV_TOOLS}-static STATIC ${SPIRV_SOURCES}) + spirv_tools_default_target_options(${SPIRV_TOOLS}-static) + # The static target does not have the '-static' suffix. + set_target_properties(${SPIRV_TOOLS}-static PROPERTIES OUTPUT_NAME "${SPIRV_TOOLS}") + + # Create the "${SPIRV_TOOLS}" target as an alias to either "${SPIRV_TOOLS}-static" + # or "${SPIRV_TOOLS}-shared" depending on the value of BUILD_SHARED_LIBS. + if(BUILD_SHARED_LIBS) add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-shared) -else() + else() add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-static) + endif() + + set(SPIRV_TOOLS_TARGETS ${SPIRV_TOOLS}-static ${SPIRV_TOOLS}-shared) +else() + add_library(${SPIRV_TOOLS} ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_SOURCES}) + spirv_tools_default_target_options(${SPIRV_TOOLS}) + set(SPIRV_TOOLS_TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared) endif() if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") find_library(LIBRT rt) if(LIBRT) - target_link_libraries(${SPIRV_TOOLS}-static ${LIBRT}) - target_link_libraries(${SPIRV_TOOLS}-shared ${LIBRT}) + foreach(target ${SPIRV_TOOLS_TARGETS}) + target_link_libraries(${target} ${LIBRT}) + endforeach() endif() endif() if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS ${SPIRV_TOOLS}-static ${SPIRV_TOOLS}-shared EXPORT ${SPIRV_TOOLS}Targets + install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/3rdparty/spirv-tools/source/cfa.h b/3rdparty/spirv-tools/source/cfa.h index 17a4ea5b4..0d09014c9 100644 --- a/3rdparty/spirv-tools/source/cfa.h +++ b/3rdparty/spirv-tools/source/cfa.h @@ -127,7 +127,7 @@ class CFA { template bool CFA::FindInWorkList(const std::vector& work_list, uint32_t id) { - for (auto& b : work_list) { + for (const auto& b : work_list) { if (b.block->id() == id) return true; } return false; diff --git a/3rdparty/spirv-tools/source/link/CMakeLists.txt b/3rdparty/spirv-tools/source/link/CMakeLists.txt index bb058ea22..c8dd2f715 100644 --- a/3rdparty/spirv-tools/source/link/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/link/CMakeLists.txt @@ -11,7 +11,7 @@ # 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. -add_library(SPIRV-Tools-link STATIC +add_library(SPIRV-Tools-link ${SPIRV_TOOLS_LIBRARY_TYPE} linker.cpp ) diff --git a/3rdparty/spirv-tools/source/operand.cpp b/3rdparty/spirv-tools/source/operand.cpp index 7b2b98f2d..d4b64a8b8 100644 --- a/3rdparty/spirv-tools/source/operand.cpp +++ b/3rdparty/spirv-tools/source/operand.cpp @@ -208,6 +208,8 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { case SPV_OPERAND_TYPE_MEMORY_ACCESS: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: return "memory access"; + case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE: + return "shading rate"; case SPV_OPERAND_TYPE_SCOPE_ID: return "scope ID"; case SPV_OPERAND_TYPE_GROUP_OPERATION: @@ -360,6 +362,7 @@ bool spvOperandIsConcreteMask(spv_operand_type_t type) { case SPV_OPERAND_TYPE_LOOP_CONTROL: case SPV_OPERAND_TYPE_FUNCTION_CONTROL: case SPV_OPERAND_TYPE_MEMORY_ACCESS: + case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: return true; diff --git a/3rdparty/spirv-tools/source/opt/CMakeLists.txt b/3rdparty/spirv-tools/source/opt/CMakeLists.txt index 3630a0605..f3ac59060 100644 --- a/3rdparty/spirv-tools/source/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/opt/CMakeLists.txt @@ -43,6 +43,7 @@ set(SPIRV_TOOLS_OPT_SOURCES eliminate_dead_functions_pass.h eliminate_dead_functions_util.h eliminate_dead_members_pass.h + empty_pass.h feature_manager.h fix_storage_class.h flatten_decoration_pass.h @@ -89,7 +90,6 @@ set(SPIRV_TOOLS_OPT_SOURCES pass.h pass_manager.h private_to_local_pass.h - process_lines_pass.h propagator.h reduce_load_size.h redundancy_elimination.h @@ -196,7 +196,6 @@ set(SPIRV_TOOLS_OPT_SOURCES pass.cpp pass_manager.cpp private_to_local_pass.cpp - process_lines_pass.cpp propagator.cpp reduce_load_size.cpp redundancy_elimination.cpp @@ -233,7 +232,7 @@ endif() spvtools_pch(SPIRV_TOOLS_OPT_SOURCES pch_source_opt) -add_library(SPIRV-Tools-opt STATIC ${SPIRV_TOOLS_OPT_SOURCES}) +add_library(SPIRV-Tools-opt ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_TOOLS_OPT_SOURCES}) spvtools_default_compile_options(SPIRV-Tools-opt) target_include_directories(SPIRV-Tools-opt @@ -245,7 +244,7 @@ target_include_directories(SPIRV-Tools-opt ) # We need the assembling and disassembling functionalities in the main library. target_link_libraries(SPIRV-Tools-opt - PUBLIC ${SPIRV_TOOLS}-static) + PUBLIC ${SPIRV_TOOLS_FULL_VISIBILITY}) set_property(TARGET SPIRV-Tools-opt PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(SPIRV-Tools-opt) diff --git a/3rdparty/spirv-tools/source/opt/ccp_pass.cpp b/3rdparty/spirv-tools/source/opt/ccp_pass.cpp index 2d19bcb38..d84f13f5d 100644 --- a/3rdparty/spirv-tools/source/opt/ccp_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/ccp_pass.cpp @@ -135,23 +135,15 @@ SSAPropagator::PropStatus CCPPass::VisitAssignment(Instruction* instr) { } return it->second; }; - uint32_t next_id = context()->module()->IdBound(); Instruction* folded_inst = context()->get_instruction_folder().FoldInstructionToConstant(instr, map_func); + if (folded_inst != nullptr) { // We do not want to change the body of the function by adding new // instructions. When folding we can only generate new constants. assert(folded_inst->IsConstant() && "CCP is only interested in constant."); values_[instr->result_id()] = folded_inst->result_id(); - - // If the folded instruction has just been created, its result ID will - // match the previous ID bound. When this happens, we need to indicate - // that CCP has modified the IR, independently of whether the constant is - // actually propagated. See - // https://github.com/KhronosGroup/SPIRV-Tools/issues/3636 for details. - if (folded_inst->result_id() >= next_id) created_new_constant_ = true; - return SSAPropagator::kInteresting; } @@ -278,10 +270,14 @@ bool CCPPass::ReplaceValues() { // Even if we make no changes to the function's IR, propagation may have // created new constants. Even if those constants cannot be replaced in // the IR, the constant definition itself is a change. To reflect this, - // we initialize the IR changed indicator with the value of the - // created_new_constant_ indicator. For an example, see the bug reported - // in https://github.com/KhronosGroup/SPIRV-Tools/issues/3636. - bool changed_ir = created_new_constant_; + // we check whether the next ID to be given by the module is different than + // the original bound ID. If that happens, new instructions were added to the + // module during propagation. + // + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/3636 and + // https://github.com/KhronosGroup/SPIRV-Tools/issues/3991 for details. + bool changed_ir = (context()->module()->IdBound() > original_id_bound_); + for (const auto& it : values_) { uint32_t id = it.first; uint32_t cst_id = it.second; @@ -290,6 +286,7 @@ bool CCPPass::ReplaceValues() { changed_ir |= context()->ReplaceAllUsesWith(id, cst_id); } } + return changed_ir; } @@ -329,7 +326,7 @@ void CCPPass::Initialize() { } } - created_new_constant_ = false; + original_id_bound_ = context()->module()->IdBound(); } Pass::Status CCPPass::Process() { diff --git a/3rdparty/spirv-tools/source/opt/ccp_pass.h b/3rdparty/spirv-tools/source/opt/ccp_pass.h index 83c4ab97b..fb20c7808 100644 --- a/3rdparty/spirv-tools/source/opt/ccp_pass.h +++ b/3rdparty/spirv-tools/source/opt/ccp_pass.h @@ -106,8 +106,9 @@ class CCPPass : public MemPass { // Propagator engine used. std::unique_ptr propagator_; - // True if the pass created new constant instructions during propagation. - bool created_new_constant_; + // Value for the module's ID bound before running CCP. Used to detect whether + // propagation created new instructions. + uint32_t original_id_bound_; }; } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp index 4941d648e..48285bda6 100644 --- a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp @@ -40,7 +40,6 @@ static const uint32_t kDebugLocalVariableOperandParentIndex = 9; static const uint32_t kExtInstInstructionInIdx = 1; static const uint32_t kDebugGlobalVariableOperandFlagsIndex = 12; static const uint32_t kDebugLocalVariableOperandFlagsIndex = 10; -static const uint32_t kDebugLocalVariableOperandArgNumberIndex = 11; namespace spvtools { namespace opt { @@ -441,32 +440,40 @@ bool DebugInfoManager::IsAncestorOfScope(uint32_t scope, uint32_t ancestor) { return false; } -Instruction* DebugInfoManager::GetDebugLocalVariableFromDeclare( - Instruction* dbg_declare) { - assert(dbg_declare); +bool DebugInfoManager::IsDeclareVisibleToInstr(Instruction* dbg_declare, + Instruction* scope) { + assert(dbg_declare != nullptr); + assert(scope != nullptr); + + std::vector scope_ids; + if (scope->opcode() == SpvOpPhi) { + scope_ids.push_back(scope->GetDebugScope().GetLexicalScope()); + for (uint32_t i = 0; i < scope->NumInOperands(); i += 2) { + auto* value = context()->get_def_use_mgr()->GetDef( + scope->GetSingleWordInOperand(i)); + if (value != nullptr) + scope_ids.push_back(value->GetDebugScope().GetLexicalScope()); + } + } else { + scope_ids.push_back(scope->GetDebugScope().GetLexicalScope()); + } + uint32_t dbg_local_var_id = dbg_declare->GetSingleWordOperand(kDebugDeclareOperandLocalVariableIndex); auto dbg_local_var_itr = id_to_dbg_inst_.find(dbg_local_var_id); assert(dbg_local_var_itr != id_to_dbg_inst_.end()); - return dbg_local_var_itr->second; -} - -bool DebugInfoManager::IsFunctionParameter(Instruction* dbg_local_var) const { - // If a DebugLocalVariable has ArgNumber operand, it is a function parameter. - return dbg_local_var->NumOperands() > - kDebugLocalVariableOperandArgNumberIndex; -} - -bool DebugInfoManager::IsLocalVariableVisibleToInstr(Instruction* dbg_local_var, - uint32_t instr_scope_id) { - if (instr_scope_id == kNoDebugScope) return false; - - uint32_t decl_scope_id = dbg_local_var->GetSingleWordOperand( + uint32_t decl_scope_id = dbg_local_var_itr->second->GetSingleWordOperand( kDebugLocalVariableOperandParentIndex); // If the scope of DebugDeclare is an ancestor scope of the instruction's // scope, the local variable is visible to the instruction. - return IsAncestorOfScope(instr_scope_id, decl_scope_id); + for (uint32_t scope_id : scope_ids) { + if (scope_id != kNoDebugScope && + IsAncestorOfScope(scope_id, decl_scope_id)) { + return true; + } + } + return false; } Instruction* DebugInfoManager::AddDebugValueWithIndex( @@ -509,26 +516,21 @@ Instruction* DebugInfoManager::AddDebugValueWithIndex( void DebugInfoManager::AddDebugValueIfVarDeclIsVisible( Instruction* scope_and_line, uint32_t variable_id, uint32_t value_id, - Instruction* insert_pos) { + Instruction* insert_pos, + std::unordered_set* invisible_decls) { auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id); if (dbg_decl_itr == var_id_to_dbg_decl_.end()) return; - uint32_t instr_scope_id = scope_and_line->GetDebugScope().GetLexicalScope(); for (auto* dbg_decl_or_val : dbg_decl_itr->second) { - // If it declares a function parameter, the store instruction for the - // function parameter can exist out of the function parameter's scope - // because of the function inlining. We always add DebugValue for a - // function parameter next to the DebugDeclare regardless of the scope. - auto* dbg_local_var = GetDebugLocalVariableFromDeclare(dbg_decl_or_val); - bool is_function_param = IsFunctionParameter(dbg_local_var); - if (!is_function_param && - !IsLocalVariableVisibleToInstr(dbg_local_var, instr_scope_id)) + if (scope_and_line && + !IsDeclareVisibleToInstr(dbg_decl_or_val, scope_and_line)) { + if (invisible_decls) invisible_decls->insert(dbg_decl_or_val); continue; + } // Avoid inserting the new DebugValue between OpPhi or OpVariable // instructions. - Instruction* insert_before = is_function_param ? dbg_decl_or_val->NextNode() - : insert_pos->NextNode(); + Instruction* insert_before = insert_pos->NextNode(); while (insert_before->opcode() == SpvOpPhi || insert_before->opcode() == SpvOpVariable) { insert_before = insert_before->NextNode(); @@ -545,12 +547,36 @@ void DebugInfoManager::AddDebugValueIfVarDeclIsVisible( kDebugValueOperandLocalVariableIndex), value_id, 0, index_id, insert_before); assert(added_dbg_value != nullptr); - added_dbg_value->UpdateDebugInfoFrom(is_function_param ? dbg_decl_or_val - : scope_and_line); + added_dbg_value->UpdateDebugInfoFrom(scope_and_line ? scope_and_line + : dbg_decl_or_val); AnalyzeDebugInst(added_dbg_value); } } +bool DebugInfoManager::AddDebugValueForDecl(Instruction* dbg_decl, + uint32_t value_id) { + if (dbg_decl == nullptr || !IsDebugDeclare(dbg_decl)) return false; + + std::unique_ptr dbg_val(dbg_decl->Clone(context())); + dbg_val->SetResultId(context()->TakeNextId()); + dbg_val->SetInOperand(kExtInstInstructionInIdx, + {OpenCLDebugInfo100DebugValue}); + dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id}); + dbg_val->SetOperand(kDebugValueOperandExpressionIndex, + {GetEmptyDebugExpression()->result_id()}); + + auto* added_dbg_val = dbg_decl->InsertBefore(std::move(dbg_val)); + AnalyzeDebugInst(added_dbg_val); + if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse)) + context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_val); + if (context()->AreAnalysesValid( + IRContext::Analysis::kAnalysisInstrToBlockMapping)) { + auto insert_blk = context()->get_instr_block(dbg_decl); + context()->set_instr_block(added_dbg_val, insert_blk); + } + return true; +} + uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare( Instruction* inst) { if (inst->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugValue) return 0; diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.h b/3rdparty/spirv-tools/source/opt/debug_info_manager.h index bf398b467..edb11b73f 100644 --- a/3rdparty/spirv-tools/source/opt/debug_info_manager.h +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.h @@ -144,9 +144,11 @@ class DebugInfoManager { // Generates a DebugValue instruction with value |value_id| for every local // variable that is in the scope of |scope_and_line| and whose memory is // |variable_id| and inserts it after the instruction |insert_pos|. - void AddDebugValueIfVarDeclIsVisible(Instruction* scope_and_line, - uint32_t variable_id, uint32_t value_id, - Instruction* insert_pos); + // |invisible_decls| returns DebugDeclares invisible to |scope_and_line|. + void AddDebugValueIfVarDeclIsVisible( + Instruction* scope_and_line, uint32_t variable_id, uint32_t value_id, + Instruction* insert_pos, + std::unordered_set* invisible_decls); // Generates a DebugValue instruction with |dbg_local_var_id|, |value_id|, // |expr_id|, |index_id| operands and inserts it before |insert_before|. @@ -155,6 +157,11 @@ class DebugInfoManager { uint32_t index_id, Instruction* insert_before); + // Adds DebugValue for DebugDeclare |dbg_decl|. The new DebugValue has the + // same line, scope, and operands but it uses |value_id| for value. Returns + // weather it succeeds or not. + bool AddDebugValueForDecl(Instruction* dbg_decl, uint32_t value_id); + // Erases |instr| from data structures of this class. void ClearDebugInfo(Instruction* instr); @@ -215,17 +222,9 @@ class DebugInfoManager { // of |scope|. bool IsAncestorOfScope(uint32_t scope, uint32_t ancestor); - // Returns the DebugLocalVariable declared by |dbg_declare|. - Instruction* GetDebugLocalVariableFromDeclare(Instruction* dbg_declare); - - // Returns true if the DebugLocalVariable |dbg_local_var| is a function - // parameter. - bool IsFunctionParameter(Instruction* dbg_local_var) const; - - // Returns true if the DebugLocalVariable |dbg_local_var| is visible - // in the scope of an instruction |instr_scope_id|. - bool IsLocalVariableVisibleToInstr(Instruction* dbg_local_var, - uint32_t instr_scope_id); + // Returns true if the declaration of a local variable |dbg_declare| + // is visible in the scope of an instruction |instr_scope_id|. + bool IsDeclareVisibleToInstr(Instruction* dbg_declare, Instruction* scope); // Returns the parent scope of the scope |child_scope|. uint32_t GetParentScope(uint32_t child_scope); diff --git a/3rdparty/spirv-tools/source/opt/empty_pass.h b/3rdparty/spirv-tools/source/opt/empty_pass.h new file mode 100644 index 000000000..1fd2ae59b --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/empty_pass.h @@ -0,0 +1,36 @@ +// Copyright (c) 2020 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_EMPTY_PASS_H_ +#define SOURCE_OPT_EMPTY_PASS_H_ + +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Documented in optimizer.hpp +class EmptyPass : public Pass { + public: + EmptyPass() {} + + const char* name() const override { return "empty-pass"; } + + Status Process() override { return Status::SuccessWithoutChange; } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_EMPTY_PASS_H_ diff --git a/3rdparty/spirv-tools/source/opt/function.h b/3rdparty/spirv-tools/source/opt/function.h index b7c17a6b2..4b20dcb9b 100644 --- a/3rdparty/spirv-tools/source/opt/function.h +++ b/3rdparty/spirv-tools/source/opt/function.h @@ -94,6 +94,9 @@ class Function { // Returns function's return type id inline uint32_t type_id() const { return def_inst_->type_id(); } + // Returns the function's control mask + inline uint32_t control_mask() const { return def_inst_->GetSingleWordInOperand(0); } + // Returns the entry basic block for this function. const std::unique_ptr& entry() const { return blocks_.front(); } diff --git a/3rdparty/spirv-tools/source/opt/inline_pass.cpp b/3rdparty/spirv-tools/source/opt/inline_pass.cpp index 6021a7c53..eaf29aa05 100644 --- a/3rdparty/spirv-tools/source/opt/inline_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/inline_pass.cpp @@ -727,6 +727,12 @@ void InlinePass::AnalyzeReturns(Function* func) { bool InlinePass::IsInlinableFunction(Function* func) { // We can only inline a function if it has blocks. if (func->cbegin() == func->cend()) return false; + + // Do not inline functions with DontInline flag. + if (func->control_mask() & SpvFunctionControlDontInlineMask) { + return false; + } + // Do not inline functions with returns in loops. Currently early return // functions are inlined by wrapping them in a one trip loop and implementing // the returns as a branch to the loop's merge block. However, this can only diff --git a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.cpp b/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.cpp index 3691414c5..64d389ca4 100644 --- a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.cpp @@ -349,8 +349,9 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref, : SpvDecorationArrayStride; uint32_t arr_stride = FindStride(curr_ty_id, stride_deco); uint32_t arr_stride_id = builder->GetUintConstantId(arr_stride); + uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder); Instruction* curr_offset_inst = builder->AddBinaryOp( - GetUintId(), SpvOpIMul, arr_stride_id, curr_idx_id); + GetUintId(), SpvOpIMul, arr_stride_id, curr_idx_32b_id); curr_offset_id = curr_offset_inst->result_id(); // Get element type for next step curr_ty_id = curr_ty_inst->GetSingleWordInOperand(0); @@ -360,8 +361,9 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref, uint32_t comp_ty_id = curr_ty_inst->GetSingleWordInOperand(0u); uint32_t vec_stride = ByteSize(comp_ty_id); uint32_t vec_stride_id = builder->GetUintConstantId(vec_stride); + uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder); Instruction* curr_offset_inst = builder->AddBinaryOp( - GetUintId(), SpvOpIMul, vec_stride_id, curr_idx_id); + GetUintId(), SpvOpIMul, vec_stride_id, curr_idx_32b_id); curr_offset_id = curr_offset_inst->result_id(); // Get element type for next step curr_ty_id = comp_ty_id; @@ -434,18 +436,27 @@ void InstBindlessCheckPass::GenCheckCode( new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); builder.SetInsertPoint(&*new_blk_ptr); uint32_t u_index_id = GenUintCastCode(ref->desc_idx_id, &builder); - if (offset_id != 0) + if (offset_id != 0) { + // Buffer OOB + uint32_t u_offset_id = GenUintCastCode(offset_id, &builder); + uint32_t u_length_id = GenUintCastCode(length_id, &builder); GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_index_id, offset_id, length_id}, &builder); - else if (buffer_bounds_enabled_) - // So all error modes will use same debug stream write function + {error_id, u_index_id, u_offset_id, u_length_id}, + &builder); + } else if (buffer_bounds_enabled_) { + // Uninitialized Descriptor - Return additional unused zero so all error + // modes will use same debug stream write function + uint32_t u_length_id = GenUintCastCode(length_id, &builder); GenDebugStreamWrite( uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_index_id, length_id, builder.GetUintConstantId(0)}, + {error_id, u_index_id, u_length_id, builder.GetUintConstantId(0)}, &builder); - else + } else { + // Uninitialized Descriptor - Normal error return + uint32_t u_length_id = GenUintCastCode(length_id, &builder); GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_index_id, length_id}, &builder); + {error_id, u_index_id, u_length_id}, &builder); + } // Remember last invalid block id uint32_t last_invalid_blk_id = new_blk_ptr->GetLabelInst()->result_id(); // Gen zero for invalid reference @@ -516,8 +527,11 @@ void InstBindlessCheckPass::GenDescIdxCheckCode( // Generate full runtime bounds test code with true branch // being full reference and false branch being debug output and zero // for the referenced value. + uint32_t desc_idx_32b_id = Gen32BitCvtCode(ref.desc_idx_id, &builder); + uint32_t length_32b_id = Gen32BitCvtCode(length_id, &builder); Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, - ref.desc_idx_id, length_id); + desc_idx_32b_id, length_32b_id); + ref.desc_idx_id = desc_idx_32b_id; GenCheckCode(ult_inst->result_id(), error_id, 0u, length_id, stage_idx, &ref, new_blocks); // Move original block's remaining code into remainder/merge block and add diff --git a/3rdparty/spirv-tools/source/opt/instruction.cpp b/3rdparty/spirv-tools/source/opt/instruction.cpp index 961826139..1054a2039 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.cpp +++ b/3rdparty/spirv-tools/source/opt/instruction.cpp @@ -527,7 +527,7 @@ void Instruction::UpdateDebugInfoFrom(const Instruction* from) { if (from == nullptr) return; clear_dbg_line_insts(); if (!from->dbg_line_insts().empty()) - dbg_line_insts().push_back(from->dbg_line_insts()[0]); + dbg_line_insts().push_back(from->dbg_line_insts().back()); SetDebugScope(from->GetDebugScope()); if (!IsDebugLineInst(opcode()) && context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) { diff --git a/3rdparty/spirv-tools/source/opt/instrument_pass.cpp b/3rdparty/spirv-tools/source/opt/instrument_pass.cpp index 6ee3cf040..e7d97789c 100644 --- a/3rdparty/spirv-tools/source/opt/instrument_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/instrument_pass.cpp @@ -88,12 +88,36 @@ std::unique_ptr InstrumentPass::NewLabel(uint32_t label_id) { return newLabel; } +uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id, + InstructionBuilder* builder) { + // Convert integer value to 32-bit if necessary + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_id)->type_id(); + analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger(); + if (val_ty->width() == 32) return val_id; + bool is_signed = val_ty->IsSigned(); + analysis::Integer val_32b_ty(32, is_signed); + analysis::Type* val_32b_reg_ty = type_mgr->GetRegisteredType(&val_32b_ty); + uint32_t val_32b_reg_ty_id = type_mgr->GetId(val_32b_reg_ty); + if (is_signed) + return builder->AddUnaryOp(val_32b_reg_ty_id, SpvOpSConvert, val_id) + ->result_id(); + else + return builder->AddUnaryOp(val_32b_reg_ty_id, SpvOpUConvert, val_id) + ->result_id(); +} + uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id, InstructionBuilder* builder) { - // Cast value to 32-bit unsigned if necessary - if (get_def_use_mgr()->GetDef(val_id)->type_id() == GetUintId()) - return val_id; - return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_id)->result_id(); + // Convert value to 32-bit if necessary + uint32_t val_32b_id = Gen32BitCvtCode(val_id, builder); + // Cast value to unsigned if necessary + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_32b_id)->type_id(); + analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger(); + if (!val_ty->IsSigned()) return val_32b_id; + return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_32b_id) + ->result_id(); } void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id, diff --git a/3rdparty/spirv-tools/source/opt/instrument_pass.h b/3rdparty/spirv-tools/source/opt/instrument_pass.h index 03c99bd9a..12b939d4d 100644 --- a/3rdparty/spirv-tools/source/opt/instrument_pass.h +++ b/3rdparty/spirv-tools/source/opt/instrument_pass.h @@ -213,8 +213,12 @@ class InstrumentPass : public Pass { uint32_t GenDebugDirectRead(const std::vector& offset_ids, InstructionBuilder* builder); - // Generate code to cast |value_id| to unsigned, if needed. Return - // an id to the unsigned equivalent. + // Generate code to convert integer |value_id| to 32bit, if needed. Return + // an id to the 32bit equivalent. + uint32_t Gen32BitCvtCode(uint32_t value_id, InstructionBuilder* builder); + + // Generate code to cast integer |value_id| to 32bit unsigned, if needed. + // Return an id to the Uint equivalent. uint32_t GenUintCastCode(uint32_t value_id, InstructionBuilder* builder); // Return new label. diff --git a/3rdparty/spirv-tools/source/opt/ir_loader.cpp b/3rdparty/spirv-tools/source/opt/ir_loader.cpp index a10812e48..4a4430944 100644 --- a/3rdparty/spirv-tools/source/opt/ir_loader.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_loader.cpp @@ -41,6 +41,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { ++inst_index_; const auto opcode = static_cast(inst->opcode); if (IsDebugLineInst(opcode)) { + last_line_inst_.reset(); dbg_line_info_.push_back( Instruction(module()->context(), *inst, last_dbg_scope_)); return true; @@ -90,7 +91,16 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { std::unique_ptr spv_inst( new Instruction(module()->context(), *inst, std::move(dbg_line_info_))); - dbg_line_info_.clear(); + if (!spv_inst->dbg_line_insts().empty()) { + if (spv_inst->dbg_line_insts().back().opcode() != SpvOpNoLine) { + last_line_inst_ = std::unique_ptr( + spv_inst->dbg_line_insts().back().Clone(module()->context())); + } + dbg_line_info_.clear(); + } else if (last_line_inst_ != nullptr) { + last_line_inst_->SetDebugScope(last_dbg_scope_); + spv_inst->dbg_line_insts().push_back(*last_line_inst_); + } const char* src = source_.c_str(); spv_position_t loc = {inst_index_, 0, 0}; @@ -141,6 +151,8 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { function_->AddBasicBlock(std::move(block_)); block_ = nullptr; last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); + last_line_inst_.reset(); + dbg_line_info_.clear(); } else { if (function_ == nullptr) { // Outside function definition SPIRV_ASSERT(consumer_, block_ == nullptr); diff --git a/3rdparty/spirv-tools/source/opt/ir_loader.h b/3rdparty/spirv-tools/source/opt/ir_loader.h index 507992150..d0610f139 100644 --- a/3rdparty/spirv-tools/source/opt/ir_loader.h +++ b/3rdparty/spirv-tools/source/opt/ir_loader.h @@ -78,6 +78,8 @@ class IrLoader { std::unique_ptr block_; // Line related debug instructions accumulated thus far. std::vector dbg_line_info_; + // Line instruction that should be applied to the next instruction. + std::unique_ptr last_line_inst_; // The last DebugScope information that IrLoader::AddInstruction() handled. DebugScope last_dbg_scope_; diff --git a/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp index c3479749e..f1b8177bc 100644 --- a/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp @@ -149,8 +149,8 @@ bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { const analysis::Type* store_type = var_type->AsPointer()->pointee_type(); if (!(store_type->AsStruct() || store_type->AsArray())) { context()->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible( - store_inst, var_id, store_inst->GetSingleWordInOperand(1), - store_inst); + nullptr, var_id, store_inst->GetSingleWordInOperand(1), store_inst, + nullptr); context()->get_debug_info_mgr()->KillDebugDeclares(var_id); } } diff --git a/3rdparty/spirv-tools/source/opt/module.cpp b/3rdparty/spirv-tools/source/opt/module.cpp index 670763152..9d3b0edc6 100644 --- a/3rdparty/spirv-tools/source/opt/module.cpp +++ b/3rdparty/spirv-tools/source/opt/module.cpp @@ -143,8 +143,38 @@ void Module::ToBinary(std::vector* binary, bool skip_nop) const { size_t bound_idx = binary->size() - 2; DebugScope last_scope(kNoDebugScope, kNoInlinedAt); - auto write_inst = [binary, skip_nop, &last_scope, - this](const Instruction* i) { + const Instruction* last_line_inst = nullptr; + bool between_merge_and_branch = false; + auto write_inst = [binary, skip_nop, &last_scope, &last_line_inst, + &between_merge_and_branch, this](const Instruction* i) { + // Skip emitting line instructions between merge and branch instructions. + auto opcode = i->opcode(); + if (between_merge_and_branch && + (opcode == SpvOpLine || opcode == SpvOpNoLine)) { + return; + } + between_merge_and_branch = false; + if (last_line_inst != nullptr) { + // If the current instruction is OpLine and it is the same with + // the last line instruction that is still effective (can be applied + // to the next instruction), we skip writing the current instruction. + if (opcode == SpvOpLine) { + uint32_t operand_index = 0; + if (last_line_inst->WhileEachInOperand( + [&operand_index, i](const uint32_t* word) { + assert(i->NumInOperandWords() > operand_index); + return *word == i->GetSingleWordInOperand(operand_index++); + })) { + return; + } + } else if (opcode != SpvOpNoLine && i->dbg_line_insts().empty()) { + // If the current instruction does not have the line information, + // the last line information is not effective any more. Emit OpNoLine + // to specify it. + binary->push_back((1 << 16) | static_cast(SpvOpNoLine)); + last_line_inst = nullptr; + } + } if (!(skip_nop && i->IsNop())) { const auto& scope = i->GetDebugScope(); if (scope != last_scope) { @@ -157,6 +187,15 @@ void Module::ToBinary(std::vector* binary, bool skip_nop) const { i->ToBinaryWithoutAttachedDebugInsts(binary); } + // Update the last line instruction. + if (IsTerminatorInst(opcode) || opcode == SpvOpNoLine) { + last_line_inst = nullptr; + } else if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) { + between_merge_and_branch = true; + last_line_inst = nullptr; + } else if (opcode == SpvOpLine) { + last_line_inst = i; + } }; ForEachInst(write_inst, true); diff --git a/3rdparty/spirv-tools/source/opt/module.h b/3rdparty/spirv-tools/source/opt/module.h index 2c96f0295..75da8705b 100644 --- a/3rdparty/spirv-tools/source/opt/module.h +++ b/3rdparty/spirv-tools/source/opt/module.h @@ -246,6 +246,12 @@ class Module { // If |skip_nop| is true and this is a OpNop, do nothing. void ToBinary(std::vector* binary, bool skip_nop) const; + // Pushes the binary segments for this instruction into the back of *|binary| + // including all OpLine and OpNoLine even if we can skip emitting some line + // instructions. If |skip_nop| is true and this is a OpNop, do nothing. + void ToBinaryWithAllOpLines(std::vector* binary, + bool skip_nop) const; + // Returns 1 more than the maximum Id value mentioned in the module. uint32_t ComputeIdBound() const; diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index b891124e4..bc1441114 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -339,10 +339,6 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateDescriptorScalarReplacementPass()); } else if (pass_name == "eliminate-dead-code-aggressive") { RegisterPass(CreateAggressiveDCEPass()); - } else if (pass_name == "propagate-line-info") { - RegisterPass(CreatePropagateLineInfoPass()); - } else if (pass_name == "eliminate-redundant-line-info") { - RegisterPass(CreateRedundantLineInfoElimPass()); } else if (pass_name == "eliminate-insert-extract") { RegisterPass(CreateInsertExtractElimPass()); } else if (pass_name == "eliminate-local-single-block") { @@ -758,13 +754,11 @@ Optimizer::PassToken CreateAggressiveDCEPass() { } Optimizer::PassToken CreatePropagateLineInfoPass() { - return MakeUnique( - MakeUnique(opt::kLinesPropagateLines)); + return MakeUnique(MakeUnique()); } Optimizer::PassToken CreateRedundantLineInfoElimPass() { - return MakeUnique( - MakeUnique(opt::kLinesEliminateDeadLines)); + return MakeUnique(MakeUnique()); } Optimizer::PassToken CreateCompactIdsPass() { diff --git a/3rdparty/spirv-tools/source/opt/passes.h b/3rdparty/spirv-tools/source/opt/passes.h index 5b4ab898e..d47cc1cee 100644 --- a/3rdparty/spirv-tools/source/opt/passes.h +++ b/3rdparty/spirv-tools/source/opt/passes.h @@ -35,6 +35,7 @@ #include "source/opt/eliminate_dead_constant_pass.h" #include "source/opt/eliminate_dead_functions_pass.h" #include "source/opt/eliminate_dead_members_pass.h" +#include "source/opt/empty_pass.h" #include "source/opt/fix_storage_class.h" #include "source/opt/flatten_decoration_pass.h" #include "source/opt/fold_spec_constant_op_and_composite_pass.h" @@ -61,7 +62,6 @@ #include "source/opt/merge_return_pass.h" #include "source/opt/null_pass.h" #include "source/opt/private_to_local_pass.h" -#include "source/opt/process_lines_pass.h" #include "source/opt/reduce_load_size.h" #include "source/opt/redundancy_elimination.h" #include "source/opt/relax_float_ops_pass.h" diff --git a/3rdparty/spirv-tools/source/opt/process_lines_pass.cpp b/3rdparty/spirv-tools/source/opt/process_lines_pass.cpp deleted file mode 100644 index 0ae2f7583..000000000 --- a/3rdparty/spirv-tools/source/opt/process_lines_pass.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2018 The Khronos Group Inc. -// Copyright (c) 2018 Valve Corporation -// Copyright (c) 2018 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/process_lines_pass.h" - -#include -#include -#include - -namespace { - -// Input Operand Indices -static const int kSpvLineFileInIdx = 0; -static const int kSpvLineLineInIdx = 1; -static const int kSpvLineColInIdx = 2; - -} // anonymous namespace - -namespace spvtools { -namespace opt { - -Pass::Status ProcessLinesPass::Process() { - bool modified = ProcessLines(); - return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); -} - -bool ProcessLinesPass::ProcessLines() { - bool modified = false; - uint32_t file_id = 0; - uint32_t line = 0; - uint32_t col = 0; - // Process types, globals, constants - for (Instruction& inst : get_module()->types_values()) - modified |= line_process_func_(&inst, &file_id, &line, &col); - // Process functions - for (Function& function : *get_module()) { - modified |= line_process_func_(&function.DefInst(), &file_id, &line, &col); - function.ForEachParam( - [this, &modified, &file_id, &line, &col](Instruction* param) { - modified |= line_process_func_(param, &file_id, &line, &col); - }); - for (BasicBlock& block : function) { - modified |= - line_process_func_(block.GetLabelInst(), &file_id, &line, &col); - for (Instruction& inst : block) { - modified |= line_process_func_(&inst, &file_id, &line, &col); - // Don't process terminal instruction if preceeded by merge - if (inst.opcode() == SpvOpSelectionMerge || - inst.opcode() == SpvOpLoopMerge) - break; - } - // Nullify line info after each block. - file_id = 0; - } - modified |= line_process_func_(function.EndInst(), &file_id, &line, &col); - } - return modified; -} - -bool ProcessLinesPass::PropagateLine(Instruction* inst, uint32_t* file_id, - uint32_t* line, uint32_t* col) { - bool modified = false; - // only the last debug instruction needs to be considered - auto line_itr = inst->dbg_line_insts().rbegin(); - // if no line instructions, propagate previous info - if (line_itr == inst->dbg_line_insts().rend()) { - // if no current line info, add OpNoLine, else OpLine - if (*file_id == 0) - inst->dbg_line_insts().push_back(Instruction(context(), SpvOpNoLine)); - else - inst->dbg_line_insts().push_back(Instruction( - context(), SpvOpLine, 0, 0, - {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*file_id}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {*line}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {*col}}})); - modified = true; - } else { - // else pre-existing line instruction, so update source line info - if (line_itr->opcode() == SpvOpNoLine) { - *file_id = 0; - } else { - assert(line_itr->opcode() == SpvOpLine && "unexpected debug inst"); - *file_id = line_itr->GetSingleWordInOperand(kSpvLineFileInIdx); - *line = line_itr->GetSingleWordInOperand(kSpvLineLineInIdx); - *col = line_itr->GetSingleWordInOperand(kSpvLineColInIdx); - } - } - return modified; -} - -bool ProcessLinesPass::EliminateDeadLines(Instruction* inst, uint32_t* file_id, - uint32_t* line, uint32_t* col) { - // If no debug line instructions, return without modifying lines - if (inst->dbg_line_insts().empty()) return false; - // Only the last debug instruction needs to be considered; delete all others - bool modified = inst->dbg_line_insts().size() > 1; - Instruction last_inst = inst->dbg_line_insts().back(); - inst->dbg_line_insts().clear(); - // If last line is OpNoLine - if (last_inst.opcode() == SpvOpNoLine) { - // If no propagated line info, throw away redundant OpNoLine - if (*file_id == 0) { - modified = true; - // Else replace OpNoLine and propagate no line info - } else { - inst->dbg_line_insts().push_back(last_inst); - *file_id = 0; - } - } else { - // Else last line is OpLine - assert(last_inst.opcode() == SpvOpLine && "unexpected debug inst"); - // If propagated info matches last line, throw away last line - if (*file_id == last_inst.GetSingleWordInOperand(kSpvLineFileInIdx) && - *line == last_inst.GetSingleWordInOperand(kSpvLineLineInIdx) && - *col == last_inst.GetSingleWordInOperand(kSpvLineColInIdx)) { - modified = true; - } else { - // Else replace last line and propagate line info - *file_id = last_inst.GetSingleWordInOperand(kSpvLineFileInIdx); - *line = last_inst.GetSingleWordInOperand(kSpvLineLineInIdx); - *col = last_inst.GetSingleWordInOperand(kSpvLineColInIdx); - inst->dbg_line_insts().push_back(last_inst); - } - } - return modified; -} - -ProcessLinesPass::ProcessLinesPass(uint32_t func_id) { - if (func_id == kLinesPropagateLines) { - line_process_func_ = [this](Instruction* inst, uint32_t* file_id, - uint32_t* line, uint32_t* col) { - return PropagateLine(inst, file_id, line, col); - }; - } else { - assert(func_id == kLinesEliminateDeadLines && "unknown Lines param"); - line_process_func_ = [this](Instruction* inst, uint32_t* file_id, - uint32_t* line, uint32_t* col) { - return EliminateDeadLines(inst, file_id, line, col); - }; - } -} - -} // namespace opt -} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/process_lines_pass.h b/3rdparty/spirv-tools/source/opt/process_lines_pass.h deleted file mode 100644 index c988bfd0d..000000000 --- a/3rdparty/spirv-tools/source/opt/process_lines_pass.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2018 The Khronos Group Inc. -// Copyright (c) 2018 Valve Corporation -// Copyright (c) 2018 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_PROPAGATE_LINES_PASS_H_ -#define SOURCE_OPT_PROPAGATE_LINES_PASS_H_ - -#include "source/opt/function.h" -#include "source/opt/ir_context.h" -#include "source/opt/pass.h" - -namespace spvtools { -namespace opt { - -namespace { - -// Constructor Parameters -static const int kLinesPropagateLines = 0; -static const int kLinesEliminateDeadLines = 1; - -} // anonymous namespace - -// See optimizer.hpp for documentation. -class ProcessLinesPass : public Pass { - using LineProcessFunction = - std::function; - - public: - ProcessLinesPass(uint32_t func_id); - ~ProcessLinesPass() override = default; - - const char* name() const override { return "propagate-lines"; } - - // See optimizer.hpp for this pass' user documentation. - Status Process() override; - - IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse | - IRContext::kAnalysisInstrToBlockMapping | - IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | - IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | - IRContext::kAnalysisTypes; - } - - private: - // If |inst| has no debug line instruction, create one with - // |file_id, line, col|. If |inst| has debug line instructions, set - // |file_id, line, col| from the last. |file_id| equals 0 indicates no line - // info is available. Return true if |inst| modified. - bool PropagateLine(Instruction* inst, uint32_t* file_id, uint32_t* line, - uint32_t* col); - - // If last debug line instruction of |inst| matches |file_id, line, col|, - // delete all debug line instructions of |inst|. If they do not match, - // replace all debug line instructions of |inst| with new line instruction - // set from |file_id, line, col|. If |inst| has no debug line instructions, - // do not modify |inst|. |file_id| equals 0 indicates no line info is - // available. Return true if |inst| modified. - bool EliminateDeadLines(Instruction* inst, uint32_t* file_id, uint32_t* line, - uint32_t* col); - - // Apply lpfn() to all type, constant, global variable and function - // instructions in their physical order. - bool ProcessLines(); - - // A function that calls either PropagateLine or EliminateDeadLines. - // Initialized by the class constructor. - LineProcessFunction line_process_func_; -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_PROPAGATE_LINES_PASS_H_ diff --git a/3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.cpp b/3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.cpp index 76f1781aa..5a5688706 100644 --- a/3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.cpp @@ -66,6 +66,7 @@ namespace opt { namespace { const uint32_t kStoreValIdInIdx = 1; const uint32_t kVariableInitIdInIdx = 1; +const uint32_t kDebugDeclareOperandVariableIdx = 5; } // namespace std::string SSARewriter::PhiCandidate::PrettyPrint(const CFG* cfg) const { @@ -241,8 +242,8 @@ uint32_t SSARewriter::AddPhiOperands(PhiCandidate* phi_candidate) { return repl_id; } -uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) { - // If |var_id| has a definition in |bb|, return it. +uint32_t SSARewriter::GetValueAtBlock(uint32_t var_id, BasicBlock* bb) { + assert(bb != nullptr); const auto& bb_it = defs_at_block_.find(bb); if (bb_it != defs_at_block_.end()) { const auto& current_defs = bb_it->second; @@ -251,9 +252,15 @@ uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) { return var_it->second; } } + return 0; +} + +uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) { + // If |var_id| has a definition in |bb|, return it. + uint32_t val_id = GetValueAtBlock(var_id, bb); + if (val_id != 0) return val_id; // Otherwise, look up the value for |var_id| in |bb|'s predecessors. - uint32_t val_id = 0; auto& predecessors = pass_->cfg()->preds(bb->id()); if (predecessors.size() == 1) { // If |bb| has exactly one predecessor, we look for |var_id|'s definition @@ -308,7 +315,7 @@ void SSARewriter::ProcessStore(Instruction* inst, BasicBlock* bb) { if (pass_->IsTargetVar(var_id)) { WriteVariable(var_id, bb, val_id); pass_->context()->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible( - inst, var_id, val_id, inst); + inst, var_id, val_id, inst, &decls_invisible_to_value_assignment_); #if SSA_REWRITE_DEBUGGING_LEVEL > 1 std::cerr << "\tFound store '%" << var_id << " = %" << val_id << "': " @@ -439,8 +446,6 @@ bool SSARewriter::ApplyReplacements() { // Add Phi instructions from completed Phi candidates. std::vector generated_phis; - // Add DebugValue instructions for Phi instructions. - std::vector dbg_values_for_phis; for (const PhiCandidate* phi_candidate : phis_to_generate_) { #if SSA_REWRITE_DEBUGGING_LEVEL > 2 std::cerr << "Phi candidate: " << phi_candidate->PrettyPrint(pass_->cfg()) @@ -493,7 +498,7 @@ bool SSARewriter::ApplyReplacements() { insert_it->SetDebugScope(local_var->GetDebugScope()); pass_->context()->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible( &*insert_it, phi_candidate->var_id(), phi_candidate->result_id(), - &*insert_it); + &*insert_it, &decls_invisible_to_value_assignment_); modified = true; } @@ -581,6 +586,61 @@ void SSARewriter::FinalizePhiCandidates() { } } +Pass::Status SSARewriter::AddDebugValuesForInvisibleDebugDecls(Function* fp) { + // For the cases the value assignment is invisible to DebugDeclare e.g., + // the argument passing for an inlined function. + // + // Before inlining foo(int x): + // a = 3; + // foo(3); + // After inlining: + // a = 3; // we want to specify "DebugValue: %x = %int_3" + // foo and x disappeared! + // + // We want to specify the value for the variable using |defs_at_block_[bb]|, + // where |bb| is the basic block contains the decl. + DominatorAnalysis* dom_tree = pass_->context()->GetDominatorAnalysis(fp); + Pass::Status status = Pass::Status::SuccessWithoutChange; + for (auto* decl : decls_invisible_to_value_assignment_) { + uint32_t var_id = + decl->GetSingleWordOperand(kDebugDeclareOperandVariableIdx); + auto* var = pass_->get_def_use_mgr()->GetDef(var_id); + if (var->opcode() == SpvOpFunctionParameter) continue; + + auto* bb = pass_->context()->get_instr_block(decl); + uint32_t value_id = GetValueAtBlock(var_id, bb); + Instruction* value = nullptr; + if (value_id) value = pass_->get_def_use_mgr()->GetDef(value_id); + + // If |value| is defined before the function body, it dominates |decl|. + // If |value| dominates |decl|, we can set it as DebugValue. + if (value && (pass_->context()->get_instr_block(value) == nullptr || + dom_tree->Dominates(value, decl))) { + if (!pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl( + decl, value->result_id())) { + return Pass::Status::Failure; + } + } else { + // If |value| in the same basic block does not dominate |decl|, we can + // assign the value in the immediate dominator. + value_id = GetValueAtBlock(var_id, dom_tree->ImmediateDominator(bb)); + if (value_id && + !pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl( + decl, value_id)) { + return Pass::Status::Failure; + } + } + + // DebugDeclares of target variables will be removed by + // SSARewritePass::Process(). + if (!pass_->IsTargetVar(var_id)) { + pass_->context()->get_debug_info_mgr()->KillDebugDeclares(var_id); + } + status = Pass::Status::SuccessWithChange; + } + return status; +} + Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) { #if SSA_REWRITE_DEBUGGING_LEVEL > 0 std::cerr << "Function before SSA rewrite:\n" @@ -610,6 +670,12 @@ Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) { // Finally, apply all the replacements in the IR. bool modified = ApplyReplacements(); + auto status = AddDebugValuesForInvisibleDebugDecls(fp); + if (status == Pass::Status::SuccessWithChange || + status == Pass::Status::Failure) { + return status; + } + #if SSA_REWRITE_DEBUGGING_LEVEL > 0 std::cerr << "\n\n\nFunction after SSA rewrite:\n" << fp->PrettyPrint(0) << "\n"; diff --git a/3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.h b/3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.h index bbbfebbf1..1f4cd24ca 100644 --- a/3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.h +++ b/3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.h @@ -192,6 +192,10 @@ class SSARewriter { } } + // Returns the value of |var_id| at |bb| if |defs_at_block_| contains it. + // Otherwise, returns 0. + uint32_t GetValueAtBlock(uint32_t var_id, BasicBlock* bb); + // Processes the store operation |inst| in basic block |bb|. This extracts // the variable ID being stored into, determines whether the variable is an // SSA-target variable, and, if it is, it stores its value in the @@ -249,6 +253,11 @@ class SSARewriter { // candidates. void FinalizePhiCandidates(); + // Adds DebugValues for DebugDeclares in + // |decls_invisible_to_value_assignment_|. Returns whether the function was + // modified or not, and whether or not the conversion was successful. + Pass::Status AddDebugValuesForInvisibleDebugDecls(Function* fp); + // Prints the table of Phi candidates to std::cerr. void PrintPhiCandidates() const; @@ -286,6 +295,10 @@ class SSARewriter { // Memory pass requesting the SSA rewriter. MemPass* pass_; + + // Set of DebugDeclare instructions that are not added as DebugValue because + // they are invisible to the store or phi instructions. + std::unordered_set decls_invisible_to_value_assignment_; }; class SSARewritePass : public MemPass { diff --git a/3rdparty/spirv-tools/source/reduce/CMakeLists.txt b/3rdparty/spirv-tools/source/reduce/CMakeLists.txt index e113ca255..a3291c77b 100644 --- a/3rdparty/spirv-tools/source/reduce/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/reduce/CMakeLists.txt @@ -78,7 +78,7 @@ endif() spvtools_pch(SPIRV_TOOLS_REDUCE_SOURCES pch_source_reduce) -add_library(SPIRV-Tools-reduce STATIC ${SPIRV_TOOLS_REDUCE_SOURCES}) +add_library(SPIRV-Tools-reduce ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_TOOLS_REDUCE_SOURCES}) spvtools_default_compile_options(SPIRV-Tools-reduce) target_include_directories(SPIRV-Tools-reduce @@ -90,7 +90,7 @@ target_include_directories(SPIRV-Tools-reduce ) # The reducer reuses a lot of functionality from the SPIRV-Tools library. target_link_libraries(SPIRV-Tools-reduce - PUBLIC ${SPIRV_TOOLS}-static + PUBLIC ${SPIRV_TOOLS_FULL_VISIBILITY} PUBLIC SPIRV-Tools-opt) set_property(TARGET SPIRV-Tools-reduce PROPERTY FOLDER "SPIRV-Tools libraries") diff --git a/3rdparty/spirv-tools/source/val/validate_atomics.cpp b/3rdparty/spirv-tools/source/val/validate_atomics.cpp index df7973f87..3f1f56175 100644 --- a/3rdparty/spirv-tools/source/val/validate_atomics.cpp +++ b/3rdparty/spirv-tools/source/val/validate_atomics.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2017 Google Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights +// reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -151,7 +153,9 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { } if (spvIsVulkanEnv(_.context()->target_env) && - _.GetBitWidth(result_type) != 32) { + (_.GetBitWidth(result_type) != 32 && + (_.GetBitWidth(result_type) != 64 || + !_.HasCapability(SpvCapabilityInt64ImageEXT)))) { switch (opcode) { case SpvOpAtomicSMin: case SpvOpAtomicUMin: diff --git a/3rdparty/spirv-tools/source/val/validate_builtins.cpp b/3rdparty/spirv-tools/source/val/validate_builtins.cpp index 1d7017d11..1d85f8877 100644 --- a/3rdparty/spirv-tools/source/val/validate_builtins.cpp +++ b/3rdparty/spirv-tools/source/val/validate_builtins.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2018 Google LLC. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights +// reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +16,6 @@ // Validates correctness of built-in variables. -#include "source/val/validate.h" - #include #include #include @@ -31,6 +31,7 @@ #include "source/spirv_target_env.h" #include "source/util/bitutils.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { @@ -230,6 +231,12 @@ class BuiltInsValidator { spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration, const Instruction& inst); + spv_result_t ValidatePrimitiveShadingRateAtDefinition( + const Decoration& decoration, const Instruction& inst); + + spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration, + const Instruction& inst); + // The following section contains functions which are called when id defined // by |referenced_inst| is // 1. referenced by |referenced_from_inst| @@ -383,6 +390,16 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidatePrimitiveShadingRateAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateShadingRateAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + // Validates that |built_in_inst| is not (even indirectly) referenced from // within a function which can be called with |execution_model|. // @@ -2623,12 +2640,26 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( case SpvExecutionModelVertex: case SpvExecutionModelTessellationEvaluation: { if (!_.HasCapability(SpvCapabilityShaderViewportIndexLayerEXT)) { + if (operand == SpvBuiltInViewportIndex && + _.HasCapability(SpvCapabilityShaderViewportIndex)) + break; // Ok + if (operand == SpvBuiltInLayer && + _.HasCapability(SpvCapabilityShaderLayer)) + break; // Ok + + const char* capability = "ShaderViewportIndexLayerEXT"; + + if (operand == SpvBuiltInViewportIndex) + capability = "ShaderViewportIndexLayerEXT or ShaderViewportIndex"; + if (operand == SpvBuiltInLayer) + capability = "ShaderViewportIndexLayerEXT or ShaderLayer"; + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << "Using BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, operand) - << " in Vertex or Tessellation execution model requires " - "the ShaderViewportIndexLayerEXT capability."; + << " in Vertex or Tessellation execution model requires the " + << capability << " capability."; } break; } @@ -3314,6 +3345,142 @@ spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst, + &decoration](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4486) + << "According to the Vulkan spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidatePrimitiveShadingRateAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassOutput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4485) << "Vulkan spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Output storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + switch (execution_model) { + case SpvExecutionModelVertex: + case SpvExecutionModelGeometry: + case SpvExecutionModelMeshNV: + break; + default: { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4484) << "Vulkan spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be used only with Vertex, Geometry, or MeshNV " + "execution models. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back( + std::bind(&BuiltInsValidator::ValidatePrimitiveShadingRateAtReference, + this, decoration, built_in_inst, referenced_from_inst, + std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateShadingRateAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst, + &decoration](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4492) + << "According to the Vulkan spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidateShadingRateAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateShadingRateAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4491) << "Vulkan spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + if (execution_model != SpvExecutionModelFragment) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4490) << "Vulkan spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be used only with the Fragment execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateShadingRateAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( const Decoration& decoration, const Instruction& inst) { const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]); @@ -3514,6 +3681,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInRayGeometryIndexKHR: { // No validation rules (for the moment). break; + + case SpvBuiltInPrimitiveShadingRateKHR: + return ValidatePrimitiveShadingRateAtDefinition(decoration, inst); + case SpvBuiltInShadingRateKHR: + return ValidateShadingRateAtDefinition(decoration, inst); } } return SPV_SUCCESS; diff --git a/3rdparty/spirv-tools/source/val/validate_cfg.cpp b/3rdparty/spirv-tools/source/val/validate_cfg.cpp index 8eb3a968f..8babd355d 100644 --- a/3rdparty/spirv-tools/source/val/validate_cfg.cpp +++ b/3rdparty/spirv-tools/source/val/validate_cfg.cpp @@ -89,6 +89,8 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { << block->predecessors()->size() << ")."; } + std::unordered_set observed_predecessors; + for (size_t i = 3; i < inst->words().size(); ++i) { auto inc_id = inst->word(i); if (i % 2 == 1) { @@ -115,6 +117,17 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { << " is not a predecessor of " << _.getIdName(block->id()) << "."; } + + // We must not have already seen this predecessor as one of the phi's + // operands. + if (observed_predecessors.count(inc_id) != 0) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpPhi references incoming basic block " + << _.getIdName(inc_id) << " multiple times."; + } + + // Note the fact that we have now observed this predecessor. + observed_predecessors.insert(inc_id); } } diff --git a/3rdparty/spirv-tools/source/val/validate_image.cpp b/3rdparty/spirv-tools/source/val/validate_image.cpp index 8a2bdf137..299a3efca 100644 --- a/3rdparty/spirv-tools/source/val/validate_image.cpp +++ b/3rdparty/spirv-tools/source/val/validate_image.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2017 Google Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights +// reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -737,7 +739,9 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { if (spvIsVulkanEnv(_.context()->target_env)) { if ((!_.IsFloatScalarType(info.sampled_type) && !_.IsIntScalarType(info.sampled_type)) || - 32 != _.GetBitWidth(info.sampled_type)) { + (32 != _.GetBitWidth(info.sampled_type) && + (64 != _.GetBitWidth(info.sampled_type) || + !_.HasCapability(SpvCapabilityInt64ImageEXT)))) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Sampled Type to be a 32-bit int or float " "scalar type for Vulkan environment";