diff --git a/3rdparty/spirv-tools/Android.mk b/3rdparty/spirv-tools/Android.mk index 179cf2614..67d4fc3f3 100644 --- a/3rdparty/spirv-tools/Android.mk +++ b/3rdparty/spirv-tools/Android.mk @@ -76,6 +76,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/aggressive_dead_code_elim_pass.cpp \ source/opt/basic_block.cpp \ source/opt/block_merge_pass.cpp \ + source/opt/block_merge_util.cpp \ source/opt/build_module.cpp \ source/opt/cfg.cpp \ source/opt/cfg_cleanup_pass.cpp \ diff --git a/3rdparty/spirv-tools/README.md b/3rdparty/spirv-tools/README.md index 534664f77..c8e1cb6e9 100644 --- a/3rdparty/spirv-tools/README.md +++ b/3rdparty/spirv-tools/README.md @@ -128,6 +128,23 @@ See the [CHANGES](CHANGES) file for reports on completed work, and the [General sub-project](https://github.com/KhronosGroup/SPIRV-Tools/projects/2) for planned and in-progress work. + +### Reducer + +*Note:* The reducer is still under development. + +The reducer simplifies and shrinks a SPIR-V module with respect to a +user-supplied *interestingness function*. For example, given a large +SPIR-V module that cause some SPIR-V compiler to fail with a given +fatal error message, the reducer could be used to look for a smaller +version of the module that causes the compiler to fail with the same +fatal error message. + +To suggest an additional capability for the reducer, [file an +issue](https://github.com/KhronosGroup/SPIRV-Tools/issues]) with +"Reducer:" as the start of its title. + + ### Extras * [Utility filters](#utility-filters) diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index b0c547197..1fde97052 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2019.2-dev", "SPIRV-Tools v2019.2-dev 7d149d91055744e5a9bc6368de7b3bb605d0e1a9" +"v2019.2-dev", "SPIRV-Tools v2019.2-dev eae8dd2d23578d8b3cbb404d2caa01b27d69da15" diff --git a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc index fdb05b10c..58362f5bd 100644 --- a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc @@ -1,5 +1,6 @@ static const SpvCapability pygen_variable_caps_Addresses[] = {SpvCapabilityAddresses}; -static const SpvCapability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBuffer[] = {SpvCapabilityAddresses, SpvCapabilityVariablePointers, SpvCapabilityVariablePointersStorageBuffer}; +static const SpvCapability pygen_variable_caps_AddressesPhysicalStorageBufferAddressesEXT[] = {SpvCapabilityAddresses, SpvCapabilityPhysicalStorageBufferAddressesEXT}; +static const SpvCapability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBufferPhysicalStorageBufferAddressesEXT[] = {SpvCapabilityAddresses, SpvCapabilityVariablePointers, SpvCapabilityVariablePointersStorageBuffer, SpvCapabilityPhysicalStorageBufferAddressesEXT}; static const SpvCapability pygen_variable_caps_DerivativeControl[] = {SpvCapabilityDerivativeControl}; static const SpvCapability pygen_variable_caps_DeviceEnqueue[] = {SpvCapabilityDeviceEnqueue}; static const SpvCapability pygen_variable_caps_FragmentMaskAMD[] = {SpvCapabilityFragmentMaskAMD}; @@ -82,7 +83,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"TypeReserveId", SpvOpTypeReserveId, 1, pygen_variable_caps_Pipes, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"TypeQueue", SpvOpTypeQueue, 1, pygen_variable_caps_DeviceEnqueue, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"TypePipe", SpvOpTypePipe, 1, pygen_variable_caps_Pipes, 2, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ACCESS_QUALIFIER}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, - {"TypeForwardPointer", SpvOpTypeForwardPointer, 1, pygen_variable_caps_Addresses, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_STORAGE_CLASS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, + {"TypeForwardPointer", SpvOpTypeForwardPointer, 2, pygen_variable_caps_AddressesPhysicalStorageBufferAddressesEXT, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_STORAGE_CLASS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"ConstantTrue", SpvOpConstantTrue, 0, nullptr, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"ConstantFalse", SpvOpConstantFalse, 0, nullptr, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"Constant", SpvOpConstant, 0, nullptr, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, @@ -106,7 +107,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"CopyMemorySized", SpvOpCopyMemorySized, 1, pygen_variable_caps_Addresses, 4, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"AccessChain", SpvOpAccessChain, 0, nullptr, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"InBoundsAccessChain", SpvOpInBoundsAccessChain, 0, nullptr, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, - {"PtrAccessChain", SpvOpPtrAccessChain, 3, pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBuffer, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, + {"PtrAccessChain", SpvOpPtrAccessChain, 4, pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBufferPhysicalStorageBufferAddressesEXT, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"ArrayLength", SpvOpArrayLength, 1, pygen_variable_caps_Shader, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"GenericPtrMemSemantics", SpvOpGenericPtrMemSemantics, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"InBoundsPtrAccessChain", SpvOpInBoundsPtrAccessChain, 1, pygen_variable_caps_Addresses, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, @@ -153,10 +154,10 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"SConvert", SpvOpSConvert, 0, nullptr, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"FConvert", SpvOpFConvert, 0, nullptr, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"QuantizeToF16", SpvOpQuantizeToF16, 0, nullptr, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, - {"ConvertPtrToU", SpvOpConvertPtrToU, 1, pygen_variable_caps_Addresses, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, + {"ConvertPtrToU", SpvOpConvertPtrToU, 2, pygen_variable_caps_AddressesPhysicalStorageBufferAddressesEXT, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"SatConvertSToU", SpvOpSatConvertSToU, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"SatConvertUToS", SpvOpSatConvertUToS, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, - {"ConvertUToPtr", SpvOpConvertUToPtr, 1, pygen_variable_caps_Addresses, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, + {"ConvertUToPtr", SpvOpConvertUToPtr, 2, pygen_variable_caps_AddressesPhysicalStorageBufferAddressesEXT, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"PtrCastToGeneric", SpvOpPtrCastToGeneric, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"GenericCastToPtr", SpvOpGenericCastToPtr, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, {"GenericCastToPtrExplicit", SpvOpGenericCastToPtrExplicit, 1, pygen_variable_caps_Kernel, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_STORAGE_CLASS}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)}, diff --git a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc index fce3b6c2c..c95524055 100644 --- a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc +++ b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc @@ -26,6 +26,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_EXT_fragment_fully_covered"; case Extension::kSPV_EXT_fragment_invocation_density: return "SPV_EXT_fragment_invocation_density"; + case Extension::kSPV_EXT_physical_storage_buffer: + return "SPV_EXT_physical_storage_buffer"; case Extension::kSPV_EXT_shader_stencil_export: return "SPV_EXT_shader_stencil_export"; case Extension::kSPV_EXT_shader_viewport_index_layer: @@ -97,8 +99,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_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_INTEL_subgroups", "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_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_vote", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "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_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_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, 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_INTEL_subgroups, 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_post_depth_coverage, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_vote, 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_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_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_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_INTEL_subgroups", "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_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_vote", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "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_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_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_physical_storage_buffer, 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_INTEL_subgroups, 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_post_depth_coverage, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_vote, 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_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_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( @@ -364,6 +366,8 @@ const char* CapabilityToString(SpvCapability capability) { return "ComputeDerivativeGroupLinearNV"; case SpvCapabilityFragmentDensityEXT: return "FragmentDensityEXT"; + case SpvCapabilityPhysicalStorageBufferAddressesEXT: + return "PhysicalStorageBufferAddressesEXT"; case SpvCapabilityMax: assert(0 && "Attempting to convert SpvCapabilityMax to string"); return ""; diff --git a/3rdparty/spirv-tools/include/generated/extension_enum.inc b/3rdparty/spirv-tools/include/generated/extension_enum.inc index 83a2daa80..640009f2b 100644 --- a/3rdparty/spirv-tools/include/generated/extension_enum.inc +++ b/3rdparty/spirv-tools/include/generated/extension_enum.inc @@ -11,6 +11,7 @@ kSPV_AMD_texture_gather_bias_lod, kSPV_EXT_descriptor_indexing, kSPV_EXT_fragment_fully_covered, kSPV_EXT_fragment_invocation_density, +kSPV_EXT_physical_storage_buffer, kSPV_EXT_shader_stencil_export, kSPV_EXT_shader_viewport_index_layer, kSPV_GOOGLE_decorate_string, diff --git a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc index cc1d26f9a..f73be1fdb 100644 --- a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc @@ -42,6 +42,7 @@ static const SpvCapability pygen_variable_caps_MinLod[] = {SpvCapabilityMinLod}; static const SpvCapability pygen_variable_caps_MultiView[] = {SpvCapabilityMultiView}; static const SpvCapability pygen_variable_caps_MultiViewport[] = {SpvCapabilityMultiViewport}; static const SpvCapability pygen_variable_caps_PerViewAttributesNVMeshShadingNV[] = {SpvCapabilityPerViewAttributesNV, SpvCapabilityMeshShadingNV}; +static const SpvCapability pygen_variable_caps_PhysicalStorageBufferAddressesEXT[] = {SpvCapabilityPhysicalStorageBufferAddressesEXT}; static const SpvCapability pygen_variable_caps_Pipes[] = {SpvCapabilityPipes}; static const SpvCapability pygen_variable_caps_RayTracingNV[] = {SpvCapabilityRayTracingNV}; static const SpvCapability pygen_variable_caps_RoundingModeRTE[] = {SpvCapabilityRoundingModeRTE}; @@ -87,6 +88,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_AMD_texture_gather_bias static const spvtools::Extension pygen_variable_exts_SPV_EXT_descriptor_indexing[] = {spvtools::Extension::kSPV_EXT_descriptor_indexing}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_fully_covered[] = {spvtools::Extension::kSPV_EXT_fragment_fully_covered}; static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate[] = {spvtools::Extension::kSPV_EXT_fragment_invocation_density, spvtools::Extension::kSPV_NV_shading_rate}; +static const spvtools::Extension pygen_variable_exts_SPV_EXT_physical_storage_buffer[] = {spvtools::Extension::kSPV_EXT_physical_storage_buffer}; 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_layer[] = {spvtools::Extension::kSPV_EXT_shader_viewport_index_layer}; static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1}; @@ -231,7 +233,8 @@ static const spv_operand_desc_t pygen_variable_ExecutionModelEntries[] = { static const spv_operand_desc_t pygen_variable_AddressingModelEntries[] = { {"Logical", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)}, {"Physical32", 1, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)}, - {"Physical64", 2, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)} + {"Physical64", 2, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)}, + {"PhysicalStorageBuffer64EXT", 5348, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1, 0)} }; static const spv_operand_desc_t pygen_variable_MemoryModelEntries[] = { @@ -313,7 +316,8 @@ static const spv_operand_desc_t pygen_variable_StorageClassEntries[] = { {"RayPayloadNV", 5338, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)}, {"HitAttributeNV", 5339, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)}, {"IncomingRayPayloadNV", 5342, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)}, - {"ShaderRecordBufferNV", 5343, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)} + {"ShaderRecordBufferNV", 5343, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)}, + {"PhysicalStorageBufferEXT", 5349, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1, 0)} }; static const spv_operand_desc_t pygen_variable_DimEntries[] = { @@ -513,6 +517,8 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = { {"PerTaskNV", 5273, 1, pygen_variable_caps_MeshShadingNV, 1, pygen_variable_exts_SPV_NV_mesh_shader, {}, 0xffffffffu}, {"PerVertexNV", 5285, 1, pygen_variable_caps_FragmentBarycentricNV, 1, pygen_variable_exts_SPV_NV_fragment_shader_barycentric, {}, 0xffffffffu}, {"NonUniformEXT", 5300, 1, pygen_variable_caps_ShaderNonUniformEXT, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)}, + {"RestrictPointerEXT", 5355, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu}, + {"AliasedPointerEXT", 5356, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu}, {"HlslCounterBufferGOOGLE", 5634, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_ID}, 0xffffffffu}, {"HlslSemanticGOOGLE", 5635, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_LITERAL_STRING}, 0xffffffffu} }; @@ -769,6 +775,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"RayTracingNV", 5340, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu}, {"VulkanMemoryModelKHR", 5345, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, 0xffffffffu}, {"VulkanMemoryModelDeviceScopeKHR", 5346, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, 0xffffffffu}, + {"PhysicalStorageBufferAddressesEXT", 5347, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu}, {"ComputeDerivativeGroupLinearNV", 5350, 0, nullptr, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu}, {"SubgroupShuffleINTEL", 5568, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu}, {"SubgroupBufferBlockIOINTEL", 5569, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu}, diff --git a/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp b/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp index 9cb5afe3f..ee4efe852 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp @@ -235,6 +235,9 @@ class SpirvTools { bool Validate(const uint32_t* binary, size_t binary_size, spv_validator_options options) const; + // Was this object successfully constructed. + bool IsValid() const; + private: struct Impl; // Opaque struct for holding the data fields used by this class. std::unique_ptr impl_; // Unique pointer to implementation data. diff --git a/3rdparty/spirv-tools/source/libspirv.cpp b/3rdparty/spirv-tools/source/libspirv.cpp index b5fe89766..a1ed11d3f 100644 --- a/3rdparty/spirv-tools/source/libspirv.cpp +++ b/3rdparty/spirv-tools/source/libspirv.cpp @@ -128,4 +128,6 @@ bool SpirvTools::Validate(const uint32_t* binary, const size_t binary_size, return valid; } +bool SpirvTools::IsValid() const { return impl_->context != nullptr; } + } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/CMakeLists.txt b/3rdparty/spirv-tools/source/opt/CMakeLists.txt index 0f3835cbb..444379855 100644 --- a/3rdparty/spirv-tools/source/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/opt/CMakeLists.txt @@ -15,6 +15,7 @@ set(SPIRV_TOOLS_OPT_SOURCES aggressive_dead_code_elim_pass.h basic_block.h block_merge_pass.h + block_merge_util.h build_module.h ccp_pass.h cfg_cleanup_pass.h @@ -108,6 +109,7 @@ set(SPIRV_TOOLS_OPT_SOURCES aggressive_dead_code_elim_pass.cpp basic_block.cpp block_merge_pass.cpp + block_merge_util.cpp build_module.cpp ccp_pass.cpp cfg_cleanup_pass.cpp diff --git a/3rdparty/spirv-tools/source/opt/block_merge_pass.cpp b/3rdparty/spirv-tools/source/opt/block_merge_pass.cpp index 09deb217a..c7315baf2 100644 --- a/3rdparty/spirv-tools/source/opt/block_merge_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/block_merge_pass.cpp @@ -18,6 +18,7 @@ #include +#include "source/opt/block_merge_util.h" #include "source/opt/ir_context.h" #include "source/opt/iterator.h" @@ -27,112 +28,17 @@ namespace opt { bool BlockMergePass::MergeBlocks(Function* func) { bool modified = false; for (auto bi = func->begin(); bi != func->end();) { - // Find block with single successor which has no other predecessors. - auto ii = bi->end(); - --ii; - Instruction* br = &*ii; - if (br->opcode() != SpvOpBranch) { + if (blockmergeutil::CanMergeWithSuccessor(context(), &*bi)) { + blockmergeutil::MergeWithSuccessor(context(), func, bi); + // Reprocess block. + modified = true; + } else { ++bi; - continue; } - - const uint32_t lab_id = br->GetSingleWordInOperand(0); - if (cfg()->preds(lab_id).size() != 1) { - ++bi; - continue; - } - - bool pred_is_merge = IsMerge(&*bi); - bool succ_is_merge = IsMerge(lab_id); - if (pred_is_merge && succ_is_merge) { - // Cannot merge two merges together. - ++bi; - continue; - } - - Instruction* merge_inst = bi->GetMergeInst(); - bool pred_is_header = IsHeader(&*bi); - if (pred_is_header && lab_id != merge_inst->GetSingleWordInOperand(0u)) { - bool succ_is_header = IsHeader(lab_id); - if (pred_is_header && succ_is_header) { - // Cannot merge two headers together when the successor is not the merge - // block of the predecessor. - ++bi; - continue; - } - - // If this is a header block and the successor is not its merge, we must - // be careful about which blocks we are willing to merge together. - // OpLoopMerge must be followed by a conditional or unconditional branch. - // The merge must be a loop merge because a selection merge cannot be - // followed by an unconditional branch. - BasicBlock* succ_block = context()->get_instr_block(lab_id); - SpvOp succ_term_op = succ_block->terminator()->opcode(); - assert(merge_inst->opcode() == SpvOpLoopMerge); - if (succ_term_op != SpvOpBranch && - succ_term_op != SpvOpBranchConditional) { - ++bi; - continue; - } - } - - // Merge blocks. - context()->KillInst(br); - auto sbi = bi; - for (; sbi != func->end(); ++sbi) - if (sbi->id() == lab_id) break; - // If bi is sbi's only predecessor, it dominates sbi and thus - // sbi must follow bi in func's ordering. - assert(sbi != func->end()); - - // Update the inst-to-block mapping for the instructions in sbi. - for (auto& inst : *sbi) { - context()->set_instr_block(&inst, &*bi); - } - - // Now actually move the instructions. - bi->AddInstructions(&*sbi); - - if (merge_inst) { - if (pred_is_header && lab_id == merge_inst->GetSingleWordInOperand(0u)) { - // Merging the header and merge blocks, so remove the structured control - // flow declaration. - context()->KillInst(merge_inst); - } else { - // Move the merge instruction to just before the terminator. - merge_inst->InsertBefore(bi->terminator()); - } - } - context()->ReplaceAllUsesWith(lab_id, bi->id()); - context()->KillInst(sbi->GetLabelInst()); - (void)sbi.Erase(); - // Reprocess block. - modified = true; } return modified; } -bool BlockMergePass::IsHeader(BasicBlock* block) { - return block->GetMergeInst() != nullptr; -} - -bool BlockMergePass::IsHeader(uint32_t id) { - return IsHeader(context()->get_instr_block(get_def_use_mgr()->GetDef(id))); -} - -bool BlockMergePass::IsMerge(uint32_t id) { - return !get_def_use_mgr()->WhileEachUse(id, [](Instruction* user, - uint32_t index) { - SpvOp op = user->opcode(); - if ((op == SpvOpLoopMerge || op == SpvOpSelectionMerge) && index == 0u) { - return false; - } - return true; - }); -} - -bool BlockMergePass::IsMerge(BasicBlock* block) { return IsMerge(block->id()); } - Pass::Status BlockMergePass::Process() { // Process all entry point functions. ProcessFunction pfn = [this](Function* fp) { return MergeBlocks(fp); }; diff --git a/3rdparty/spirv-tools/source/opt/block_merge_pass.h b/3rdparty/spirv-tools/source/opt/block_merge_pass.h index 3ae7a5c00..aabf789fd 100644 --- a/3rdparty/spirv-tools/source/opt/block_merge_pass.h +++ b/3rdparty/spirv-tools/source/opt/block_merge_pass.h @@ -54,14 +54,6 @@ class BlockMergePass : public Pass { // with no other predecessors. Merge these blocks into a single block. bool MergeBlocks(Function* func); - // Returns true if |block| (or |id|) contains a merge instruction. - bool IsHeader(BasicBlock* block); - bool IsHeader(uint32_t id); - - // Returns true if |block| (or |id|) is the merge target of a merge - // instruction. - bool IsMerge(BasicBlock* block); - bool IsMerge(uint32_t id); }; } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/block_merge_util.cpp b/3rdparty/spirv-tools/source/opt/block_merge_util.cpp new file mode 100644 index 000000000..0a46ae6ed --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/block_merge_util.cpp @@ -0,0 +1,147 @@ +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG Inc. +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "block_merge_util.h" + +namespace spvtools { +namespace opt { +namespace blockmergeutil { + +namespace { + +// Returns true if |block| contains a merge instruction. +bool IsHeader(BasicBlock* block) { return block->GetMergeInst() != nullptr; } + +// Returns true if |id| contains a merge instruction. +bool IsHeader(IRContext* context, uint32_t id) { + return IsHeader( + context->get_instr_block(context->get_def_use_mgr()->GetDef(id))); +} + +// Returns true if |id| is the merge target of a merge instruction. +bool IsMerge(IRContext* context, uint32_t id) { + return !context->get_def_use_mgr()->WhileEachUse(id, [](Instruction* user, + uint32_t index) { + SpvOp op = user->opcode(); + if ((op == SpvOpLoopMerge || op == SpvOpSelectionMerge) && index == 0u) { + return false; + } + return true; + }); +} + +// Returns true if |block| is the merge target of a merge instruction. +bool IsMerge(IRContext* context, BasicBlock* block) { + return IsMerge(context, block->id()); +} + +} // Anonymous namespace + +bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) { + // Find block with single successor which has no other predecessors. + auto ii = block->end(); + --ii; + Instruction* br = &*ii; + if (br->opcode() != SpvOpBranch) { + return false; + } + + const uint32_t lab_id = br->GetSingleWordInOperand(0); + if (context->cfg()->preds(lab_id).size() != 1) { + return false; + } + + bool pred_is_merge = IsMerge(context, block); + bool succ_is_merge = IsMerge(context, lab_id); + if (pred_is_merge && succ_is_merge) { + // Cannot merge two merges together. + return false; + } + + Instruction* merge_inst = block->GetMergeInst(); + const bool pred_is_header = IsHeader(block); + if (pred_is_header && lab_id != merge_inst->GetSingleWordInOperand(0u)) { + bool succ_is_header = IsHeader(context, lab_id); + if (pred_is_header && succ_is_header) { + // Cannot merge two headers together when the successor is not the merge + // block of the predecessor. + return false; + } + + // If this is a header block and the successor is not its merge, we must + // be careful about which blocks we are willing to merge together. + // OpLoopMerge must be followed by a conditional or unconditional branch. + // The merge must be a loop merge because a selection merge cannot be + // followed by an unconditional branch. + BasicBlock* succ_block = context->get_instr_block(lab_id); + SpvOp succ_term_op = succ_block->terminator()->opcode(); + assert(merge_inst->opcode() == SpvOpLoopMerge); + if (succ_term_op != SpvOpBranch && succ_term_op != SpvOpBranchConditional) { + return false; + } + } + return true; +} + +void MergeWithSuccessor(IRContext* context, Function* func, + Function::iterator bi) { + assert(CanMergeWithSuccessor(context, &*bi) && + "Precondition failure for MergeWithSuccessor: it must be legal to " + "merge the block and its successor."); + + auto ii = bi->end(); + --ii; + Instruction* br = &*ii; + const uint32_t lab_id = br->GetSingleWordInOperand(0); + Instruction* merge_inst = bi->GetMergeInst(); + bool pred_is_header = IsHeader(&*bi); + + // Merge blocks. + context->KillInst(br); + auto sbi = bi; + for (; sbi != func->end(); ++sbi) + if (sbi->id() == lab_id) break; + // If bi is sbi's only predecessor, it dominates sbi and thus + // sbi must follow bi in func's ordering. + assert(sbi != func->end()); + + // Update the inst-to-block mapping for the instructions in sbi. + for (auto& inst : *sbi) { + context->set_instr_block(&inst, &*bi); + } + + // Now actually move the instructions. + bi->AddInstructions(&*sbi); + + if (merge_inst) { + if (pred_is_header && lab_id == merge_inst->GetSingleWordInOperand(0u)) { + // Merging the header and merge blocks, so remove the structured control + // flow declaration. + context->KillInst(merge_inst); + } else { + // Move the merge instruction to just before the terminator. + merge_inst->InsertBefore(bi->terminator()); + } + } + context->ReplaceAllUsesWith(lab_id, bi->id()); + context->KillInst(sbi->GetLabelInst()); + (void)sbi.Erase(); +} + +} // namespace blockmergeutil +} // namespace opt +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/block_merge_util.h b/3rdparty/spirv-tools/source/opt/block_merge_util.h new file mode 100644 index 000000000..e71e3d6ad --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/block_merge_util.h @@ -0,0 +1,44 @@ +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG Inc. +// Copyright (c) 2019 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_BLOCK_MERGE_UTIL_H_ +#define SOURCE_OPT_BLOCK_MERGE_UTIL_H_ + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +// Provides functions for determining when it is safe to merge blocks, and for +// actually merging blocks, for use by various analyses and passes. +namespace blockmergeutil { + +// Returns true if and only if |block| has exactly one successor and merging +// this successor into |block| has no impact on the semantics or validity of the +// SPIR-V module. +bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block); + +// Requires that |bi| has a successor that can be safely merged into |bi|, and +// performs the merge. +void MergeWithSuccessor(IRContext* context, Function* func, + Function::iterator bi); + +} // namespace blockmergeutil +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_BLOCK_MERGE_UTIL_H_ diff --git a/3rdparty/spirv-tools/source/opt/code_sink.cpp b/3rdparty/spirv-tools/source/opt/code_sink.cpp index e1e819017..9d54ee517 100644 --- a/3rdparty/spirv-tools/source/opt/code_sink.cpp +++ b/3rdparty/spirv-tools/source/opt/code_sink.cpp @@ -80,7 +80,10 @@ BasicBlock* CodeSinkingPass::FindNewBasicBlockFor(Instruction* inst) { get_def_use_mgr()->ForEachUse( inst, [&bbs_with_uses, this](Instruction* use, uint32_t idx) { if (use->opcode() != SpvOpPhi) { - bbs_with_uses.insert(context()->get_instr_block(use)->id()); + BasicBlock* use_bb = context()->get_instr_block(use); + if (use_bb) { + bbs_with_uses.insert(use_bb->id()); + } } else { bbs_with_uses.insert(use->GetSingleWordOperand(idx + 1)); } diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index a31349f45..61c5425d6 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -89,6 +89,11 @@ void IRContext::InvalidateAnalysesExceptFor( } void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { + // The ConstantManager contains Type pointers. If the TypeManager goes + // away, the ConstantManager has to go away. + if (analyses_to_invalidate & kAnalysisTypes) { + analyses_to_invalidate |= kAnalysisConstants; + } if (analyses_to_invalidate & kAnalysisDefUse) { def_use_mgr_.reset(nullptr); } @@ -127,9 +132,6 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { constant_mgr_.reset(nullptr); } if (analyses_to_invalidate & kAnalysisTypes) { - // The ConstantManager contains Type pointers. If the TypeManager goes - // away, the ConstantManager has to go away. - constant_mgr_.reset(nullptr); type_mgr_.reset(nullptr); } diff --git a/3rdparty/spirv-tools/source/reduce/CMakeLists.txt b/3rdparty/spirv-tools/source/reduce/CMakeLists.txt index 0a6bce99c..2f8c460df 100644 --- a/3rdparty/spirv-tools/source/reduce/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/reduce/CMakeLists.txt @@ -14,33 +14,34 @@ set(SPIRV_TOOLS_REDUCE_SOURCES change_operand_reduction_opportunity.h change_operand_to_undef_reduction_opportunity.h - operand_to_const_reduction_pass.h - operand_to_undef_reduction_pass.h - operand_to_dominating_id_reduction_pass.h + operand_to_const_reduction_opportunity_finder.h + operand_to_undef_reduction_opportunity_finder.h + operand_to_dominating_id_reduction_opportunity_finder.h reducer.h reduction_opportunity.h + reduction_opportunity_finder.h reduction_pass.h reduction_util.h remove_instruction_reduction_opportunity.h - remove_opname_instruction_reduction_pass.h - remove_unreferenced_instruction_reduction_pass.h + remove_opname_instruction_reduction_opportunity_finder.h + remove_unreferenced_instruction_reduction_opportunity_finder.h structured_loop_to_selection_reduction_opportunity.h - structured_loop_to_selection_reduction_pass.h + structured_loop_to_selection_reduction_opportunity_finder.h change_operand_reduction_opportunity.cpp change_operand_to_undef_reduction_opportunity.cpp - operand_to_const_reduction_pass.cpp - operand_to_undef_reduction_pass.cpp - operand_to_dominating_id_reduction_pass.cpp + operand_to_const_reduction_opportunity_finder.cpp + operand_to_undef_reduction_opportunity_finder.cpp + operand_to_dominating_id_reduction_opportunity_finder.cpp reducer.cpp reduction_opportunity.cpp reduction_pass.cpp reduction_util.cpp remove_instruction_reduction_opportunity.cpp - remove_unreferenced_instruction_reduction_pass.cpp - remove_opname_instruction_reduction_pass.cpp + remove_unreferenced_instruction_reduction_opportunity_finder.cpp + remove_opname_instruction_reduction_opportunity_finder.cpp structured_loop_to_selection_reduction_opportunity.cpp - structured_loop_to_selection_reduction_pass.cpp + structured_loop_to_selection_reduction_opportunity_finder.cpp ) if(MSVC) diff --git a/3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_pass.cpp b/3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.cpp similarity index 92% rename from 3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_pass.cpp rename to 3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.cpp index 4d04506e1..97e0b9d9a 100644 --- a/3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_pass.cpp +++ b/3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/reduce/operand_to_const_reduction_pass.h" +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" #include "source/opt/instruction.h" #include "source/reduce/change_operand_reduction_opportunity.h" @@ -23,7 +23,7 @@ namespace reduce { using namespace opt; std::vector> -OperandToConstReductionPass::GetAvailableOpportunities( +OperandToConstReductionOpportunityFinder::GetAvailableOpportunities( opt::IRContext* context) const { std::vector> result; assert(result.empty()); @@ -75,8 +75,8 @@ OperandToConstReductionPass::GetAvailableOpportunities( return result; } -std::string OperandToConstReductionPass::GetName() const { - return "OperandToConstReductionPass"; +std::string OperandToConstReductionOpportunityFinder::GetName() const { + return "OperandToConstReductionOpportunityFinder"; } } // namespace reduce diff --git a/3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_pass.h b/3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.h similarity index 61% rename from 3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_pass.h rename to 3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.h index 4e7381e93..93c0dcd3f 100644 --- a/3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_pass.h +++ b/3rdparty/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.h @@ -12,30 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_ -#define SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_ +#ifndef SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_ -#include "source/reduce/reduction_pass.h" +#include "source/reduce/reduction_opportunity_finder.h" namespace spvtools { namespace reduce { -// A reduction pass for replacing id operands of instructions with ids of +// A finder for opportunities to replace id operands of instructions with ids of // constants. This reduces the extent to which ids of non-constants are used, -// paving the way for instructions that generate them to be eliminated by other -// passes. -class OperandToConstReductionPass : public ReductionPass { +// paving the way for instructions that generate them to be eliminated. +class OperandToConstReductionOpportunityFinder + : public ReductionOpportunityFinder { public: - // Creates the reduction pass in the context of the given target environment - // |target_env| - explicit OperandToConstReductionPass(const spv_target_env target_env) - : ReductionPass(target_env) {} + OperandToConstReductionOpportunityFinder() = default; - ~OperandToConstReductionPass() override = default; + ~OperandToConstReductionOpportunityFinder() override = default; std::string GetName() const final; - protected: std::vector> GetAvailableOpportunities( opt::IRContext* context) const final; @@ -45,4 +41,4 @@ class OperandToConstReductionPass : public ReductionPass { } // namespace reduce } // namespace spvtools -#endif // SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_ +#endif // SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_pass.cpp b/3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.cpp similarity index 87% rename from 3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_pass.cpp rename to 3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.cpp index 9280a41dd..d31acdf2b 100644 --- a/3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_pass.cpp +++ b/3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "operand_to_dominating_id_reduction_pass.h" +#include "operand_to_dominating_id_reduction_opportunity_finder.h" #include "change_operand_reduction_opportunity.h" #include "source/opt/instruction.h" @@ -22,7 +22,7 @@ namespace reduce { using namespace opt; std::vector> -OperandToDominatingIdReductionPass::GetAvailableOpportunities( +OperandToDominatingIdReductionOpportunityFinder::GetAvailableOpportunities( opt::IRContext* context) const { std::vector> result; @@ -55,11 +55,12 @@ OperandToDominatingIdReductionPass::GetAvailableOpportunities( return result; } -void OperandToDominatingIdReductionPass::GetOpportunitiesForDominatingInst( - std::vector>* opportunities, - opt::Instruction* candidate_dominator, - opt::Function::iterator candidate_dominator_block, opt::Function* function, - opt::IRContext* context) const { +void OperandToDominatingIdReductionOpportunityFinder:: + GetOpportunitiesForDominatingInst( + std::vector>* opportunities, + opt::Instruction* candidate_dominator, + opt::Function::iterator candidate_dominator_block, + opt::Function* function, opt::IRContext* context) const { assert(candidate_dominator->HasResultId()); assert(candidate_dominator->type_id()); auto dominator_analysis = context->GetDominatorAnalysis(function); @@ -106,8 +107,8 @@ void OperandToDominatingIdReductionPass::GetOpportunitiesForDominatingInst( } } -std::string OperandToDominatingIdReductionPass::GetName() const { - return "OperandToDominatingIdReductionPass"; +std::string OperandToDominatingIdReductionOpportunityFinder::GetName() const { + return "OperandToDominatingIdReductionOpportunityFinder"; } } // namespace reduce diff --git a/3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_pass.h b/3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h similarity index 57% rename from 3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_pass.h rename to 3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h index 36bb20112..471c5835c 100644 --- a/3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_pass.h +++ b/3rdparty/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h @@ -12,36 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_PASS_H_ -#define SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_PASS_H_ +#ifndef SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_ -#include "reduction_pass.h" +#include "reduction_opportunity_finder.h" namespace spvtools { namespace reduce { -// A reduction pass that aims to bring to SPIR-V (and generalize) the idea from -// human-readable languages of e.g. replacing an expression with one of its -// arguments, (x + y) -> x, or with a reference to an identifier that was -// assigned to higher up in the program. The generalization of this is to -// replace an id with a different id of the same type defined in some -// dominating instruction. +// A finder that aims to bring to SPIR-V (and generalize) the idea from +// human-readable languages of e.g. finding opportunities to replace an +// expression with one of its arguments, (x + y) -> x, or with a reference to an +// identifier that was assigned to higher up in the program. The generalization +// of this is to replace an id with a different id of the same type defined in +// some dominating instruction. // // If id x is defined and then used several times, changing each use of x to // some dominating definition may eventually allow the statement defining x // to be eliminated by another pass. -class OperandToDominatingIdReductionPass : public ReductionPass { +class OperandToDominatingIdReductionOpportunityFinder + : public ReductionOpportunityFinder { public: - // Creates the reduction pass in the context of the given target environment - // |target_env| - explicit OperandToDominatingIdReductionPass(const spv_target_env target_env) - : ReductionPass(target_env) {} + OperandToDominatingIdReductionOpportunityFinder() = default; - ~OperandToDominatingIdReductionPass() override = default; + ~OperandToDominatingIdReductionOpportunityFinder() override = default; std::string GetName() const final; - protected: std::vector> GetAvailableOpportunities( opt::IRContext* context) const final; @@ -56,4 +53,4 @@ class OperandToDominatingIdReductionPass : public ReductionPass { } // namespace reduce } // namespace spvtools -#endif // SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_PASS_H_ +#endif // SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_pass.cpp b/3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.cpp similarity index 91% rename from 3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_pass.cpp rename to 3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.cpp index e3d8a8ea3..516b5292c 100644 --- a/3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_pass.cpp +++ b/3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/reduce/operand_to_undef_reduction_pass.h" +#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h" #include "source/opt/instruction.h" #include "source/reduce/change_operand_to_undef_reduction_opportunity.h" @@ -23,7 +23,7 @@ namespace reduce { using namespace opt; std::vector> -OperandToUndefReductionPass::GetAvailableOpportunities( +OperandToUndefReductionOpportunityFinder::GetAvailableOpportunities( IRContext* context) const { std::vector> result; @@ -86,8 +86,8 @@ OperandToUndefReductionPass::GetAvailableOpportunities( return result; } -std::string OperandToUndefReductionPass::GetName() const { - return "OperandToUndefReductionPass"; +std::string OperandToUndefReductionOpportunityFinder::GetName() const { + return "OperandToUndefReductionOpportunityFinder"; } } // namespace reduce diff --git a/3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_pass.h b/3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.h similarity index 58% rename from 3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_pass.h rename to 3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.h index e4ec603fb..9cdd8cd56 100644 --- a/3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_pass.h +++ b/3rdparty/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.h @@ -12,27 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_PASS_H_ -#define SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_PASS_H_ +#ifndef SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_ -#include "source/reduce/reduction_pass.h" +#include "source/reduce/reduction_opportunity_finder.h" namespace spvtools { namespace reduce { -// A reduction pass for replacing id operands of instructions with ids of undef. -class OperandToUndefReductionPass : public ReductionPass { +// A finder of opportunities to replace id operands of instructions with ids of +// undef. +class OperandToUndefReductionOpportunityFinder + : public ReductionOpportunityFinder { public: - // Creates the reduction pass in the context of the given target environment - // |target_env| - explicit OperandToUndefReductionPass(const spv_target_env target_env) - : ReductionPass(target_env) {} + OperandToUndefReductionOpportunityFinder() = default; - ~OperandToUndefReductionPass() override = default; + ~OperandToUndefReductionOpportunityFinder() override = default; std::string GetName() const final; - protected: std::vector> GetAvailableOpportunities( opt::IRContext* context) const final; @@ -42,4 +40,4 @@ class OperandToUndefReductionPass : public ReductionPass { } // namespace reduce } // namespace spvtools -#endif // SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_PASS_H_ +#endif // SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/3rdparty/spirv-tools/source/reduce/pch_source_reduce.h b/3rdparty/spirv-tools/source/reduce/pch_source_reduce.h index 823b55a8a..6c0da0c7b 100644 --- a/3rdparty/spirv-tools/source/reduce/pch_source_reduce.h +++ b/3rdparty/spirv-tools/source/reduce/pch_source_reduce.h @@ -16,8 +16,8 @@ #include #include #include "source/reduce/change_operand_reduction_opportunity.h" -#include "source/reduce/operand_to_const_reduction_pass.h" +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" #include "source/reduce/reduction_opportunity.h" #include "source/reduce/reduction_pass.h" #include "source/reduce/remove_instruction_reduction_opportunity.h" -#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h" +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" diff --git a/3rdparty/spirv-tools/source/reduce/reducer.cpp b/3rdparty/spirv-tools/source/reduce/reducer.cpp index 4f4429aab..aaef3fb43 100644 --- a/3rdparty/spirv-tools/source/reduce/reducer.cpp +++ b/3rdparty/spirv-tools/source/reduce/reducer.cpp @@ -141,8 +141,9 @@ Reducer::ReductionResultStatus Reducer::Run( } void Reducer::AddReductionPass( - std::unique_ptr&& reduction_pass) { - impl_->passes.push_back(std::move(reduction_pass)); + std::unique_ptr&& finder) { + impl_->passes.push_back(spvtools::MakeUnique( + impl_->target_env, std::move(finder))); } bool Reducer::Impl::ReachedStepLimit(uint32_t current_step, diff --git a/3rdparty/spirv-tools/source/reduce/reducer.h b/3rdparty/spirv-tools/source/reduce/reducer.h index 3a4c26c97..0b9bfa111 100644 --- a/3rdparty/spirv-tools/source/reduce/reducer.h +++ b/3rdparty/spirv-tools/source/reduce/reducer.h @@ -75,9 +75,9 @@ class Reducer { void SetInterestingnessFunction( InterestingnessFunction interestingness_function); - // Adds a reduction pass to the sequence of passes that will be iterated - // over. - void AddReductionPass(std::unique_ptr&& reduction_pass); + // Adds a reduction pass based on the given finder to the sequence of passes + // that will be iterated over. + void AddReductionPass(std::unique_ptr&& finder); // Reduces the given SPIR-V module |binary_out|. // The reduced binary ends up in |binary_out|. diff --git a/3rdparty/spirv-tools/source/reduce/reduction_opportunity_finder.h b/3rdparty/spirv-tools/source/reduce/reduction_opportunity_finder.h new file mode 100644 index 000000000..b9f55d5be --- /dev/null +++ b/3rdparty/spirv-tools/source/reduce/reduction_opportunity_finder.h @@ -0,0 +1,43 @@ +// Copyright (c) 2019 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_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "reduction_opportunity.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace reduce { + +// Abstract class for finding opportunities for reducing a SPIR-V module. +class ReductionOpportunityFinder { + public: + ReductionOpportunityFinder() = default; + + virtual ~ReductionOpportunityFinder() = default; + + // Finds and returns the reduction opportunities relevant to this pass that + // could be applied to the given SPIR-V module. + virtual std::vector> + GetAvailableOpportunities(opt::IRContext* context) const = 0; + + // Provides a name for the finder. + virtual std::string GetName() const = 0; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/3rdparty/spirv-tools/source/reduce/reduction_pass.cpp b/3rdparty/spirv-tools/source/reduce/reduction_pass.cpp index befba8bc6..66e11cb59 100644 --- a/3rdparty/spirv-tools/source/reduce/reduction_pass.cpp +++ b/3rdparty/spirv-tools/source/reduce/reduction_pass.cpp @@ -34,7 +34,7 @@ std::vector ReductionPass::TryApplyReduction( assert(context); std::vector> opportunities = - GetAvailableOpportunities(context.get()); + finder_->GetAvailableOpportunities(context.get()); if (!is_initialized_) { is_initialized_ = true; @@ -82,5 +82,7 @@ bool ReductionPass::ReachedMinimumGranularity() const { return granularity_ == 1; } +std::string ReductionPass::GetName() const { return finder_->GetName(); } + } // namespace reduce } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/reduce/reduction_pass.h b/3rdparty/spirv-tools/source/reduce/reduction_pass.h index 57e1c5f66..46cd19244 100644 --- a/3rdparty/spirv-tools/source/reduce/reduction_pass.h +++ b/3rdparty/spirv-tools/source/reduce/reduction_pass.h @@ -17,7 +17,7 @@ #include "spirv-tools/libspirv.hpp" -#include "reduction_opportunity.h" +#include "reduction_opportunity_finder.h" #include "source/opt/ir_context.h" namespace spvtools { @@ -32,12 +32,14 @@ namespace reduce { // again, until the minimum granularity is reached. class ReductionPass { public: - // Constructs a reduction pass with a given target environment, |target_env|. - // Initially the pass is uninitialized. - explicit ReductionPass(const spv_target_env target_env) - : target_env_(target_env), is_initialized_(false) {} - - virtual ~ReductionPass() = default; + // Constructs a reduction pass with a given target environment, |target_env|, + // and a given finder of reduction opportunities, |finder|. Initially the + // pass is uninitialized. + explicit ReductionPass(const spv_target_env target_env, + std::unique_ptr finder) + : target_env_(target_env), + finder_(std::move(finder)), + is_initialized_(false) {} // Applies the reduction pass to the given binary. std::vector TryApplyReduction(const std::vector& binary); @@ -49,18 +51,13 @@ class ReductionPass { // applied has reached a minimum. bool ReachedMinimumGranularity() const; - // Returns the name of the reduction pass (useful for monitoring reduction - // progress). - virtual std::string GetName() const = 0; - - protected: - // Finds and returns the reduction opportunities relevant to this pass that - // could be applied to the given SPIR-V module. - virtual std::vector> - GetAvailableOpportunities(opt::IRContext* context) const = 0; + // Returns the name associated with this reduction pass (based on its + // associated finder). + std::string GetName() const; private: const spv_target_env target_env_; + const std::unique_ptr finder_; MessageConsumer consumer_; bool is_initialized_; uint32_t index_; diff --git a/3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_pass.cpp b/3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_opportunity_finder.cpp similarity index 80% rename from 3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_pass.cpp rename to 3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_opportunity_finder.cpp index bf99bc57f..fa2d27f7c 100644 --- a/3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_pass.cpp +++ b/3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_opportunity_finder.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "remove_opname_instruction_reduction_pass.h" +#include "remove_opname_instruction_reduction_opportunity_finder.h" #include "remove_instruction_reduction_opportunity.h" #include "source/opcode.h" #include "source/opt/instruction.h" @@ -23,7 +23,7 @@ namespace reduce { using namespace opt; std::vector> -RemoveOpNameInstructionReductionPass::GetAvailableOpportunities( +RemoveOpNameInstructionReductionOpportunityFinder::GetAvailableOpportunities( opt::IRContext* context) const { std::vector> result; @@ -36,8 +36,8 @@ RemoveOpNameInstructionReductionPass::GetAvailableOpportunities( return result; } -std::string RemoveOpNameInstructionReductionPass::GetName() const { - return "RemoveOpNameInstructionReductionPass"; +std::string RemoveOpNameInstructionReductionOpportunityFinder::GetName() const { + return "RemoveOpNameInstructionReductionOpportunityFinder"; } } // namespace reduce diff --git a/3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_pass.h b/3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_opportunity_finder.h similarity index 56% rename from 3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_pass.h rename to 3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_opportunity_finder.h index 2990a49cc..4304226da 100644 --- a/3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_pass.h +++ b/3rdparty/spirv-tools/source/reduce/remove_opname_instruction_reduction_opportunity_finder.h @@ -12,30 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_PASS_H_ -#define SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_PASS_H_ +#ifndef SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ -#include "reduction_pass.h" +#include "reduction_opportunity_finder.h" namespace spvtools { namespace reduce { -// A reduction pass for removing OpName instructions. As well as making the -// module smaller, removing an OpName instruction may create opportunities +// A finder for opportunities to remove OpName instructions. As well as making +// the module smaller, removing an OpName instruction may create opportunities // for subsequently removing the instructions that create the ids to which the // OpName applies. -class RemoveOpNameInstructionReductionPass : public ReductionPass { +class RemoveOpNameInstructionReductionOpportunityFinder + : public ReductionOpportunityFinder { public: - // Creates the reduction pass in the context of the given target environment - // |target_env| - explicit RemoveOpNameInstructionReductionPass(const spv_target_env target_env) - : ReductionPass(target_env) {} + RemoveOpNameInstructionReductionOpportunityFinder() = default; - ~RemoveOpNameInstructionReductionPass() override = default; + ~RemoveOpNameInstructionReductionOpportunityFinder() override = default; std::string GetName() const final; - protected: std::vector> GetAvailableOpportunities( opt::IRContext* context) const final; @@ -45,4 +42,4 @@ class RemoveOpNameInstructionReductionPass : public ReductionPass { } // namespace reduce } // namespace spvtools -#endif // SOURCE_REDUCE_REMOVE_OpName_INSTRUCTION_REDUCTION_PASS_H_ +#endif // SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_pass.cpp b/3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp similarity index 83% rename from 3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_pass.cpp rename to 3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp index bc4998d6a..03880afa0 100644 --- a/3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_pass.cpp +++ b/3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "remove_unreferenced_instruction_reduction_pass.h" +#include "remove_unreferenced_instruction_reduction_opportunity_finder.h" #include "remove_instruction_reduction_opportunity.h" #include "source/opcode.h" #include "source/opt/instruction.h" @@ -23,8 +23,8 @@ namespace reduce { using namespace opt; std::vector> -RemoveUnreferencedInstructionReductionPass::GetAvailableOpportunities( - opt::IRContext* context) const { +RemoveUnreferencedInstructionReductionOpportunityFinder:: + GetAvailableOpportunities(opt::IRContext* context) const { std::vector> result; for (auto& function : *context->module()) { @@ -52,8 +52,9 @@ RemoveUnreferencedInstructionReductionPass::GetAvailableOpportunities( return result; } -std::string RemoveUnreferencedInstructionReductionPass::GetName() const { - return "RemoveUnreferencedInstructionReductionPass"; +std::string RemoveUnreferencedInstructionReductionOpportunityFinder::GetName() + const { + return "RemoveUnreferencedInstructionReductionOpportunityFinder"; } } // namespace reduce diff --git a/3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_pass.h b/3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h similarity index 67% rename from 3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_pass.h rename to 3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h index 44a0d55e9..1bb2afb55 100644 --- a/3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_pass.h +++ b/3rdparty/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h @@ -12,32 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_PASS_H_ -#define SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_PASS_H_ +#ifndef SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ -#include "reduction_pass.h" +#include "reduction_opportunity_finder.h" namespace spvtools { namespace reduce { -// A reduction pass for removing non-control-flow instructions in blocks in -// cases where the instruction's id is not referenced. As well as making the +// A finder for opportunities to remove non-control-flow instructions in blocks +// in cases where the instruction's id is not referenced. As well as making the // module smaller, removing an instruction that references particular ids may // create opportunities for subsequently removing the instructions that // generated those ids. -class RemoveUnreferencedInstructionReductionPass : public ReductionPass { +class RemoveUnreferencedInstructionReductionOpportunityFinder + : public ReductionOpportunityFinder { public: - // Creates the reduction pass in the context of the given target environment - // |target_env| - explicit RemoveUnreferencedInstructionReductionPass( - const spv_target_env target_env) - : ReductionPass(target_env) {} + RemoveUnreferencedInstructionReductionOpportunityFinder() = default; - ~RemoveUnreferencedInstructionReductionPass() override = default; + ~RemoveUnreferencedInstructionReductionOpportunityFinder() override = default; std::string GetName() const final; - protected: std::vector> GetAvailableOpportunities( opt::IRContext* context) const final; @@ -47,4 +43,4 @@ class RemoveUnreferencedInstructionReductionPass : public ReductionPass { } // namespace reduce } // namespace spvtools -#endif // SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_PASS_H_ +#endif // SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_pass.cpp b/3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp similarity index 91% rename from 3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_pass.cpp rename to 3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp index 768a2e8e1..7d150fbe8 100644 --- a/3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_pass.cpp +++ b/3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "structured_loop_to_selection_reduction_pass.h" +#include "structured_loop_to_selection_reduction_opportunity_finder.h" #include "structured_loop_to_selection_reduction_opportunity.h" namespace spvtools { @@ -26,7 +26,7 @@ const uint32_t kContinueNodeIndex = 1; } // namespace std::vector> -StructuredLoopToSelectionReductionPass::GetAvailableOpportunities( +StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities( opt::IRContext* context) const { std::vector> result; @@ -87,8 +87,9 @@ StructuredLoopToSelectionReductionPass::GetAvailableOpportunities( return result; } -std::string StructuredLoopToSelectionReductionPass::GetName() const { - return "StructuredLoopToSelectionReductionPass"; +std::string StructuredLoopToSelectionReductionOpportunityFinder::GetName() + const { + return "StructuredLoopToSelectionReductionOpportunityFinder"; } } // namespace reduce diff --git a/3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_pass.h b/3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h similarity index 52% rename from 3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_pass.h rename to 3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h index a1f88bc54..4c714ec93 100644 --- a/3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_pass.h +++ b/3rdparty/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SOURCE_REDUCE_CUT_LOOP_REDUCTION_PASS_H_ -#define SOURCE_REDUCE_CUT_LOOP_REDUCTION_PASS_H_ +#ifndef SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H +#define SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H -#include "reduction_pass.h" +#include "reduction_opportunity_finder.h" namespace spvtools { namespace reduce { -// Turns structured loops into selections, generalizing from a human-writable -// language the idea of turning a loop: +// A finder for opportunities to turn structured loops into selections, +// generalizing from a human-writable language the idea of turning a loop: // // while (c) { // body; @@ -33,22 +33,18 @@ namespace reduce { // body; // } // -// The pass results in continue constructs of transformed loops becoming -// unreachable; another pass for eliminating blocks may end up being able to -// remove them. -class StructuredLoopToSelectionReductionPass : public ReductionPass { +// Applying such opportunities results in continue constructs of transformed +// loops becoming unreachable, so that it may be possible to remove them +// subsequently. +class StructuredLoopToSelectionReductionOpportunityFinder + : public ReductionOpportunityFinder { public: - // Creates the reduction pass in the context of the given target environment - // |target_env| - explicit StructuredLoopToSelectionReductionPass( - const spv_target_env target_env) - : ReductionPass(target_env) {} + StructuredLoopToSelectionReductionOpportunityFinder() = default; - ~StructuredLoopToSelectionReductionPass() override = default; + ~StructuredLoopToSelectionReductionOpportunityFinder() override = default; std::string GetName() const final; - protected: std::vector> GetAvailableOpportunities( opt::IRContext* context) const final; @@ -58,4 +54,4 @@ class StructuredLoopToSelectionReductionPass : public ReductionPass { } // namespace reduce } // namespace spvtools -#endif // SOURCE_REDUCE_CUT_LOOP_REDUCTION_PASS_H_ +#endif // SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H diff --git a/3rdparty/spirv-tools/source/spirv_target_env.cpp b/3rdparty/spirv-tools/source/spirv_target_env.cpp index a3aa0af03..320b3064d 100644 --- a/3rdparty/spirv-tools/source/spirv_target_env.cpp +++ b/3rdparty/spirv-tools/source/spirv_target_env.cpp @@ -248,3 +248,43 @@ bool spvIsWebGPUEnv(spv_target_env env) { } return false; } + +bool spvIsVulkanOrWebGPUEnv(spv_target_env env) { + return spvIsVulkanEnv(env) || spvIsWebGPUEnv(env); +} + +std::string spvLogStringForEnv(spv_target_env env) { + switch (env) { + case SPV_ENV_OPENCL_1_2: + case SPV_ENV_OPENCL_2_0: + case SPV_ENV_OPENCL_2_1: + case SPV_ENV_OPENCL_2_2: + case SPV_ENV_OPENCL_EMBEDDED_1_2: + case SPV_ENV_OPENCL_EMBEDDED_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_1: + case SPV_ENV_OPENCL_EMBEDDED_2_2: { + return "OpenCL"; + } + case SPV_ENV_OPENGL_4_0: + case SPV_ENV_OPENGL_4_1: + case SPV_ENV_OPENGL_4_2: + case SPV_ENV_OPENGL_4_3: + case SPV_ENV_OPENGL_4_5: { + return "OpenGL"; + } + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_VULKAN_1_1: { + return "Vulkan"; + } + case SPV_ENV_WEBGPU_0: { + return "WebGPU"; + } + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: { + return "Universal"; + } + } + return "Unknown"; +} diff --git a/3rdparty/spirv-tools/source/spirv_target_env.h b/3rdparty/spirv-tools/source/spirv_target_env.h index d1bd83512..d4635705f 100644 --- a/3rdparty/spirv-tools/source/spirv_target_env.h +++ b/3rdparty/spirv-tools/source/spirv_target_env.h @@ -15,6 +15,8 @@ #ifndef SOURCE_SPIRV_TARGET_ENV_H_ #define SOURCE_SPIRV_TARGET_ENV_H_ +#include + #include "spirv-tools/libspirv.h" // Parses s into *env and returns true if successful. If unparsable, returns @@ -30,7 +32,14 @@ bool spvIsOpenCLEnv(spv_target_env env); // Returns true if |env| is an WEBGPU environment, false otherwise. bool spvIsWebGPUEnv(spv_target_env env); +// Returns true if |env| is a VULKAN or WEBGPU environment, false otherwise. +bool spvIsVulkanOrWebGPUEnv(spv_target_env env); + // Returns the version number for the given SPIR-V target environment. uint32_t spvVersionForTargetEnv(spv_target_env env); +// Returns a string to use in logging messages that indicates the class of +// environment, i.e. "Vulkan", "WebGPU", "OpenCL", etc. +std::string spvLogStringForEnv(spv_target_env env); + #endif // SOURCE_SPIRV_TARGET_ENV_H_ diff --git a/3rdparty/spirv-tools/source/val/validate.cpp b/3rdparty/spirv-tools/source/val/validate.cpp index 9797d31ad..4024f6169 100644 --- a/3rdparty/spirv-tools/source/val/validate.cpp +++ b/3rdparty/spirv-tools/source/val/validate.cpp @@ -249,8 +249,7 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) { // For Vulkan and WebGPU, the static function-call graph for an entry point // must not contain cycles. - if (spvIsWebGPUEnv(_.context()->target_env) || - spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { if (_.recursive_entry_points().find(entry_point) != _.recursive_entry_points().end()) { return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(entry_point)) diff --git a/3rdparty/spirv-tools/source/val/validate_builtins.cpp b/3rdparty/spirv-tools/source/val/validate_builtins.cpp index aaba32490..ee7fc3c3d 100644 --- a/3rdparty/spirv-tools/source/val/validate_builtins.cpp +++ b/3rdparty/spirv-tools/source/val/validate_builtins.cpp @@ -1617,6 +1617,46 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( } } + if (spvIsWebGPUEnv(_.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) + << "WebGPU spec allows BuiltIn Position 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: { + if (spv_result_t error = ValidateF32Vec( + decoration, built_in_inst, 4, + [this, &referenced_from_inst]( + const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << "According to the WebGPU spec BuiltIn Position " + "variable needs to be a 4-component 32-bit float " + "vector. " + << message; + })) { + return error; + } + break; + } + default: { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << "WebGPU spec allows BuiltIn Position to be used only " + "with the Vertex 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( @@ -2656,14 +2696,15 @@ spv_result_t BuiltInsValidator::Run() { // Validates correctness of built-in variables. spv_result_t ValidateBuiltIns(ValidationState_t& _) { - if (!spvIsVulkanEnv(_.context()->target_env)) { - // Early return. All currently implemented rules are based on Vulkan spec. + if (!spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + // Early return. All currently implemented rules are based on Vulkan or + // WebGPU spec. // // TODO: If you are adding validation rules for environments other than - // Vulkan (or general rules which are not environment independent), then you - // need to modify or remove this condition. Consider also adding early - // returns into BuiltIn-specific rules, so that the system doesn't spawn new - // rules which don't do anything. + // Vulkan or WebGPU (or general rules which are not environment + // independent), then you need to modify or remove this condition. Consider + // also adding early returns into BuiltIn-specific rules, so that the system + // doesn't spawn new rules which don't do anything. return SPV_SUCCESS; } diff --git a/3rdparty/spirv-tools/source/val/validate_cfg.cpp b/3rdparty/spirv-tools/source/val/validate_cfg.cpp index 8fe30a881..fe79dde1e 100644 --- a/3rdparty/spirv-tools/source/val/validate_cfg.cpp +++ b/3rdparty/spirv-tools/source/val/validate_cfg.cpp @@ -112,6 +112,19 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } +spv_result_t ValidateBranch(ValidationState_t& _, const Instruction* inst) { + // target operands must be OpLabel + const auto id = inst->GetOperandAs(0); + const auto target = _.FindDef(id); + if (!target || SpvOpLabel != target->opcode()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "'Target Label' operands for OpBranch must be the ID " + "of an OpLabel instruction"; + } + + return SPV_SUCCESS; +} + spv_result_t ValidateBranchConditional(ValidationState_t& _, const Instruction* inst) { // num_operands is either 3 or 5 --- if 5, the last two need to be literal @@ -155,6 +168,26 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateSwitch(ValidationState_t& _, const Instruction* inst) { + const auto num_operands = inst->operands().size(); + // At least two operands (selector, default), any more than that are + // literal/target. + + // target operands must be OpLabel + for (size_t i = 2; i < num_operands; i += 2) { + // literal, id + const auto id = inst->GetOperandAs(i + 1); + const auto target = _.FindDef(id); + if (!target || SpvOpLabel != target->opcode()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "'Target Label' operands for OpSwitch must be IDs of an " + "OpLabel instruction"; + } + } + + return SPV_SUCCESS; +} + spv_result_t ValidateReturnValue(ValidationState_t& _, const Instruction* inst) { const auto value_id = inst->GetOperandAs(0); @@ -764,12 +797,18 @@ spv_result_t ControlFlowPass(ValidationState_t& _, const Instruction* inst) { case SpvOpPhi: if (auto error = ValidatePhi(_, inst)) return error; break; + case SpvOpBranch: + if (auto error = ValidateBranch(_, inst)) return error; + break; case SpvOpBranchConditional: if (auto error = ValidateBranchConditional(_, inst)) return error; break; case SpvOpReturnValue: if (auto error = ValidateReturnValue(_, inst)) return error; break; + case SpvOpSwitch: + if (auto error = ValidateSwitch(_, inst)) return error; + break; default: break; } diff --git a/3rdparty/spirv-tools/source/val/validate_datarules.cpp b/3rdparty/spirv-tools/source/val/validate_datarules.cpp index 129b6bbf9..826eb8d85 100644 --- a/3rdparty/spirv-tools/source/val/validate_datarules.cpp +++ b/3rdparty/spirv-tools/source/val/validate_datarules.cpp @@ -214,6 +214,21 @@ spv_result_t ValidateStruct(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } +// Validates that any undefined type of the array is a forward pointer. +// It is valid to declare a forward pointer, and use its as the element +// type of the array. +spv_result_t ValidateArray(ValidationState_t& _, const Instruction* inst) { + auto element_type_id = inst->GetOperandAs(1); + auto element_type_instruction = _.FindDef(element_type_id); + if (element_type_instruction == nullptr && + !_.IsForwardPointer(element_type_id)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Forward reference operands in an OpTypeArray must first be " + "declared using OpTypeForwardPointer."; + } + return SPV_SUCCESS; +} + } // namespace // Validates that Data Rules are followed according to the specifications. @@ -256,6 +271,10 @@ spv_result_t DataRulesPass(ValidationState_t& _, const Instruction* inst) { if (auto error = ValidateStruct(_, inst)) return error; break; } + case SpvOpTypeArray: { + if (auto error = ValidateArray(_, inst)) return error; + break; + } // TODO(ehsan): add more data rules validation here. default: { break; } } diff --git a/3rdparty/spirv-tools/source/val/validate_decorations.cpp b/3rdparty/spirv-tools/source/val/validate_decorations.cpp index 7f150aafa..164a5ddc9 100644 --- a/3rdparty/spirv-tools/source/val/validate_decorations.cpp +++ b/3rdparty/spirv-tools/source/val/validate_decorations.cpp @@ -379,6 +379,7 @@ bool IsAlignedTo(uint32_t offset, uint32_t alignment) { // or row major-ness. spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, const char* decoration_str, bool blockRules, + uint32_t incoming_offset, MemberConstraints& constraints, ValidationState_t& vstate) { if (vstate.options()->skip_block_layout) return SPV_SUCCESS; @@ -429,7 +430,8 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, } } } - member_offsets.push_back(MemberOffsetPair{memberIdx, offset}); + member_offsets.push_back( + MemberOffsetPair{memberIdx, incoming_offset + offset}); } std::stable_sort( member_offsets.begin(), member_offsets.end(), @@ -493,9 +495,9 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, // Check struct members recursively. spv_result_t recursive_status = SPV_SUCCESS; if (SpvOpTypeStruct == opcode && - SPV_SUCCESS != (recursive_status = - checkLayout(id, storage_class_str, decoration_str, - blockRules, constraints, vstate))) + SPV_SUCCESS != (recursive_status = checkLayout( + id, storage_class_str, decoration_str, blockRules, + offset, constraints, vstate))) return recursive_status; // Check matrix stride. if (SpvOpTypeMatrix == opcode) { @@ -507,23 +509,53 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, << " not satisfying alignment to " << alignment; } } - // Check arrays and runtime arrays. - if (SpvOpTypeArray == opcode || SpvOpTypeRuntimeArray == opcode) { - const auto typeId = inst->word(2); - const auto arrayInst = vstate.FindDef(typeId); - if (SpvOpTypeStruct == arrayInst->opcode() && - SPV_SUCCESS != (recursive_status = checkLayout( - typeId, storage_class_str, decoration_str, - blockRules, constraints, vstate))) - return recursive_status; + + // Check arrays and runtime arrays recursively. + auto array_inst = inst; + auto array_alignment = alignment; + while (array_inst->opcode() == SpvOpTypeArray || + array_inst->opcode() == SpvOpTypeRuntimeArray) { + const auto typeId = array_inst->word(2); + const auto element_inst = vstate.FindDef(typeId); // Check array stride. - for (auto& decoration : vstate.id_decorations(id)) { - if (SpvDecorationArrayStride == decoration.dec_type() && - !IsAlignedTo(decoration.params()[0], alignment)) - return fail(memberIdx) - << "is an array with stride " << decoration.params()[0] - << " not satisfying alignment to " << alignment; + auto array_stride = 0; + for (auto& decoration : vstate.id_decorations(array_inst->id())) { + if (SpvDecorationArrayStride == decoration.dec_type()) { + array_stride = decoration.params()[0]; + if (!IsAlignedTo(array_stride, array_alignment)) + return fail(memberIdx) + << "contains an array with stride " << decoration.params()[0] + << " not satisfying alignment to " << alignment; + } } + + bool is_int32 = false; + bool is_const = false; + uint32_t num_elements = 0; + if (array_inst->opcode() == SpvOpTypeArray) { + std::tie(is_int32, is_const, num_elements) = + vstate.EvalInt32IfConst(array_inst->word(3)); + } + num_elements = std::max(1u, num_elements); + // Check each element recursively if it is a struct. There is a + // limitation to this check if the array size is a spec constant or is a + // runtime array then we will only check a single element. This means + // some improper straddles might be missed. + for (uint32_t i = 0; i < num_elements; ++i) { + uint32_t next_offset = i * array_stride + offset; + if (SpvOpTypeStruct == element_inst->opcode() && + SPV_SUCCESS != (recursive_status = checkLayout( + typeId, storage_class_str, decoration_str, + blockRules, next_offset, constraints, vstate))) + return recursive_status; + } + + // Proceed to the element in case it is an array. + array_inst = element_inst; + array_alignment = scalar_block_layout + ? getScalarAlignment(array_inst->id(), vstate) + : getBaseAlignment(array_inst->id(), blockRules, + constraint, constraints, vstate); } nextValidOffset = offset + size; if (!scalar_block_layout && blockRules && @@ -859,8 +891,15 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { if (uniform || push_constant || storage_buffer || phys_storage_buffer) { const auto ptrInst = vstate.FindDef(words[1]); assert(SpvOpTypePointer == ptrInst->opcode()); - const auto id = ptrInst->words()[3]; - if (SpvOpTypeStruct != vstate.FindDef(id)->opcode()) continue; + auto id = ptrInst->words()[3]; + auto id_inst = vstate.FindDef(id); + // Jump through one level of arraying. + if (id_inst->opcode() == SpvOpTypeArray || + id_inst->opcode() == SpvOpTypeRuntimeArray) { + id = id_inst->GetOperandAs(1u); + id_inst = vstate.FindDef(id); + } + if (SpvOpTypeStruct != id_inst->opcode()) continue; MemberConstraints constraints; ComputeMemberConstraintsForStruct(&constraints, id, LayoutConstraints(), vstate); @@ -942,12 +981,12 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { "decorations."; } else if (blockRules && (SPV_SUCCESS != (recursive_status = checkLayout( - id, sc_str, deco_str, true, + id, sc_str, deco_str, true, 0, constraints, vstate)))) { return recursive_status; } else if (bufferRules && (SPV_SUCCESS != (recursive_status = checkLayout( - id, sc_str, deco_str, false, + id, sc_str, deco_str, false, 0, constraints, vstate)))) { return recursive_status; } @@ -959,42 +998,64 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { return SPV_SUCCESS; } +// Returns true if |decoration| cannot be applied to the same id more than once. +bool AtMostOncePerId(SpvDecoration decoration) { + return decoration == SpvDecorationArrayStride; +} + +// Returns true if |decoration| cannot be applied to the same member more than +// once. +bool AtMostOncePerMember(SpvDecoration decoration) { + switch (decoration) { + case SpvDecorationOffset: + case SpvDecorationMatrixStride: + case SpvDecorationRowMajor: + case SpvDecorationColMajor: + return true; + default: + return false; + } +} + +// Returns the string name for |decoration|. +const char* GetDecorationName(SpvDecoration decoration) { + switch (decoration) { + case SpvDecorationArrayStride: + return "ArrayStride"; + case SpvDecorationOffset: + return "Offset"; + case SpvDecorationMatrixStride: + return "MatrixStride"; + case SpvDecorationRowMajor: + return "RowMajor"; + case SpvDecorationColMajor: + return "ColMajor"; + case SpvDecorationBlock: + return "Block"; + case SpvDecorationBufferBlock: + return "BufferBlock"; + default: + return ""; + } +} + spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) { - using AtMostOnceSet = std::unordered_set; - using MutuallyExclusiveSets = - std::vector>; using PerIDKey = std::tuple; using PerMemberKey = std::tuple; - using DecorationNameTable = - std::unordered_map; - static const auto* const at_most_once_per_id = new AtMostOnceSet{ - SpvDecorationArrayStride, - }; - static const auto* const at_most_once_per_member = new AtMostOnceSet{ - SpvDecorationOffset, - SpvDecorationMatrixStride, - SpvDecorationRowMajor, - SpvDecorationColMajor, - }; - static const auto* const mutually_exclusive_per_id = - new MutuallyExclusiveSets{ - {SpvDecorationBlock, SpvDecorationBufferBlock}, - }; - static const auto* const mutually_exclusive_per_member = - new MutuallyExclusiveSets{ - {SpvDecorationRowMajor, SpvDecorationColMajor}, - }; - // For printing the decoration name. - static const auto* const decoration_name = new DecorationNameTable{ - {SpvDecorationArrayStride, "ArrayStride"}, - {SpvDecorationOffset, "Offset"}, - {SpvDecorationMatrixStride, "MatrixStride"}, - {SpvDecorationRowMajor, "RowMajor"}, - {SpvDecorationColMajor, "ColMajor"}, - {SpvDecorationBlock, "Block"}, - {SpvDecorationBufferBlock, "BufferBlock"}, - }; + // An Array of pairs where the decorations in the pair cannot both be applied + // to the same id. + static const SpvDecoration mutually_exclusive_per_id[][2] = { + {SpvDecorationBlock, SpvDecorationBufferBlock}}; + static const auto num_mutually_exclusive_per_id_pairs = + sizeof(mutually_exclusive_per_id) / (2 * sizeof(SpvDecoration)); + + // An Array of pairs where the decorations in the pair cannot both be applied + // to the same member. + static const SpvDecoration mutually_exclusive_per_member[][2] = { + {SpvDecorationRowMajor, SpvDecorationColMajor}}; + static const auto num_mutually_exclusive_per_mem_pairs = + sizeof(mutually_exclusive_per_member) / (2 * sizeof(SpvDecoration)); std::set seen_per_id; std::set seen_per_member; @@ -1006,26 +1067,31 @@ spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) { const auto dec_type = static_cast(words[2]); const auto k = PerIDKey(dec_type, id); const auto already_used = !seen_per_id.insert(k).second; - if (already_used && - at_most_once_per_id->find(dec_type) != at_most_once_per_id->end()) { + if (already_used && AtMostOncePerId(dec_type)) { return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) << "ID '" << id << "' decorated with " - << decoration_name->at(dec_type) + << GetDecorationName(dec_type) << " multiple times is not allowed."; } // Verify certain mutually exclusive decorations are not both applied on // an ID. - for (const auto& s : *mutually_exclusive_per_id) { - if (s.find(dec_type) == s.end()) continue; - for (auto excl_dec_type : s) { - if (excl_dec_type == dec_type) continue; - const auto excl_k = PerIDKey(excl_dec_type, id); - if (seen_per_id.find(excl_k) != seen_per_id.end()) { - return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) - << "ID '" << id << "' decorated with both " - << decoration_name->at(dec_type) << " and " - << decoration_name->at(excl_dec_type) << " is not allowed."; - } + for (uint32_t pair_idx = 0; + pair_idx < num_mutually_exclusive_per_id_pairs; ++pair_idx) { + SpvDecoration excl_dec_type = SpvDecorationMax; + if (mutually_exclusive_per_id[pair_idx][0] == dec_type) { + excl_dec_type = mutually_exclusive_per_id[pair_idx][1]; + } else if (mutually_exclusive_per_id[pair_idx][1] == dec_type) { + excl_dec_type = mutually_exclusive_per_id[pair_idx][0]; + } else { + continue; + } + + const auto excl_k = PerIDKey(excl_dec_type, id); + if (seen_per_id.find(excl_k) != seen_per_id.end()) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "ID '" << id << "' decorated with both " + << GetDecorationName(dec_type) << " and " + << GetDecorationName(excl_dec_type) << " is not allowed."; } } } else if (SpvOpMemberDecorate == inst.opcode()) { @@ -1034,27 +1100,32 @@ spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) { const auto dec_type = static_cast(words[3]); const auto k = PerMemberKey(dec_type, id, member_id); const auto already_used = !seen_per_member.insert(k).second; - if (already_used && at_most_once_per_member->find(dec_type) != - at_most_once_per_member->end()) { + if (already_used && AtMostOncePerMember(dec_type)) { return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) << "ID '" << id << "', member '" << member_id - << "' decorated with " << decoration_name->at(dec_type) + << "' decorated with " << GetDecorationName(dec_type) << " multiple times is not allowed."; } // Verify certain mutually exclusive decorations are not both applied on // a (ID, member) tuple. - for (const auto& s : *mutually_exclusive_per_member) { - if (s.find(dec_type) == s.end()) continue; - for (auto excl_dec_type : s) { - if (excl_dec_type == dec_type) continue; - const auto excl_k = PerMemberKey(excl_dec_type, id, member_id); - if (seen_per_member.find(excl_k) != seen_per_member.end()) { - return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) - << "ID '" << id << "', member '" << member_id - << "' decorated with both " << decoration_name->at(dec_type) - << " and " << decoration_name->at(excl_dec_type) - << " is not allowed."; - } + for (uint32_t pair_idx = 0; + pair_idx < num_mutually_exclusive_per_mem_pairs; ++pair_idx) { + SpvDecoration excl_dec_type = SpvDecorationMax; + if (mutually_exclusive_per_member[pair_idx][0] == dec_type) { + excl_dec_type = mutually_exclusive_per_member[pair_idx][1]; + } else if (mutually_exclusive_per_member[pair_idx][1] == dec_type) { + excl_dec_type = mutually_exclusive_per_member[pair_idx][0]; + } else { + continue; + } + + const auto excl_k = PerMemberKey(excl_dec_type, id, member_id); + if (seen_per_member.find(excl_k) != seen_per_member.end()) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "ID '" << id << "', member '" << member_id + << "' decorated with both " << GetDecorationName(dec_type) + << " and " << GetDecorationName(excl_dec_type) + << " is not allowed."; } } } diff --git a/3rdparty/spirv-tools/source/val/validate_memory.cpp b/3rdparty/spirv-tools/source/val/validate_memory.cpp index 3b104be8d..9e93cf134 100644 --- a/3rdparty/spirv-tools/source/val/validate_memory.cpp +++ b/3rdparty/spirv-tools/source/val/validate_memory.cpp @@ -515,23 +515,13 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { if (inst->operands().size() > 3 && storage_class != SpvStorageClassOutput && storage_class != SpvStorageClassPrivate && storage_class != SpvStorageClassFunction) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpVariable, '" << _.getIdName(inst->id()) << "', has a disallowed initializer & storage class " << "combination.\n" - << "From Vulkan spec, Appendix A:\n" - << "Variable declarations that include initializers must have " - << "one of the following storage classes: Output, Private, or " - << "Function"; - } - - if (spvIsWebGPUEnv(_.context()->target_env)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpVariable, '" << _.getIdName(inst->id()) - << "', has a disallowed initializer & storage class " - << "combination.\n" - << "From WebGPU execution environment spec:\n" + << "From " << spvLogStringForEnv(_.context()->target_env) + << " spec:\n" << "Variable declarations that include initializers must have " << "one of the following storage classes: Output, Private, or " << "Function"; diff --git a/3rdparty/spirv-tools/source/val/validate_type.cpp b/3rdparty/spirv-tools/source/val/validate_type.cpp index 94ea66034..7669f72f0 100644 --- a/3rdparty/spirv-tools/source/val/validate_type.cpp +++ b/3rdparty/spirv-tools/source/val/validate_type.cpp @@ -107,14 +107,12 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) { << "' is a void type."; } - if ((spvIsVulkanEnv(_.context()->target_env) || - spvIsWebGPUEnv(_.context()->target_env)) && + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && element_type->opcode() == SpvOpTypeRuntimeArray) { - const char* env_text = - spvIsVulkanEnv(_.context()->target_env) ? "Vulkan" : "WebGPU"; return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpTypeArray Element Type '" << _.getIdName(element_type_id) - << "' is not valid in " << env_text << " environment."; + << "' is not valid in " + << spvLogStringForEnv(_.context()->target_env) << " environments."; } const auto length_index = 2; @@ -172,15 +170,12 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _, << _.getIdName(element_id) << "' is a void type."; } - if ((spvIsVulkanEnv(_.context()->target_env) || - spvIsWebGPUEnv(_.context()->target_env)) && + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && element_type->opcode() == SpvOpTypeRuntimeArray) { - const char* env_text = - spvIsVulkanEnv(_.context()->target_env) ? "Vulkan" : "WebGPU"; return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpTypeRuntimeArray Element Type '" - << _.getIdName(element_id) << "' is not valid in " << env_text - << " environment."; + << _.getIdName(element_id) << "' is not valid in " + << spvLogStringForEnv(_.context()->target_env) << " environments."; } return SPV_SUCCESS; @@ -229,17 +224,15 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { } } - if ((spvIsVulkanEnv(_.context()->target_env) || - spvIsWebGPUEnv(_.context()->target_env)) && + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && member_type->opcode() == SpvOpTypeRuntimeArray) { const bool is_last_member = member_type_index == inst->operands().size() - 1; if (!is_last_member) { - const char* env_text = - spvIsVulkanEnv(_.context()->target_env) ? "Vulkan" : "WebGPU"; return _.diag(SPV_ERROR_INVALID_ID, inst) - << "In " << env_text << ", OpTypeRuntimeArray must only be used " - << "for the last member of an OpTypeStruct"; + << "In " << spvLogStringForEnv(_.context()->target_env) + << ", OpTypeRuntimeArray must only be used for the last member " + "of an OpTypeStruct"; } } } diff --git a/3rdparty/spirv-tools/test/opt/code_sink_test.cpp b/3rdparty/spirv-tools/test/opt/code_sink_test.cpp index 9b86c660a..f1bd12756 100644 --- a/3rdparty/spirv-tools/test/opt/code_sink_test.cpp +++ b/3rdparty/spirv-tools/test/opt/code_sink_test.cpp @@ -528,6 +528,30 @@ TEST_F(CodeSinkTest, MoveWithAtomicWithoutSync) { EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); } +TEST_F(CodeSinkTest, DecorationOnLoad) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" %2 + OpDecorate %3 RelaxedPrecision + %void = OpTypeVoid + %5 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %2 = OpVariable %_ptr_Input_float Input + %1 = OpFunction %void None %5 + %8 = OpLabel + %3 = OpLoad %float %2 + OpReturn + OpFunctionEnd +)"; + + // We just want to make sure the code does not crash. + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/reduce/CMakeLists.txt b/3rdparty/spirv-tools/test/reduce/CMakeLists.txt index b35cdb260..b1fdaff47 100644 --- a/3rdparty/spirv-tools/test/reduce/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/reduce/CMakeLists.txt @@ -13,15 +13,15 @@ # limitations under the License. add_spvtools_unittest(TARGET reduce - SRCS operand_to_constant_reduction_pass_test.cpp - operand_to_undef_reduction_pass_test.cpp - operand_to_dominating_id_reduction_pass_test.cpp + SRCS operand_to_constant_test.cpp + operand_to_undef_test.cpp + operand_to_dominating_id_test.cpp reduce_test_util.cpp reduce_test_util.h reducer_test.cpp - remove_opname_instruction_reduction_pass_test.cpp - remove_unreferenced_instruction_reduction_pass_test.cpp - structured_loop_to_selection_reduction_pass_test.cpp + remove_opname_instruction_test.cpp + remove_unreferenced_instruction_test.cpp + structured_loop_to_selection_test.cpp validation_during_reduction_test.cpp LIBS SPIRV-Tools-reduce ) diff --git a/3rdparty/spirv-tools/test/reduce/operand_to_constant_reduction_pass_test.cpp b/3rdparty/spirv-tools/test/reduce/operand_to_constant_test.cpp similarity index 93% rename from 3rdparty/spirv-tools/test/reduce/operand_to_constant_reduction_pass_test.cpp rename to 3rdparty/spirv-tools/test/reduce/operand_to_constant_test.cpp index 34cc4a117..15d76cab7 100644 --- a/3rdparty/spirv-tools/test/reduce/operand_to_constant_reduction_pass_test.cpp +++ b/3rdparty/spirv-tools/test/reduce/operand_to_constant_test.cpp @@ -14,7 +14,7 @@ #include "reduce_test_util.h" #include "source/opt/build_module.h" -#include "source/reduce/operand_to_const_reduction_pass.h" +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" namespace spvtools { namespace reduce { @@ -97,8 +97,9 @@ TEST(OperandToConstantReductionPassTest, BasicCheck) { const auto consumer = nullptr; const auto context = BuildModule(env, consumer, original, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = + OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); ASSERT_EQ(17, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); ops[0]->TryToApply(); @@ -146,8 +147,9 @@ TEST(OperandToConstantReductionPassTest, WithCalledFunction) { const auto consumer = nullptr; const auto context = BuildModule(env, consumer, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = + OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); ASSERT_EQ(0, ops.size()); } diff --git a/3rdparty/spirv-tools/test/reduce/operand_to_dominating_id_reduction_pass_test.cpp b/3rdparty/spirv-tools/test/reduce/operand_to_dominating_id_test.cpp similarity index 96% rename from 3rdparty/spirv-tools/test/reduce/operand_to_dominating_id_reduction_pass_test.cpp rename to 3rdparty/spirv-tools/test/reduce/operand_to_dominating_id_test.cpp index cc0de65cd..60bff9b25 100644 --- a/3rdparty/spirv-tools/test/reduce/operand_to_dominating_id_reduction_pass_test.cpp +++ b/3rdparty/spirv-tools/test/reduce/operand_to_dominating_id_test.cpp @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/reduce/operand_to_dominating_id_reduction_pass.h" #include "reduce_test_util.h" #include "source/opt/build_module.h" +#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h" namespace spvtools { namespace reduce { @@ -53,8 +53,8 @@ TEST(OperandToDominatingIdReductionPassTest, BasicCheck) { const auto consumer = nullptr; const auto context = BuildModule(env, consumer, original, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = OperandToDominatingIdReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(10, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); ops[0]->TryToApply(); diff --git a/3rdparty/spirv-tools/test/reduce/operand_to_undef_reduction_pass_test.cpp b/3rdparty/spirv-tools/test/reduce/operand_to_undef_test.cpp similarity index 95% rename from 3rdparty/spirv-tools/test/reduce/operand_to_undef_reduction_pass_test.cpp rename to 3rdparty/spirv-tools/test/reduce/operand_to_undef_test.cpp index 71bf96cf4..3e3079b85 100644 --- a/3rdparty/spirv-tools/test/reduce/operand_to_undef_reduction_pass_test.cpp +++ b/3rdparty/spirv-tools/test/reduce/operand_to_undef_test.cpp @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/reduce/operand_to_undef_reduction_pass.h" #include "source/opt/build_module.h" +#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h" #include "test/reduce/reduce_test_util.h" namespace spvtools { @@ -163,8 +163,9 @@ TEST(OperandToUndefReductionPassTest, BasicCheck) { const auto consumer = nullptr; const auto context = BuildModule(env, consumer, original, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = + OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); ASSERT_EQ(10, ops.size()); @@ -216,8 +217,9 @@ TEST(OperandToUndefReductionPassTest, WithCalledFunction) { const auto consumer = nullptr; const auto context = BuildModule(env, consumer, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = + OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); ASSERT_EQ(0, ops.size()); } diff --git a/3rdparty/spirv-tools/test/reduce/reduce_test_util.h b/3rdparty/spirv-tools/test/reduce/reduce_test_util.h index 499c77475..080edad10 100644 --- a/3rdparty/spirv-tools/test/reduce/reduce_test_util.h +++ b/3rdparty/spirv-tools/test/reduce/reduce_test_util.h @@ -24,23 +24,6 @@ namespace spvtools { namespace reduce { -// A helper class that subclasses a given reduction pass class in order to -// provide a wrapper for its protected methods. -template -class TestSubclass : public ReductionPassT { - public: - // Creates an instance of the reduction pass subclass with respect to target - // environment |env|. - explicit TestSubclass(const spv_target_env env) : ReductionPassT(env) {} - ~TestSubclass() = default; - - // A wrapper for GetAvailableOpportunities(...) - std::vector> - WrapGetAvailableOpportunities(opt::IRContext* context) const { - return ReductionPassT::GetAvailableOpportunities(context); - } -}; - // Checks whether the given binaries are bit-wise equal. void CheckEqual(spv_target_env env, const std::vector& expected_binary, diff --git a/3rdparty/spirv-tools/test/reduce/reducer_test.cpp b/3rdparty/spirv-tools/test/reduce/reducer_test.cpp index 88fc5e44e..888724c3d 100644 --- a/3rdparty/spirv-tools/test/reduce/reducer_test.cpp +++ b/3rdparty/spirv-tools/test/reduce/reducer_test.cpp @@ -14,10 +14,10 @@ #include "reduce_test_util.h" -#include "source/reduce/operand_to_const_reduction_pass.h" +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" #include "source/reduce/reducer.h" -#include "source/reduce/remove_opname_instruction_reduction_pass.h" -#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h" +#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h" +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" namespace spvtools { namespace reduce { @@ -217,9 +217,10 @@ TEST(ReducerTest, ExprToConstantAndRemoveUnreferenced) { [&](const std::vector& binary, uint32_t) -> bool { return ping_pong_interesting.IsInteresting(binary); }); - reducer.AddReductionPass(MakeUnique(env)); reducer.AddReductionPass( - MakeUnique(env)); + MakeUnique()); + reducer.AddReductionPass( + MakeUnique()); std::vector binary_in; SpirvTools t(env); @@ -288,9 +289,9 @@ TEST(ReducerTest, RemoveOpnameAndRemoveUnreferenced) { return ping_pong_interesting.IsInteresting(binary); }); reducer.AddReductionPass( - MakeUnique(env)); + MakeUnique()); reducer.AddReductionPass( - MakeUnique(env)); + MakeUnique()); std::vector binary_in; SpirvTools t(env); diff --git a/3rdparty/spirv-tools/test/reduce/remove_opname_instruction_reduction_pass_test.cpp b/3rdparty/spirv-tools/test/reduce/remove_opname_instruction_test.cpp similarity index 84% rename from 3rdparty/spirv-tools/test/reduce/remove_opname_instruction_reduction_pass_test.cpp rename to 3rdparty/spirv-tools/test/reduce/remove_opname_instruction_test.cpp index 38a2d7f77..e74c0f9c1 100644 --- a/3rdparty/spirv-tools/test/reduce/remove_opname_instruction_reduction_pass_test.cpp +++ b/3rdparty/spirv-tools/test/reduce/remove_opname_instruction_test.cpp @@ -16,7 +16,8 @@ #include "source/opt/build_module.h" #include "source/reduce/reduction_opportunity.h" -#include "source/reduce/remove_opname_instruction_reduction_pass.h" +#include "source/reduce/reduction_pass.h" +#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h" namespace spvtools { namespace reduce { @@ -42,8 +43,8 @@ TEST(RemoveOpnameInstructionReductionPassTest, NothingToRemove) { const auto consumer = nullptr; const auto context = BuildModule(env, consumer, source, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = RemoveOpNameInstructionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(0, ops.size()); } @@ -76,8 +77,8 @@ TEST(RemoveOpnameInstructionReductionPassTest, RemoveSingleOpName) { const auto consumer = nullptr; const auto context = BuildModule(env, consumer, original, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = RemoveOpNameInstructionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); ops[0]->TryToApply(); @@ -126,14 +127,14 @@ TEST(RemoveOpnameInstructionReductionPassTest, TryApplyRemovesAllOpName) { const std::string expected = prologue + epilogue; const auto env = SPV_ENV_UNIVERSAL_1_3; - auto pass = TestSubclass(env); { // Check the right number of opportunities is detected const auto consumer = nullptr; const auto context = BuildModule(env, consumer, original, kReduceAssembleOption); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = RemoveOpNameInstructionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(5, ops.size()); } @@ -142,7 +143,11 @@ TEST(RemoveOpnameInstructionReductionPassTest, TryApplyRemovesAllOpName) { std::vector binary; SpirvTools t(env); ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption)); - auto reduced_binary = pass.TryApplyReduction(binary); + auto reduced_binary = + ReductionPass(env, + spvtools::MakeUnique< + RemoveOpNameInstructionReductionOpportunityFinder>()) + .TryApplyReduction(binary); CheckEqual(env, expected, reduced_binary); } } @@ -190,14 +195,14 @@ TEST(RemoveOpnameInstructionReductionPassTest, const std::string expected = prologue + epilogue; const auto env = SPV_ENV_UNIVERSAL_1_3; - auto pass = TestSubclass(env); { // Check the right number of opportunities is detected const auto consumer = nullptr; const auto context = BuildModule(env, consumer, original, kReduceAssembleOption); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = RemoveOpNameInstructionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(6, ops.size()); } @@ -206,7 +211,11 @@ TEST(RemoveOpnameInstructionReductionPassTest, std::vector binary; SpirvTools t(env); ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption)); - auto reduced_binary = pass.TryApplyReduction(binary); + auto reduced_binary = + ReductionPass(env, + spvtools::MakeUnique< + RemoveOpNameInstructionReductionOpportunityFinder>()) + .TryApplyReduction(binary); CheckEqual(env, expected, reduced_binary); } } diff --git a/3rdparty/spirv-tools/test/reduce/remove_unreferenced_instruction_reduction_pass_test.cpp b/3rdparty/spirv-tools/test/reduce/remove_unreferenced_instruction_test.cpp similarity index 94% rename from 3rdparty/spirv-tools/test/reduce/remove_unreferenced_instruction_reduction_pass_test.cpp rename to 3rdparty/spirv-tools/test/reduce/remove_unreferenced_instruction_test.cpp index a002fa36a..76d7ddd09 100644 --- a/3rdparty/spirv-tools/test/reduce/remove_unreferenced_instruction_reduction_pass_test.cpp +++ b/3rdparty/spirv-tools/test/reduce/remove_unreferenced_instruction_test.cpp @@ -16,7 +16,9 @@ #include "source/opt/build_module.h" #include "source/reduce/reduction_opportunity.h" -#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h" +#include "source/reduce/reduction_pass.h" +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" +#include "source/util/make_unique.h" namespace spvtools { namespace reduce { @@ -73,9 +75,8 @@ TEST(RemoveUnreferencedInstructionReductionPassTest, RemoveStores) { const auto consumer = nullptr; const auto context = BuildModule(env, consumer, original, kReduceAssembleOption); - const auto pass = - TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = RemoveUnreferencedInstructionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(4, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); ops[0]->TryToApply(); @@ -132,7 +133,9 @@ TEST(RemoveUnreferencedInstructionReductionPassTest, ApplyReduction) { SpirvTools t(env); ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption)); - auto pass = TestSubclass(env); + ReductionPass pass( + env, spvtools::MakeUnique< + RemoveUnreferencedInstructionReductionOpportunityFinder>()); { // Attempt 1 should remove everything removable. diff --git a/3rdparty/spirv-tools/test/reduce/structured_loop_to_selection_reduction_pass_test.cpp b/3rdparty/spirv-tools/test/reduce/structured_loop_to_selection_test.cpp similarity index 96% rename from 3rdparty/spirv-tools/test/reduce/structured_loop_to_selection_reduction_pass_test.cpp rename to 3rdparty/spirv-tools/test/reduce/structured_loop_to_selection_test.cpp index 8388cb2e2..ae55d55cc 100644 --- a/3rdparty/spirv-tools/test/reduce/structured_loop_to_selection_reduction_pass_test.cpp +++ b/3rdparty/spirv-tools/test/reduce/structured_loop_to_selection_test.cpp @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/reduce/structured_loop_to_selection_reduction_pass.h" #include "reduce_test_util.h" #include "source/opt/build_module.h" +#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h" namespace spvtools { namespace reduce { @@ -62,8 +62,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader1) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -208,8 +208,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader2) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(4, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -677,8 +677,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader3) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(0, ops.size()); } @@ -755,8 +755,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader4) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); // Initially there are two opportunities. ASSERT_EQ(2, ops.size()); @@ -878,8 +878,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak1) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -953,8 +953,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak2) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -1021,8 +1021,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, UnconditionalBreak) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -1221,8 +1221,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, Complex) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(2, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -1688,8 +1688,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, ComplexOptimized) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(2, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2005,8 +2005,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, DominanceIssue) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2153,8 +2153,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, AccessChainIssue) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2310,8 +2310,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, DominanceAndPhiIssue) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2418,8 +2418,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, OpLineBeforeOpPhi) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2508,8 +2508,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); // There should be no opportunities. ASSERT_EQ(0, ops.size()); @@ -2552,8 +2552,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); // There should be no opportunities. ASSERT_EQ(0, ops.size()); @@ -2592,8 +2592,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, ContinueTargetIsSwitchTarget) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2667,8 +2667,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2730,8 +2730,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopBranchesStraightToMerge) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2787,8 +2787,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2871,8 +2871,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, MultipleAccessChains) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -2967,8 +2967,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(2, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -3086,8 +3086,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - const auto ops = pass.WrapGetAvailableOpportunities(context.get()); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(2, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); @@ -3206,8 +3206,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - auto ops = pass.WrapGetAvailableOpportunities(context.get()); + auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); // We cannot transform the inner loop due to its header jumping straight to // the outer loop merge (the inner loop's merge does not post-dominate its @@ -3251,7 +3251,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, CheckEqual(env, after_op_0, context.get()); // Now look again for more opportunities. - ops = pass.WrapGetAvailableOpportunities(context.get()); + ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); // What was the inner loop should now be transformable, as the jump to the // outer loop's merge has been redirected. @@ -3418,8 +3419,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LongAccessChains) { const auto env = SPV_ENV_UNIVERSAL_1_3; const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); - const auto pass = TestSubclass(env); - auto ops = pass.WrapGetAvailableOpportunities(context.get()); + auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); ASSERT_EQ(1, ops.size()); ASSERT_TRUE(ops[0]->PreconditionHolds()); diff --git a/3rdparty/spirv-tools/test/reduce/validation_during_reduction_test.cpp b/3rdparty/spirv-tools/test/reduce/validation_during_reduction_test.cpp index bb7d14e10..b8a0b206e 100644 --- a/3rdparty/spirv-tools/test/reduce/validation_during_reduction_test.cpp +++ b/3rdparty/spirv-tools/test/reduce/validation_during_reduction_test.cpp @@ -22,24 +22,21 @@ namespace spvtools { namespace reduce { namespace { -// A dumb reduction pass that removes global values regardless of whether they -// are referenced. This is very likely to make the resulting module invalid. We -// use this to test the reducer's behavior in the scenario where a bad reduction -// pass leads to an invalid module. -class BlindlyRemoveGlobalValuesPass : public ReductionPass { +// A dumb reduction opportunity finder that finds opportunities to remove global +// values regardless of whether they are referenced. This is very likely to make +// the resulting module invalid. We use this to test the reducer's behavior in +// the scenario where a bad reduction pass leads to an invalid module. +class BlindlyRemoveGlobalValuesReductionOpportunityFinder + : public ReductionOpportunityFinder { public: - // Creates the reduction pass in the context of the given target environment - // |target_env| - explicit BlindlyRemoveGlobalValuesPass(const spv_target_env target_env) - : ReductionPass(target_env) {} + BlindlyRemoveGlobalValuesReductionOpportunityFinder() = default; - ~BlindlyRemoveGlobalValuesPass() override = default; + ~BlindlyRemoveGlobalValuesReductionOpportunityFinder() override = default; // The name of this pass. std::string GetName() const final { return "BlindlyRemoveGlobalValuesPass"; }; - protected: - // Adds opportunities to remove all global values. Assuming they are all + // Finds opportunities to remove all global values. Assuming they are all // referenced (directly or indirectly) from elsewhere in the module, each such // opportunity will make the module invalid. std::vector> GetAvailableOpportunities( @@ -153,7 +150,8 @@ TEST(ValidationDuringReductionTest, CheckInvalidPassMakesNoProgress) { reducer.SetInterestingnessFunction( [](const std::vector&, uint32_t) -> bool { return true; }); - reducer.AddReductionPass(MakeUnique(env)); + reducer.AddReductionPass( + MakeUnique()); std::vector binary_in; SpirvTools t(env); @@ -357,7 +355,8 @@ TEST(ValidationDuringReductionTest, CheckNotAlwaysInvalidCanMakeProgress) { reducer.SetInterestingnessFunction( [](const std::vector&, uint32_t) -> bool { return true; }); - reducer.AddReductionPass(MakeUnique(env)); + reducer.AddReductionPass( + MakeUnique()); std::vector binary_in; SpirvTools t(env); diff --git a/3rdparty/spirv-tools/test/val/val_builtins_test.cpp b/3rdparty/spirv-tools/test/val/val_builtins_test.cpp index ec0758275..81c7b4f73 100644 --- a/3rdparty/spirv-tools/test/val/val_builtins_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_builtins_test.cpp @@ -24,6 +24,7 @@ #include #include "gmock/gmock.h" +#include "source/spirv_target_env.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" @@ -53,8 +54,13 @@ using ValidateBuiltIns = spvtest::ValidateBase; using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult = spvtest::ValidateBase>; +using ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult = + spvtest::ValidateBase>; using ValidateVulkanCombineBuiltInArrayedVariable = spvtest::ValidateBase< std::tuple>; +using ValidateWebGPUCombineBuiltInArrayedVariable = spvtest::ValidateBase< + std::tuple>; struct EntryPoint { std::string name; @@ -124,6 +130,13 @@ OpCapability SampleRateShading )"; } +std::string GetWebGPUShaderCapabilities() { + return R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +)"; +} + std::string GetDefaultShaderTypes() { return R"( %void = OpTypeVoid @@ -201,6 +214,55 @@ std::string GetDefaultShaderTypes() { )"; } +std::string GetWebGPUShaderTypes() { + return R"( +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 +%f32vec2 = OpTypeVector %f32 2 +%f32vec3 = OpTypeVector %f32 3 +%f32vec4 = OpTypeVector %f32 4 +%u32vec2 = OpTypeVector %u32 2 +%u32vec3 = OpTypeVector %u32 3 +%u32vec4 = OpTypeVector %u32 4 + +%f32_0 = OpConstant %f32 0 +%f32_1 = OpConstant %f32 1 +%f32_2 = OpConstant %f32 2 +%f32_3 = OpConstant %f32 3 +%f32_4 = OpConstant %f32 4 +%f32_h = OpConstant %f32 0.5 +%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 +%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 +%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 +%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 +%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 +%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 + +%u32_0 = OpConstant %u32 0 +%u32_1 = OpConstant %u32 1 +%u32_2 = OpConstant %u32 2 +%u32_3 = OpConstant %u32 3 +%u32_4 = OpConstant %u32 4 + +%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 +%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 +%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 + +%u32arr2 = OpTypeArray %u32 %u32_2 +%u32arr3 = OpTypeArray %u32 %u32_3 +%u32arr4 = OpTypeArray %u32 %u32_4 +%f32arr2 = OpTypeArray %f32 %u32_2 +%f32arr3 = OpTypeArray %f32 %u32_3 +%f32arr4 = OpTypeArray %f32 %u32_4 + +%f32vec3arr3 = OpTypeArray %f32vec3 %u32_3 +%f32vec4arr3 = OpTypeArray %f32vec4 %u32_3 +)"; +} + CodeGenerator GetDefaultShaderCodeGenerator() { CodeGenerator generator; generator.capabilities_ = GetDefaultShaderCapabilities(); @@ -209,24 +271,47 @@ CodeGenerator GetDefaultShaderCodeGenerator() { return generator; } -TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { - const char* const built_in = std::get<0>(GetParam()); - const char* const execution_model = std::get<1>(GetParam()); - const char* const storage_class = std::get<2>(GetParam()); - const char* const data_type = std::get<3>(GetParam()); - const TestResult& test_result = std::get<4>(GetParam()); +CodeGenerator GetWebGPUShaderCodeGenerator() { + CodeGenerator generator; + generator.capabilities_ = GetWebGPUShaderCapabilities(); + generator.memory_model_ = "OpMemoryModel Logical VulkanKHR\n"; + generator.extensions_ = "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"; + generator.types_ = GetWebGPUShaderTypes(); + return generator; +} + +bool InitializerRequired(spv_target_env env, const char* const storage_class) { + return spvIsWebGPUEnv(env) && (strncmp(storage_class, "Output", 6) == 0 || + strncmp(storage_class, "Private", 7) == 0 || + strncmp(storage_class, "Function", 8) == 0); +} + +CodeGenerator GetInMainCodeGenerator(spv_target_env env, + const char* const built_in, + const char* const execution_model, + const char* const storage_class, + const char* const data_type) { + CodeGenerator generator = spvIsWebGPUEnv(env) + ? GetWebGPUShaderCodeGenerator() + : GetDefaultShaderCodeGenerator(); - CodeGenerator generator = GetDefaultShaderCodeGenerator(); generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; std::ostringstream after_types; + after_types << "%built_in_type = OpTypeStruct " << data_type << "\n"; + if (InitializerRequired(env, storage_class)) { + after_types << "%built_in_null = OpConstantNull %built_in_type\n"; + } after_types << "%built_in_ptr = OpTypePointer " << storage_class << " %built_in_type\n"; - after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class - << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + if (InitializerRequired(env, storage_class)) { + after_types << " %built_in_null"; + } + after_types << "\n"; after_types << "%data_ptr = OpTypePointer " << storage_class << " " << data_type << "\n"; generator.after_types_ = after_types.str(); @@ -265,6 +350,19 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { )"; generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = GetInMainCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -276,24 +374,52 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { } } -TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) { +TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InMain) { const char* const built_in = std::get<0>(GetParam()); const char* const execution_model = std::get<1>(GetParam()); const char* const storage_class = std::get<2>(GetParam()); const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = GetInMainCodeGenerator( + SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +CodeGenerator GetInFunctionCodeGenerator(spv_target_env env, + const char* const built_in, + const char* const execution_model, + const char* const storage_class, + const char* const data_type) { + CodeGenerator generator = spvIsWebGPUEnv(env) + ? GetWebGPUShaderCodeGenerator() + : GetDefaultShaderCodeGenerator(); + generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; std::ostringstream after_types; after_types << "%built_in_type = OpTypeStruct " << data_type << "\n"; + if (InitializerRequired(env, storage_class)) { + after_types << "%built_in_null = OpConstantNull %built_in_type\n"; + } after_types << "%built_in_ptr = OpTypePointer " << storage_class << " %built_in_type\n"; - after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class - << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + if (InitializerRequired(env, storage_class)) { + after_types << " %built_in_null"; + } + after_types << "\n"; after_types << "%data_ptr = OpTypePointer " << storage_class << " " << data_type << "\n"; generator.after_types_ = after_types.str(); @@ -331,15 +457,35 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) { %val2 = OpFunctionCall %void %foo )"; - generator.add_at_the_end_ = R"( + std::string function_body = R"( %foo = OpFunction %void None %func %foo_entry = OpLabel %ptr = OpAccessChain %data_ptr %built_in_var %u32_0 OpReturn OpFunctionEnd )"; + + if (spvIsWebGPUEnv(env)) { + generator.after_types_ += function_body; + } else { + generator.add_at_the_end_ = function_body; + } + generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = GetInFunctionCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -351,23 +497,51 @@ OpFunctionEnd } } -TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { +TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InFunction) { const char* const built_in = std::get<0>(GetParam()); const char* const execution_model = std::get<1>(GetParam()); const char* const storage_class = std::get<2>(GetParam()); const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = GetInFunctionCodeGenerator( + SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +CodeGenerator GetVariableCodeGenerator(spv_target_env env, + const char* const built_in, + const char* const execution_model, + const char* const storage_class, + const char* const data_type) { + CodeGenerator generator = spvIsWebGPUEnv(env) + ? GetWebGPUShaderCodeGenerator() + : GetDefaultShaderCodeGenerator(); + generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; std::ostringstream after_types; + if (InitializerRequired(env, storage_class)) { + after_types << "%built_in_null = OpConstantNull " << data_type << "\n"; + } after_types << "%built_in_ptr = OpTypePointer " << storage_class << " " << data_type << "\n"; - after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class - << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + if (InitializerRequired(env, storage_class)) { + after_types << " %built_in_null"; + } + after_types << "\n"; generator.after_types_ = after_types.str(); EntryPoint entry_point; @@ -379,7 +553,7 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { } // Any kind of reference would do. entry_point.body = R"( -%val = OpBitcast %u64 %built_in_var +%val = OpBitcast %u32 %built_in_var )"; std::ostringstream execution_modes; @@ -405,6 +579,19 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = GetVariableCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -416,6 +603,27 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { } } +TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = GetVariableCodeGenerator( + SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + INSTANTIATE_TEST_CASE_P( ClipAndCullDistanceOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1023,6 +1231,21 @@ INSTANTIATE_TEST_CASE_P( "TessellationEvaluation"), Values("Output"), Values("%f32vec4"), Values(TestResult())), ); +INSTANTIATE_TEST_CASE_P( + PositionOutputSuccess, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("Position"), Values("Vertex"), Values("Output"), + Values("%f32vec4"), Values(TestResult())), ); + +INSTANTIATE_TEST_CASE_P( + PositionOutputFailure, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("Position"), Values("Fragment", "GLCompute"), + Values("Output"), Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "WebGPU spec allows BuiltIn Position to be used " + "only with the Vertex execution model."))), ); + INSTANTIATE_TEST_CASE_P( PositionInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1030,6 +1253,16 @@ INSTANTIATE_TEST_CASE_P( Values("Geometry", "TessellationControl", "TessellationEvaluation"), Values("Input"), Values("%f32vec4"), Values(TestResult())), ); +INSTANTIATE_TEST_CASE_P( + PositionInputFailure, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("Position"), Values("Vertex", "Fragment", "GLCompute"), + Values("Input"), Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "WebGPU spec allows BuiltIn Position to be only used " + "for variables with Output storage class"))), ); + INSTANTIATE_TEST_CASE_P( PositionVertexInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1061,6 +1294,15 @@ INSTANTIATE_TEST_CASE_P( "needs to be a 4-component 32-bit float vector", "is not a float vector"))), ); +INSTANTIATE_TEST_CASE_P( + PositionNotFloatVector, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("Position"), Values("Vertex"), Values("Output"), + Values("%f32arr4", "%u32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit float vector"))), ); + INSTANTIATE_TEST_CASE_P( PositionNotFloatVec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1070,6 +1312,15 @@ INSTANTIATE_TEST_CASE_P( "needs to be a 4-component 32-bit float vector", "has 3 components"))), ); +INSTANTIATE_TEST_CASE_P( + PositionNotFloatVec4, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("Position"), Values("Vertex"), Values("Output"), + Values("%f32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit float vector"))), ); + INSTANTIATE_TEST_CASE_P( PositionNotF32Vec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1549,24 +1800,32 @@ INSTANTIATE_TEST_CASE_P( "needs to be a 32-bit int scalar", "has bit width 64"))), ); -TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { - const char* const built_in = std::get<0>(GetParam()); - const char* const execution_model = std::get<1>(GetParam()); - const char* const storage_class = std::get<2>(GetParam()); - const char* const data_type = std::get<3>(GetParam()); - const TestResult& test_result = std::get<4>(GetParam()); +CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env, + const char* const built_in, + const char* const execution_model, + const char* const storage_class, + const char* const data_type) { + CodeGenerator generator = spvIsWebGPUEnv(env) + ? GetWebGPUShaderCodeGenerator() + : GetDefaultShaderCodeGenerator(); - CodeGenerator generator = GetDefaultShaderCodeGenerator(); generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; std::ostringstream after_types; after_types << "%built_in_array = OpTypeArray " << data_type << " %u32_3\n"; + if (InitializerRequired(env, storage_class)) { + after_types << "%built_in_array_null = OpConstantNull %built_in_array\n"; + } + after_types << "%built_in_ptr = OpTypePointer " << storage_class << " %built_in_array\n"; - after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class - << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + if (InitializerRequired(env, storage_class)) { + after_types << " %built_in_array_null"; + } + after_types << "\n"; generator.after_types_ = after_types.str(); EntryPoint entry_point; @@ -1575,7 +1834,7 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { entry_point.interfaces = "%built_in_var"; // Any kind of reference would do. entry_point.body = R"( -%val = OpBitcast %u64 %built_in_var +%val = OpBitcast %u32 %built_in_var )"; std::ostringstream execution_modes; @@ -1601,6 +1860,19 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = GetArrayedVariableCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -1612,6 +1884,27 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { } } +TEST_P(ValidateWebGPUCombineBuiltInArrayedVariable, Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = GetArrayedVariableCodeGenerator( + SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + INSTANTIATE_TEST_CASE_P(PointSizeArrayedF32TessControl, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("PointSize"), @@ -1652,7 +1945,15 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( PositionArrayedF32Vec4Vertex, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("Position"), Values("Vertex"), Values("Output"), - Values("%f32"), + Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit float vector", + "is not a float vector"))), ); + +INSTANTIATE_TEST_CASE_P( + PositionArrayedF32Vec4Vertex, ValidateWebGPUCombineBuiltInArrayedVariable, + Combine(Values("Position"), Values("Vertex"), Values("Output"), + Values("%f32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", "is not a float vector"))), ); diff --git a/3rdparty/spirv-tools/test/val/val_cfg_test.cpp b/3rdparty/spirv-tools/test/val/val_cfg_test.cpp index aed0a5788..fae570278 100644 --- a/3rdparty/spirv-tools/test/val/val_cfg_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_cfg_test.cpp @@ -493,13 +493,10 @@ TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) { str += "OpFunctionEnd\n"; CompileSuccessfully(str); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - MatchesRegex("Block\\(s\\) \\{11\\[%11\\]\\} are referenced but not " - "defined in function .\\[%Main\\]\n %Main = OpFunction " - "%void None %10\n")) - << str; + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("'Target Label' operands for OpBranch must " + "be the ID of an OpLabel instruction")); } TEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) { @@ -2060,6 +2057,57 @@ TEST_F(ValidateCFG, KernelWithPhiPtr) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateCFG, SwitchTargetMustBeLabel) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "foo" + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %6 = OpLabel + %7 = OpCopyObject %uint %uint_0 + OpSelectionMerge %8 None + OpSwitch %uint_0 %8 0 %7 + %8 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("'Target Label' operands for OpSwitch must " + "be IDs of an OpLabel instruction")); +} + +TEST_F(ValidateCFG, BranchTargetMustBeLabel) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "foo" + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %2 = OpLabel + %7 = OpCopyObject %uint %uint_0 + OpBranch %7 + %8 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("'Target Label' operands for OpBranch must " + "be the ID of an OpLabel instruction")); +} + /// TODO(umar): Nested CFG constructs } // namespace diff --git a/3rdparty/spirv-tools/test/val/val_data_test.cpp b/3rdparty/spirv-tools/test/val/val_data_test.cpp index 0aded92b5..d9413bc60 100644 --- a/3rdparty/spirv-tools/test/val/val_data_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_data_test.cpp @@ -934,6 +934,23 @@ TEST_F(ValidateData, webgpu_RTA_not_at_end_of_struct) { "OpTypeStruct %_runtimearr_uint %uint\n")); } +TEST_F(ValidateData, invalid_forward_reference_in_array) { + std::string str = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + %uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_arr_3_uint_1 = OpTypeArray %_arr_3_uint_1 %uint_1 +)"; + + CompileSuccessfully(str.c_str(), SPV_ENV_UNIVERSAL_1_3); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Forward reference operands in an OpTypeArray must " + "first be declared using OpTypeForwardPointer.")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_decoration_test.cpp b/3rdparty/spirv-tools/test/val/val_decoration_test.cpp index 827ebf185..1506a29a6 100644 --- a/3rdparty/spirv-tools/test/val/val_decoration_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_decoration_test.cpp @@ -3285,7 +3285,7 @@ TEST_F(ValidateDecorations, getDiagnosticString(), HasSubstr("Structure id 6 decorated as Block for variable in Uniform " "storage class must follow standard uniform buffer layout " - "rules: member 2 at offset 24 is not aligned to 16")); + "rules: member 2 at offset 152 is not aligned to 16")); } TEST_F(ValidateDecorations, @@ -3418,7 +3418,8 @@ TEST_F(ValidateDecorations, BlockUniformBufferLayoutIncorrectArrayStrideBad) { getDiagnosticString(), HasSubstr( "Structure id 6 decorated as Block for variable in Uniform storage " - "class must follow standard uniform buffer layout rules: member 4 is " + "class must follow standard uniform buffer layout rules: member 4 " + "contains " "an array with stride 49 not satisfying alignment to 16")); } @@ -5302,6 +5303,194 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); } +TEST_F(ValidateDecorations, InvalidStraddle) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpMemberDecorate %inner_struct 0 Offset 0 +OpMemberDecorate %inner_struct 1 Offset 4 +OpDecorate %outer_struct Block +OpMemberDecorate %outer_struct 0 Offset 0 +OpMemberDecorate %outer_struct 1 Offset 8 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float2 = OpTypeVector %float 2 +%inner_struct = OpTypeStruct %float %float2 +%outer_struct = OpTypeStruct %float2 %inner_struct +%ptr_ssbo_outer = OpTypePointer StorageBuffer %outer_struct +%var = OpVariable %ptr_ssbo_outer StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in " + "StorageBuffer storage class must follow relaxed " + "storage buffer layout rules: member 1 is an " + "improperly straddling vector at offset 12")); +} + +TEST_F(ValidateDecorations, DescriptorArray) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpMemberDecorate %struct 1 Offset 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%float2 = OpTypeVector %float 2 +%struct = OpTypeStruct %float %float2 +%struct_array = OpTypeArray %struct %int_2 +%ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array +%var = OpVariable %ptr_ssbo_array StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in " + "StorageBuffer storage class must follow standard " + "storage buffer layout rules: member 1 at offset 1 is " + "not aligned to 8")); +} + +TEST_F(ValidateDecorations, DescriptorRuntimeArray) { + const std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpMemberDecorate %struct 1 Offset 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%float2 = OpTypeVector %float 2 +%struct = OpTypeStruct %float %float2 +%struct_array = OpTypeRuntimeArray %struct +%ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array +%var = OpVariable %ptr_ssbo_array StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in " + "StorageBuffer storage class must follow standard " + "storage buffer layout rules: member 1 at offset 1 is " + "not aligned to 8")); +} + +TEST_F(ValidateDecorations, MultiDimensionalArray) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %array_4 ArrayStride 4 +OpDecorate %array_3 ArrayStride 48 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_3 = OpConstant %int 3 +%int_4 = OpConstant %int 4 +%array_4 = OpTypeArray %int %int_4 +%array_3 = OpTypeArray %array_4 %int_3 +%struct = OpTypeStruct %array_3 +%ptr_struct = OpTypePointer Uniform %struct +%var = OpVariable %ptr_struct Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in " + "Uniform storage class must follow standard uniform " + "buffer layout rules: member 0 contains an array with " + "stride 4 not satisfying alignment to 16")); +} + +TEST_F(ValidateDecorations, ImproperStraddleInArray) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %array ArrayStride 24 +OpMemberDecorate %inner 0 Offset 0 +OpMemberDecorate %inner 1 Offset 4 +OpMemberDecorate %inner 2 Offset 12 +OpMemberDecorate %inner 3 Offset 16 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%int2 = OpTypeVector %int 2 +%inner = OpTypeStruct %int %int2 %int %int +%array = OpTypeArray %inner %int_2 +%struct = OpTypeStruct %array +%ptr_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 4 decorated as Block for variable in " + "StorageBuffer storage class must follow relaxed " + "storage buffer layout rules: member 1 is an " + "improperly straddling vector at offset 28")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_memory_test.cpp b/3rdparty/spirv-tools/test/val/val_memory_test.cpp index 097477c31..9ebbac0cb 100644 --- a/3rdparty/spirv-tools/test/val/val_memory_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_memory_test.cpp @@ -449,12 +449,11 @@ OpFunctionEnd EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); EXPECT_THAT( getDiagnosticString(), - HasSubstr( - "OpVariable, '5[%5]', has a disallowed initializer & storage " - "class combination.\nFrom WebGPU execution environment spec:\n" - "Variable declarations that include initializers must have one of " - "the following storage classes: Output, Private, or Function\n" - " %5 = OpVariable %_ptr_Uniform_float Uniform %float_1\n")); + HasSubstr("OpVariable, '5[%5]', has a disallowed initializer & " + "storage class combination.\nFrom WebGPU spec:\nVariable " + "declarations that include initializers must have one of the " + "following storage classes: Output, Private, or Function\n %5 " + "= OpVariable %_ptr_Uniform_float Uniform %float_1\n")); } TEST_F(ValidateMemory, WebGPUOutputStorageClassWithoutInitializerBad) { @@ -628,12 +627,11 @@ OpFunctionEnd EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); EXPECT_THAT( getDiagnosticString(), - HasSubstr( - "OpVariable, '5[%5]', has a disallowed initializer & storage " - "class combination.\nFrom Vulkan spec, Appendix A:\n" - "Variable declarations that include initializers must have one of " - "the following storage classes: Output, Private, or Function\n " - "%5 = OpVariable %_ptr_Input_float Input %float_1\n")); + HasSubstr("OpVariable, '5[%5]', has a disallowed initializer & " + "storage class combination.\nFrom Vulkan spec:\nVariable " + "declarations that include initializers must have one of the " + "following storage classes: Output, Private, or Function\n %5 " + "= OpVariable %_ptr_Input_float Input %float_1\n")); } TEST_F(ValidateMemory, ArrayLenCorrectResultType) { @@ -2179,7 +2177,7 @@ OpFunctionEnd getDiagnosticString(), HasSubstr( "OpTypeRuntimeArray Element Type '3[%_runtimearr_2]' is not " - "valid in Vulkan environment.\n %_runtimearr__runtimearr_2 = " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_2 = " "OpTypeRuntimeArray %_runtimearr_2\n")); } @@ -2210,7 +2208,7 @@ OpFunctionEnd getDiagnosticString(), HasSubstr( "OpTypeRuntimeArray Element Type '3[%_runtimearr_2]' is not " - "valid in WebGPU environment.\n %_runtimearr__runtimearr_2 = " + "valid in WebGPU environments.\n %_runtimearr__runtimearr_2 = " "OpTypeRuntimeArray %_runtimearr_2\n")); } @@ -2242,7 +2240,7 @@ OpFunctionEnd getDiagnosticString(), HasSubstr( "OpTypeRuntimeArray Element Type '4[%_runtimearr_uint]' is not " - "valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = " "OpTypeRuntimeArray %_runtimearr_uint\n")); } @@ -2304,7 +2302,7 @@ OpFunctionEnd getDiagnosticString(), HasSubstr( "OpTypeRuntimeArray Element Type '5[%_runtimearr_uint]' is not " - "valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = " "OpTypeRuntimeArray %_runtimearr_uint\n")); } @@ -2340,7 +2338,7 @@ OpFunctionEnd getDiagnosticString(), HasSubstr( "OpTypeRuntimeArray Element Type '5[%_runtimearr_uint]' is not " - "valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = " "OpTypeRuntimeArray %_runtimearr_uint\n")); } @@ -2370,7 +2368,7 @@ OpFunctionEnd EXPECT_THAT( getDiagnosticString(), HasSubstr("OpTypeArray Element Type '5[%_runtimearr_4]' is not " - "valid in Vulkan environment.\n %_arr__runtimearr_4_uint_1 = " + "valid in Vulkan environments.\n %_arr__runtimearr_4_uint_1 = " "OpTypeArray %_runtimearr_4 %uint_1\n")); } @@ -2402,7 +2400,7 @@ OpFunctionEnd EXPECT_THAT( getDiagnosticString(), HasSubstr("OpTypeArray Element Type '5[%_runtimearr_4]' is not " - "valid in WebGPU environment.\n %_arr__runtimearr_4_uint_1 = " + "valid in WebGPU environments.\n %_arr__runtimearr_4_uint_1 = " "OpTypeArray %_runtimearr_4 %uint_1\n")); } @@ -2436,7 +2434,7 @@ OpFunctionEnd getDiagnosticString(), HasSubstr( "OpTypeRuntimeArray Element Type '6[%_runtimearr_uint]' is not " - "valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = " "OpTypeRuntimeArray %_runtimearr_uint\n")); } @@ -2468,9 +2466,10 @@ OpFunctionEnd EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpTypeArray Element Type '6[%_runtimearr_uint]' is not " - "valid in Vulkan environment.\n %_arr__runtimearr_uint_uint_1 " - "= OpTypeArray %_runtimearr_uint %uint_1\n")); + HasSubstr( + "OpTypeArray Element Type '6[%_runtimearr_uint]' is not " + "valid in Vulkan environments.\n %_arr__runtimearr_uint_uint_1 " + "= OpTypeArray %_runtimearr_uint %uint_1\n")); } TEST_F(ValidateMemory, @@ -2504,9 +2503,10 @@ OpFunctionEnd EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpTypeArray Element Type '6[%_runtimearr_uint]' is not " - "valid in Vulkan environment.\n %_arr__runtimearr_uint_uint_1 " - "= OpTypeArray %_runtimearr_uint %uint_1\n")); + HasSubstr( + "OpTypeArray Element Type '6[%_runtimearr_uint]' is not " + "valid in Vulkan environments.\n %_arr__runtimearr_uint_uint_1 " + "= OpTypeArray %_runtimearr_uint %uint_1\n")); } TEST_F(ValidateMemory, VulkanRTAStructInsideRTAWithRuntimeDescriptorArrayGood) { diff --git a/3rdparty/spirv-tools/tools/reduce/reduce.cpp b/3rdparty/spirv-tools/tools/reduce/reduce.cpp index 65325f745..4d497688c 100644 --- a/3rdparty/spirv-tools/tools/reduce/reduce.cpp +++ b/3rdparty/spirv-tools/tools/reduce/reduce.cpp @@ -20,13 +20,13 @@ #include "source/opt/build_module.h" #include "source/opt/ir_context.h" #include "source/opt/log.h" -#include "source/reduce/operand_to_const_reduction_pass.h" -#include "source/reduce/operand_to_dominating_id_reduction_pass.h" -#include "source/reduce/operand_to_undef_reduction_pass.h" +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" +#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h" +#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h" #include "source/reduce/reducer.h" -#include "source/reduce/remove_opname_instruction_reduction_pass.h" -#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h" -#include "source/reduce/structured_loop_to_selection_reduction_pass.h" +#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h" +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" +#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h" #include "source/spirv_reducer_options.h" #include "source/util/make_unique.h" #include "source/util/string_utils.h" @@ -77,7 +77,26 @@ USAGE: %s [options] The SPIR-V binary is read from . Whether a binary is interesting is determined by , which -is typically a script. +should be the path to a script. + + * The script must be executable. + + * The script should take the path to a SPIR-V binary file (.spv) as its single + argument, and exit with code 0 if and only if the binary file is + interesting. + + * Example: an interestingness test for reducing a SPIR-V binary file that + causes tool "foo" to exit with error code 1 and print "Fatal error: bar" to + standard error should: + - invoke "foo" on the binary passed as the script argument; + - capture the return code and standard error from "bar"; + - exit with code 0 if and only if the return code of "foo" was 1 and the + standard error from "bar" contained "Fatal error: bar". + + * The reducer does not place a time limit on how long the interestingness test + takes to run, so it is advisable to use per-command timeouts inside the + script when invoking SPIR-V-processing tools (such as "foo" in the above + example). NOTE: The reducer is a work in progress. @@ -85,8 +104,8 @@ Options (in lexicographical order): -h, --help Print this help. --step-limit - 32-bit unsigned integer specifying maximum number of - steps the reducer will take before giving up. + 32-bit unsigned integer specifying maximum number of steps the + reducer will take before giving up. --version Display reducer version information. )", @@ -207,18 +226,20 @@ int main(int argc, const char** argv) { }); reducer.AddReductionPass( - spvtools::MakeUnique(target_env)); + spvtools::MakeUnique< + RemoveOpNameInstructionReductionOpportunityFinder>()); reducer.AddReductionPass( - spvtools::MakeUnique(target_env)); + spvtools::MakeUnique()); reducer.AddReductionPass( - spvtools::MakeUnique(target_env)); + spvtools::MakeUnique()); reducer.AddReductionPass( - spvtools::MakeUnique(target_env)); + spvtools::MakeUnique()); reducer.AddReductionPass( - spvtools::MakeUnique( - target_env)); + spvtools::MakeUnique< + RemoveUnreferencedInstructionReductionOpportunityFinder>()); reducer.AddReductionPass( - spvtools::MakeUnique(target_env)); + spvtools::MakeUnique< + StructuredLoopToSelectionReductionOpportunityFinder>()); reducer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); diff --git a/scripts/shaderc.lua b/scripts/shaderc.lua index 043bc5c81..dd354377c 100644 --- a/scripts/shaderc.lua +++ b/scripts/shaderc.lua @@ -26,6 +26,8 @@ project "spirv-opt" files { path.join(SPIRV_TOOLS, "source/opt/**.cpp"), path.join(SPIRV_TOOLS, "source/opt/**.h"), + path.join(SPIRV_TOOLS, "source/reduce/**.cpp"), + path.join(SPIRV_TOOLS, "source/reduce/**.h"), -- libspirv path.join(SPIRV_TOOLS, "source/assembly_grammar.cpp"),