diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index cde55e3a9..0947e22df 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-41-ga8ae579f" +"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-47-g59983a60" diff --git a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc index 4df39a324..5ea67bda4 100644 --- a/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc +++ b/3rdparty/spirv-tools/include/generated/enum_string_mapping.inc @@ -38,6 +38,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_GOOGLE_decorate_string"; case Extension::kSPV_GOOGLE_hlsl_functionality1: return "SPV_GOOGLE_hlsl_functionality1"; + case Extension::kSPV_GOOGLE_user_type: + return "SPV_GOOGLE_user_type"; case Extension::kSPV_INTEL_device_side_avc_motion_estimation: return "SPV_INTEL_device_side_avc_motion_estimation"; case Extension::kSPV_INTEL_media_block_io: @@ -111,8 +113,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_fragment_shader_interlock", "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_device_side_avc_motion_estimation", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "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_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" }; - static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, 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_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique }; + static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "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_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" }; + static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, 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_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique }; const auto b = std::begin(known_ext_strs); const auto e = std::end(known_ext_strs); const auto found = std::equal_range( @@ -330,6 +332,16 @@ const char* CapabilityToString(SpvCapability capability) { return "FragmentFullyCoveredEXT"; case SpvCapabilityMeshShadingNV: return "MeshShadingNV"; + case SpvCapabilityImageFootprintNV: + return "ImageFootprintNV"; + case SpvCapabilityFragmentBarycentricNV: + return "FragmentBarycentricNV"; + case SpvCapabilityComputeDerivativeGroupQuadsNV: + return "ComputeDerivativeGroupQuadsNV"; + case SpvCapabilityFragmentDensityEXT: + return "FragmentDensityEXT"; + case SpvCapabilityGroupNonUniformPartitionedNV: + return "GroupNonUniformPartitionedNV"; case SpvCapabilityShaderNonUniformEXT: return "ShaderNonUniformEXT"; case SpvCapabilityRuntimeDescriptorArrayEXT: @@ -356,6 +368,24 @@ const char* CapabilityToString(SpvCapability capability) { return "StorageTexelBufferArrayNonUniformIndexingEXT"; case SpvCapabilityRayTracingNV: return "RayTracingNV"; + case SpvCapabilityVulkanMemoryModelKHR: + return "VulkanMemoryModelKHR"; + case SpvCapabilityVulkanMemoryModelDeviceScopeKHR: + return "VulkanMemoryModelDeviceScopeKHR"; + case SpvCapabilityPhysicalStorageBufferAddressesEXT: + return "PhysicalStorageBufferAddressesEXT"; + case SpvCapabilityComputeDerivativeGroupLinearNV: + return "ComputeDerivativeGroupLinearNV"; + case SpvCapabilityCooperativeMatrixNV: + return "CooperativeMatrixNV"; + case SpvCapabilityFragmentShaderSampleInterlockEXT: + return "FragmentShaderSampleInterlockEXT"; + case SpvCapabilityFragmentShaderShadingRateInterlockEXT: + return "FragmentShaderShadingRateInterlockEXT"; + case SpvCapabilityShaderSMBuiltinsNV: + return "ShaderSMBuiltinsNV"; + case SpvCapabilityFragmentShaderPixelInterlockEXT: + return "FragmentShaderPixelInterlockEXT"; case SpvCapabilitySubgroupShuffleINTEL: return "SubgroupShuffleINTEL"; case SpvCapabilitySubgroupBufferBlockIOINTEL: @@ -372,34 +402,6 @@ const char* CapabilityToString(SpvCapability capability) { return "SubgroupAvcMotionEstimationIntraINTEL"; case SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL: return "SubgroupAvcMotionEstimationChromaINTEL"; - case SpvCapabilityGroupNonUniformPartitionedNV: - return "GroupNonUniformPartitionedNV"; - case SpvCapabilityVulkanMemoryModelKHR: - return "VulkanMemoryModelKHR"; - case SpvCapabilityVulkanMemoryModelDeviceScopeKHR: - return "VulkanMemoryModelDeviceScopeKHR"; - case SpvCapabilityImageFootprintNV: - return "ImageFootprintNV"; - case SpvCapabilityFragmentBarycentricNV: - return "FragmentBarycentricNV"; - case SpvCapabilityComputeDerivativeGroupQuadsNV: - return "ComputeDerivativeGroupQuadsNV"; - case SpvCapabilityComputeDerivativeGroupLinearNV: - return "ComputeDerivativeGroupLinearNV"; - case SpvCapabilityFragmentDensityEXT: - return "FragmentDensityEXT"; - case SpvCapabilityPhysicalStorageBufferAddressesEXT: - return "PhysicalStorageBufferAddressesEXT"; - case SpvCapabilityCooperativeMatrixNV: - return "CooperativeMatrixNV"; - case SpvCapabilityFragmentShaderSampleInterlockEXT: - return "FragmentShaderSampleInterlockEXT"; - case SpvCapabilityFragmentShaderShadingRateInterlockEXT: - return "FragmentShaderShadingRateInterlockEXT"; - case SpvCapabilityFragmentShaderPixelInterlockEXT: - return "FragmentShaderPixelInterlockEXT"; - case SpvCapabilityShaderSMBuiltinsNV: - return "ShaderSMBuiltinsNV"; 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 9ba66b0ee..d5780c9e0 100644 --- a/3rdparty/spirv-tools/include/generated/extension_enum.inc +++ b/3rdparty/spirv-tools/include/generated/extension_enum.inc @@ -17,6 +17,7 @@ kSPV_EXT_shader_stencil_export, kSPV_EXT_shader_viewport_index_layer, kSPV_GOOGLE_decorate_string, kSPV_GOOGLE_hlsl_functionality1, +kSPV_GOOGLE_user_type, kSPV_INTEL_device_side_avc_motion_estimation, kSPV_INTEL_media_block_io, kSPV_INTEL_shader_integer_functions2, diff --git a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc index 3608e8d47..ff5962cc9 100644 --- a/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc @@ -99,6 +99,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_stencil_expo 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_EXT_shader_viewport_index_layerSPV_NV_viewport_array2[] = {spvtools::Extension::kSPV_EXT_shader_viewport_index_layer, spvtools::Extension::kSPV_NV_viewport_array2}; static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1}; +static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_user_type[] = {spvtools::Extension::kSPV_GOOGLE_user_type}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_device_side_avc_motion_estimation[] = {spvtools::Extension::kSPV_INTEL_device_side_avc_motion_estimation}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_media_block_io[] = {spvtools::Extension::kSPV_INTEL_media_block_io}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_shader_integer_functions2[] = {spvtools::Extension::kSPV_INTEL_shader_integer_functions2}; @@ -145,10 +146,10 @@ static const spv_operand_desc_t pygen_variable_ImageOperandsEntries[] = { {"ConstOffsets", 0x0020, 1, pygen_variable_caps_ImageGatherExtended, 0, nullptr, {SPV_OPERAND_TYPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Sample", 0x0040, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"MinLod", 0x0080, 1, pygen_variable_caps_MinLod, 0, nullptr, {SPV_OPERAND_TYPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"MakeTexelAvailableKHR", 0x0100, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"MakeTexelVisibleKHR", 0x0200, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"NonPrivateTexelKHR", 0x0400, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"VolatileTexelKHR", 0x0800, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, + {"MakeTexelAvailableKHR", 0x0100, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, 0xffffffffu, 0xffffffffu}, + {"MakeTexelVisibleKHR", 0x0200, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, 0xffffffffu, 0xffffffffu}, + {"NonPrivateTexelKHR", 0x0400, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"VolatileTexelKHR", 0x0800, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, {"SignExtend", 0x1000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu}, {"ZeroExtend", 0x2000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu} }; @@ -202,9 +203,10 @@ static const spv_operand_desc_t pygen_variable_MemorySemanticsEntries[] = { {"CrossWorkgroupMemory", 0x0200, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"AtomicCounterMemory", 0x0400, 1, pygen_variable_caps_AtomicStorage, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"ImageMemory", 0x0800, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"OutputMemoryKHR", 0x1000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"MakeAvailableKHR", 0x2000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"MakeVisibleKHR", 0x4000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"OutputMemoryKHR", 0x1000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"MakeAvailableKHR", 0x2000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"MakeVisibleKHR", 0x4000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"Volatile", 0x8000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_MemoryAccessEntries[] = { @@ -212,9 +214,9 @@ static const spv_operand_desc_t pygen_variable_MemoryAccessEntries[] = { {"Volatile", 0x0001, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Aligned", 0x0002, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Nontemporal", 0x0004, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"MakePointerAvailableKHR", 0x0008, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"MakePointerVisibleKHR", 0x0010, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"NonPrivatePointerKHR", 0x0020, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"MakePointerAvailableKHR", 0x0008, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, 0xffffffffu, 0xffffffffu}, + {"MakePointerVisibleKHR", 0x0010, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, 0xffffffffu, 0xffffffffu}, + {"NonPrivatePointerKHR", 0x0020, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_KernelProfilingInfoEntries[] = { @@ -239,28 +241,28 @@ static const spv_operand_desc_t pygen_variable_ExecutionModelEntries[] = { {"Fragment", 4, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"GLCompute", 5, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Kernel", 6, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"TaskNV", 5267, 1, pygen_variable_caps_MeshShadingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"MeshNV", 5268, 1, pygen_variable_caps_MeshShadingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"RayGenerationNV", 5313, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"IntersectionNV", 5314, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"AnyHitNV", 5315, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"ClosestHitNV", 5316, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"MissNV", 5317, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"CallableNV", 5318, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"TaskNV", 5267, 1, pygen_variable_caps_MeshShadingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"MeshNV", 5268, 1, pygen_variable_caps_MeshShadingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"RayGenerationNV", 5313, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"IntersectionNV", 5314, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"AnyHitNV", 5315, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"ClosestHitNV", 5316, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"MissNV", 5317, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}, + {"CallableNV", 5318, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_AddressingModelEntries[] = { {"Logical", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Physical32", 1, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Physical64", 2, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"PhysicalStorageBuffer64EXT", 5348, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"PhysicalStorageBuffer64EXT", 5348, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_MemoryModelEntries[] = { {"Simple", 0, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"GLSL450", 1, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"OpenCL", 2, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"VulkanKHR", 3, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"VulkanKHR", 3, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = { @@ -336,13 +338,13 @@ static const spv_operand_desc_t pygen_variable_StorageClassEntries[] = { {"AtomicCounter", 10, 1, pygen_variable_caps_AtomicStorage, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Image", 11, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"StorageBuffer", 12, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_KHR_storage_buffer_storage_classSPV_KHR_variable_pointers, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu}, - {"CallableDataNV", 5328, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"IncomingCallableDataNV", 5329, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"RayPayloadNV", 5338, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"HitAttributeNV", 5339, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"IncomingRayPayloadNV", 5342, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"ShaderRecordBufferNV", 5343, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"PhysicalStorageBufferEXT", 5349, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"CallableDataNV", 5328, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"IncomingCallableDataNV", 5329, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"RayPayloadNV", 5338, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"HitAttributeNV", 5339, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"IncomingRayPayloadNV", 5342, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"ShaderRecordBufferNV", 5343, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"PhysicalStorageBufferEXT", 5349, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_DimEntries[] = { @@ -548,7 +550,8 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = { {"CounterBuffer", 5634, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_ID}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu}, {"HlslCounterBufferGOOGLE", 5634, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_ID}, 0xffffffffu, 0xffffffffu}, {"UserSemantic", 5635, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_LITERAL_STRING}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu}, - {"HlslSemanticGOOGLE", 5635, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_LITERAL_STRING}, 0xffffffffu, 0xffffffffu} + {"HlslSemanticGOOGLE", 5635, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_LITERAL_STRING}, 0xffffffffu, 0xffffffffu}, + {"UserTypeGOOGLE", 5636, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_user_type, {SPV_OPERAND_TYPE_LITERAL_STRING}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = { @@ -636,24 +639,24 @@ static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = { {"FragmentSizeNV", 5292, 2, pygen_variable_caps_ShadingRateNVFragmentDensityEXT, 2, pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate, {}, 0xffffffffu, 0xffffffffu}, {"FragInvocationCountEXT", 5293, 2, pygen_variable_caps_FragmentDensityEXTShadingRateNV, 2, pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate, {}, 0xffffffffu, 0xffffffffu}, {"InvocationsPerPixelNV", 5293, 2, pygen_variable_caps_ShadingRateNVFragmentDensityEXT, 2, pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate, {}, 0xffffffffu, 0xffffffffu}, - {"LaunchIdNV", 5319, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"LaunchSizeNV", 5320, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"WorldRayOriginNV", 5321, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"WorldRayDirectionNV", 5322, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"ObjectRayOriginNV", 5323, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"ObjectRayDirectionNV", 5324, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"RayTminNV", 5325, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"RayTmaxNV", 5326, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"InstanceCustomIndexNV", 5327, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"ObjectToWorldNV", 5330, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"WorldToObjectNV", 5331, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"HitTNV", 5332, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"HitKindNV", 5333, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"IncomingRayFlagsNV", 5351, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"WarpsPerSMNV", 5374, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"SMCountNV", 5375, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"WarpIDNV", 5376, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"SMIDNV", 5377, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"LaunchIdNV", 5319, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"LaunchSizeNV", 5320, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"WorldRayOriginNV", 5321, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"WorldRayDirectionNV", 5322, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"ObjectRayOriginNV", 5323, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"ObjectRayDirectionNV", 5324, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"RayTminNV", 5325, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"RayTmaxNV", 5326, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"InstanceCustomIndexNV", 5327, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"ObjectToWorldNV", 5330, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"WorldToObjectNV", 5331, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"HitTNV", 5332, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"HitKindNV", 5333, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"IncomingRayFlagsNV", 5351, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, + {"WarpsPerSMNV", 5374, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu}, + {"SMCountNV", 5375, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu}, + {"WarpIDNV", 5376, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu}, + {"SMIDNV", 5377, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_ScopeEntries[] = { @@ -662,7 +665,7 @@ static const spv_operand_desc_t pygen_variable_ScopeEntries[] = { {"Workgroup", 2, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Subgroup", 3, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"Invocation", 4, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, - {"QueueFamilyKHR", 5, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu} + {"QueueFamilyKHR", 5, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_GroupOperationEntries[] = { diff --git a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt index c1c0c1f82..9121a5396 100644 --- a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt @@ -30,8 +30,8 @@ if(SPIRV_BUILD_FUZZER) fuzzer.h fuzzer_context.h fuzzer_pass.h - fuzzer_pass_add_useful_constructs.h fuzzer_pass_add_dead_breaks.h + fuzzer_pass_add_useful_constructs.h fuzzer_pass_permute_blocks.h fuzzer_pass_split_blocks.h fuzzer_util.h @@ -39,6 +39,7 @@ if(SPIRV_BUILD_FUZZER) protobufs/spirvfuzz_protobufs.h pseudo_random_generator.h random_generator.h + replayer.h transformation_add_constant_boolean.h transformation_add_constant_scalar.h transformation_add_dead_break.h @@ -48,6 +49,7 @@ if(SPIRV_BUILD_FUZZER) transformation_move_block_down.h transformation_replace_boolean_constant_with_constant_binary.h transformation_split_block.h + uniform_buffer_element_descriptor.h ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h fact_manager.cpp @@ -62,6 +64,7 @@ if(SPIRV_BUILD_FUZZER) id_use_descriptor.cpp pseudo_random_generator.cpp random_generator.cpp + replayer.cpp transformation_add_constant_boolean.cpp transformation_add_constant_scalar.cpp transformation_add_dead_break.cpp @@ -71,6 +74,7 @@ if(SPIRV_BUILD_FUZZER) transformation_move_block_down.cpp transformation_replace_boolean_constant_with_constant_binary.cpp transformation_split_block.cpp + uniform_buffer_element_descriptor.cpp ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc ) diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp index 1c1928789..37169415b 100644 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp @@ -12,15 +12,242 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include - #include "source/fuzz/fact_manager.h" + +#include "source/fuzz/uniform_buffer_element_descriptor.h" #include "source/opt/ir_context.h" namespace spvtools { namespace fuzz { -FactManager::FactManager() = default; +// The purpose of this struct is to group the fields and data used to represent +// facts about uniform constants. +struct FactManager::ConstantUniformFacts { + // See method in FactManager which delegates to this method. + bool AddFact(const protobufs::FactConstantUniform& fact, + opt::IRContext* context); + + // See method in FactManager which delegates to this method. + std::vector GetConstantsAvailableFromUniformsForType( + opt::IRContext* ir_context, uint32_t type_id) const; + + // See method in FactManager which delegates to this method. + const std::vector + GetUniformDescriptorsForConstant(opt::IRContext* ir_context, + uint32_t constant_id) const; + + // See method in FactManager which delegates to this method. + uint32_t GetConstantFromUniformDescriptor( + opt::IRContext* context, + const protobufs::UniformBufferElementDescriptor& uniform_descriptor) + const; + + // See method in FactManager which delegates to this method. + std::vector GetTypesForWhichUniformValuesAreKnown() const; + + // Returns true if and only if the words associated with + // |constant_instruction| exactly match the words for the constant associated + // with |constant_uniform_fact|. + bool DataMatches( + const opt::Instruction& constant_instruction, + const protobufs::FactConstantUniform& constant_uniform_fact) const; + + // Yields the constant words associated with |constant_uniform_fact|. + std::vector GetConstantWords( + const protobufs::FactConstantUniform& constant_uniform_fact) const; + + // Yields the id of a constant of type |type_id| whose data matches the + // constant data in |constant_uniform_fact|, or 0 if no such constant is + // declared. + uint32_t GetConstantId( + opt::IRContext* context, + const protobufs::FactConstantUniform& constant_uniform_fact, + uint32_t type_id) const; + + std::vector> + facts_and_type_ids; +}; + +uint32_t FactManager::ConstantUniformFacts::GetConstantId( + opt::IRContext* context, + const protobufs::FactConstantUniform& constant_uniform_fact, + uint32_t type_id) const { + auto type = context->get_type_mgr()->GetType(type_id); + assert(type != nullptr && "Unknown type id."); + auto constant = context->get_constant_mgr()->GetConstant( + type, GetConstantWords(constant_uniform_fact)); + return context->get_constant_mgr()->FindDeclaredConstant(constant, type_id); +} + +std::vector FactManager::ConstantUniformFacts::GetConstantWords( + const protobufs::FactConstantUniform& constant_uniform_fact) const { + std::vector result; + for (auto constant_word : constant_uniform_fact.constant_word()) { + result.push_back(constant_word); + } + return result; +} + +bool FactManager::ConstantUniformFacts::DataMatches( + const opt::Instruction& constant_instruction, + const protobufs::FactConstantUniform& constant_uniform_fact) const { + assert(constant_instruction.opcode() == SpvOpConstant); + std::vector data_in_constant; + for (uint32_t i = 0; i < constant_instruction.NumInOperands(); i++) { + data_in_constant.push_back(constant_instruction.GetSingleWordInOperand(i)); + } + return data_in_constant == GetConstantWords(constant_uniform_fact); +} + +std::vector +FactManager::ConstantUniformFacts::GetConstantsAvailableFromUniformsForType( + opt::IRContext* ir_context, uint32_t type_id) const { + std::vector result; + std::set already_seen; + for (auto& fact_and_type_id : facts_and_type_ids) { + if (fact_and_type_id.second != type_id) { + continue; + } + if (auto constant_id = + GetConstantId(ir_context, fact_and_type_id.first, type_id)) { + if (already_seen.find(constant_id) == already_seen.end()) { + result.push_back(constant_id); + already_seen.insert(constant_id); + } + } + } + return result; +} + +const std::vector +FactManager::ConstantUniformFacts::GetUniformDescriptorsForConstant( + opt::IRContext* ir_context, uint32_t constant_id) const { + std::vector result; + auto constant_inst = ir_context->get_def_use_mgr()->GetDef(constant_id); + assert(constant_inst->opcode() == SpvOpConstant && + "The given id must be that of a constant"); + auto type_id = constant_inst->type_id(); + for (auto& fact_and_type_id : facts_and_type_ids) { + if (fact_and_type_id.second != type_id) { + continue; + } + if (DataMatches(*constant_inst, fact_and_type_id.first)) { + result.emplace_back( + fact_and_type_id.first.uniform_buffer_element_descriptor()); + } + } + return result; +} + +uint32_t FactManager::ConstantUniformFacts::GetConstantFromUniformDescriptor( + opt::IRContext* context, + const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const { + // Consider each fact. + for (auto& fact_and_type : facts_and_type_ids) { + // Check whether the uniform descriptor associated with the fact matches + // |uniform_descriptor|. + if (UniformBufferElementDescriptorEquals()( + &uniform_descriptor, + &fact_and_type.first.uniform_buffer_element_descriptor())) { + return GetConstantId(context, fact_and_type.first, fact_and_type.second); + } + } + // No fact associated with the given uniform descriptor was found. + return 0; +} + +std::vector +FactManager::ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown() + const { + std::vector result; + for (auto& fact_and_type : facts_and_type_ids) { + if (std::find(result.begin(), result.end(), fact_and_type.second) == + result.end()) { + result.push_back(fact_and_type.second); + } + } + return result; +} + +bool FactManager::ConstantUniformFacts::AddFact( + const protobufs::FactConstantUniform& fact, opt::IRContext* context) { + auto should_be_uniform_variable = context->get_def_use_mgr()->GetDef( + fact.uniform_buffer_element_descriptor().uniform_variable_id()); + if (!should_be_uniform_variable) { + return false; + } + if (SpvOpVariable != should_be_uniform_variable->opcode()) { + return false; + } + if (SpvStorageClassUniform != + should_be_uniform_variable->GetSingleWordInOperand(0)) { + return false; + } + auto should_be_uniform_pointer_type = + context->get_type_mgr()->GetType(should_be_uniform_variable->type_id()); + if (!should_be_uniform_pointer_type->AsPointer()) { + return false; + } + if (should_be_uniform_pointer_type->AsPointer()->storage_class() != + SpvStorageClassUniform) { + return false; + } + auto should_be_uniform_pointer_instruction = + context->get_def_use_mgr()->GetDef(should_be_uniform_variable->type_id()); + auto element_type = + should_be_uniform_pointer_instruction->GetSingleWordInOperand(1); + + for (auto index : fact.uniform_buffer_element_descriptor().index()) { + auto should_be_composite_type = + context->get_def_use_mgr()->GetDef(element_type); + if (SpvOpTypeStruct == should_be_composite_type->opcode()) { + if (index >= should_be_composite_type->NumInOperands()) { + return false; + } + element_type = should_be_composite_type->GetSingleWordInOperand(index); + } else if (SpvOpTypeArray == should_be_composite_type->opcode()) { + auto array_length_constant = + context->get_constant_mgr() + ->GetConstantFromInst(context->get_def_use_mgr()->GetDef( + should_be_composite_type->GetSingleWordInOperand(1))) + ->AsIntConstant(); + if (array_length_constant->words().size() != 1) { + return false; + } + auto array_length = array_length_constant->GetU32(); + if (index >= array_length) { + return false; + } + element_type = should_be_composite_type->GetSingleWordInOperand(0); + } else if (SpvOpTypeVector == should_be_composite_type->opcode()) { + auto vector_length = should_be_composite_type->GetSingleWordInOperand(1); + if (index >= vector_length) { + return false; + } + element_type = should_be_composite_type->GetSingleWordInOperand(0); + } else { + return false; + } + } + auto final_element_type = context->get_type_mgr()->GetType(element_type); + if (!(final_element_type->AsFloat() || final_element_type->AsInteger())) { + return false; + } + auto width = final_element_type->AsFloat() + ? final_element_type->AsFloat()->width() + : final_element_type->AsInteger()->width(); + auto required_words = (width + 32 - 1) / 32; + if (static_cast(fact.constant_word().size()) != required_words) { + return false; + } + facts_and_type_ids.emplace_back( + std::pair(fact, element_type)); + return true; +} + +FactManager::FactManager() { + uniform_constant_facts_ = MakeUnique(); +} FactManager::~FactManager() = default; @@ -36,11 +263,46 @@ bool FactManager::AddFacts(const protobufs::FactSequence& initial_facts, return true; } -bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact&, - spvtools::opt::IRContext*) { - assert(0 && "No facts are yet supported."); +bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact& fact, + spvtools::opt::IRContext* context) { + assert(fact.fact_case() == protobufs::Fact::kConstantUniformFact && + "Right now this is the only fact."); + if (!uniform_constant_facts_->AddFact(fact.constant_uniform_fact(), + context)) { + return false; + } return true; } +std::vector FactManager::GetConstantsAvailableFromUniformsForType( + opt::IRContext* ir_context, uint32_t type_id) const { + return uniform_constant_facts_->GetConstantsAvailableFromUniformsForType( + ir_context, type_id); +} + +const std::vector +FactManager::GetUniformDescriptorsForConstant(opt::IRContext* ir_context, + uint32_t constant_id) const { + return uniform_constant_facts_->GetUniformDescriptorsForConstant(ir_context, + constant_id); +} + +uint32_t FactManager::GetConstantFromUniformDescriptor( + opt::IRContext* context, + const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const { + return uniform_constant_facts_->GetConstantFromUniformDescriptor( + context, uniform_descriptor); +} + +std::vector FactManager::GetTypesForWhichUniformValuesAreKnown() + const { + return uniform_constant_facts_->GetTypesForWhichUniformValuesAreKnown(); +} + +const std::vector>& +FactManager::GetConstantUniformFactsAndTypes() const { + return uniform_constant_facts_->facts_and_type_ids; +} + } // namespace fuzz } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager.h b/3rdparty/spirv-tools/source/fuzz/fact_manager.h index 49b6d6dc8..2eee9ab8e 100644 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager.h +++ b/3rdparty/spirv-tools/source/fuzz/fact_manager.h @@ -15,7 +15,9 @@ #ifndef SOURCE_FUZZ_FACT_MANAGER_H_ #define SOURCE_FUZZ_FACT_MANAGER_H_ +#include #include +#include #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/opt/constants.h" @@ -45,6 +47,60 @@ class FactManager { // Adds |fact| to the fact manager, checking it for validity with respect to // |context|. Returns true if and only if the fact is valid. bool AddFact(const protobufs::Fact& fact, opt::IRContext* context); + + // The fact manager will ultimately be responsible for managing a few distinct + // categories of facts. In principle there could be different fact managers + // for each kind of fact, but in practice providing one 'go to' place for + // facts will be convenient. To keep some separation, the public methods of + // the fact manager should be grouped according to the kind of fact to which + // they relate. At present we only have one kind of fact: facts about + // uniform variables. + + //============================== + // Querying facts about uniform constants + + // Provides the distinct type ids for which at least one "constant == + // uniform element" fact is known. + std::vector GetTypesForWhichUniformValuesAreKnown() const; + + // Provides distinct constant ids with type |type_id| for which at least one + // "constant == uniform element" fact is known. If multiple identically- + // valued constants are relevant, only one will appear in the sequence. + std::vector GetConstantsAvailableFromUniformsForType( + opt::IRContext* ir_context, uint32_t type_id) const; + + // Provides details of all uniform elements that are known to be equal to the + // constant associated with |constant_id| in |ir_context|. + const std::vector + GetUniformDescriptorsForConstant(opt::IRContext* ir_context, + uint32_t constant_id) const; + + // Returns the id of a constant whose value is known to match that of + // |uniform_descriptor|, and whose type matches the type of the uniform + // element. If multiple such constant is exist, the one that is returned + // is arbitrary. Returns 0 if no such constant id exists. + uint32_t GetConstantFromUniformDescriptor( + opt::IRContext* context, + const protobufs::UniformBufferElementDescriptor& uniform_descriptor) + const; + + // Returns all "constant == uniform element" facts known to the fact + // manager, pairing each fact with id of the type that is associated with + // both the constant and the uniform element. + const std::vector>& + GetConstantUniformFactsAndTypes() const; + + // End of uniform constant facts + //============================== + + private: + // For each distinct kind of fact to be managed, we use a separate opaque + // struct type. + + struct ConstantUniformFacts; // Opaque struct for holding data about uniform + // buffer elements. + std::unique_ptr + uniform_constant_facts_; // Unique pointer to internal data. }; } // namespace fuzz diff --git a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto index f00c51874..4bf82521f 100644 --- a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto +++ b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto @@ -57,12 +57,63 @@ message IdUseDescriptor { } +message UniformBufferElementDescriptor { + + // Represents a data element inside a uniform buffer. The element is + // specified via (a) the result id of a uniform variable in which the element + // is contained, and (b) a series of indices that need to be followed to get + // to the element (via fields and array/vector indices). + // + // Example: suppose %42 is the id of a uniform variable, and that the uniform + // variable has the following type (using GLSL-like syntax): + // + // struct S { + // float f; + // vec3 g; + // int4 h[10]; + // }; + // + // Then: + // - 42[0] describes the 'f' field. + // - 42[1,1] describes the y component of the 'g' field. + // - 42[2,7,3] describes the w component of element 7 of the 'h' field + + // The result id of a uniform variable. + uint32 uniform_variable_id = 1; + + // An ordered sequence of indices through composite structures in the + // uniform buffer. + repeated uint32 index = 2; + +} + message FactSequence { repeated Fact fact = 1; } message Fact { - // Currently there are no facts. + oneof fact { + // Order the fact options by numeric id (rather than alphabetically). + FactConstantUniform constant_uniform_fact = 1; + } +} + +// Keep fact message types in alphabetical order: + +message FactConstantUniform { + + // Records the fact that a uniform buffer element is guaranteed to be equal + // to a particular constant value. spirv-fuzz can use such guarantees to + // obfuscate code, e.g. to manufacture an expression that will (due to the + // guarantee) evaluate to a particular value at runtime but in a manner that + // cannot be predicted at compile-time. + + // An element of a uniform buffer + UniformBufferElementDescriptor uniform_buffer_element_descriptor = 1; + + // The words of the associated constant + repeated uint32 constant_word = 2; + } message TransformationSequence { diff --git a/3rdparty/spirv-tools/source/fuzz/replayer.cpp b/3rdparty/spirv-tools/source/fuzz/replayer.cpp new file mode 100644 index 000000000..ccea91f98 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/replayer.cpp @@ -0,0 +1,200 @@ +// 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 "source/fuzz/replayer.h" + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation_add_constant_boolean.h" +#include "source/fuzz/transformation_add_constant_scalar.h" +#include "source/fuzz/transformation_add_dead_break.h" +#include "source/fuzz/transformation_add_type_boolean.h" +#include "source/fuzz/transformation_add_type_float.h" +#include "source/fuzz/transformation_add_type_int.h" +#include "source/fuzz/transformation_move_block_down.h" +#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" +#include "source/fuzz/transformation_split_block.h" +#include "source/opt/build_module.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +namespace { + +// Returns true if and only if the precondition for |transformation| holds, with +// respect to the given |context| and |fact_manager|. +bool IsApplicable(const protobufs::Transformation& transformation, + opt::IRContext* context, const FactManager& fact_manager) { + switch (transformation.transformation_case()) { + case protobufs::Transformation::TransformationCase::kAddConstantBoolean: + return transformation::IsApplicable(transformation.add_constant_boolean(), + context, fact_manager); + case protobufs::Transformation::TransformationCase::kAddConstantScalar: + return transformation::IsApplicable(transformation.add_constant_scalar(), + context, fact_manager); + case protobufs::Transformation::TransformationCase::kAddDeadBreak: + return transformation::IsApplicable(transformation.add_dead_break(), + context, fact_manager); + case protobufs::Transformation::TransformationCase::kAddTypeBoolean: + return transformation::IsApplicable(transformation.add_type_boolean(), + context, fact_manager); + case protobufs::Transformation::TransformationCase::kAddTypeFloat: + return transformation::IsApplicable(transformation.add_type_float(), + context, fact_manager); + case protobufs::Transformation::TransformationCase::kAddTypeInt: + return transformation::IsApplicable(transformation.add_type_int(), + context, fact_manager); + case protobufs::Transformation::TransformationCase::kMoveBlockDown: + return transformation::IsApplicable(transformation.move_block_down(), + context, fact_manager); + case protobufs::Transformation::TransformationCase:: + kReplaceBooleanConstantWithConstantBinary: + return transformation::IsApplicable( + transformation.replace_boolean_constant_with_constant_binary(), + context, fact_manager); + case protobufs::Transformation::TransformationCase::kSplitBlock: + return transformation::IsApplicable(transformation.split_block(), context, + fact_manager); + default: + assert(transformation.transformation_case() == + protobufs::Transformation::TRANSFORMATION_NOT_SET && + "Unhandled transformation type."); + assert(false && "An unset transformation was encountered."); + return false; + } +} + +// Requires that IsApplicable holds. Applies |transformation| to the given +// |context| and |fact_manager|. +void Apply(const protobufs::Transformation& transformation, + opt::IRContext* context, FactManager* fact_manager) { + switch (transformation.transformation_case()) { + case protobufs::Transformation::TransformationCase::kAddConstantBoolean: + transformation::Apply(transformation.add_constant_boolean(), context, + fact_manager); + break; + case protobufs::Transformation::TransformationCase::kAddConstantScalar: + transformation::Apply(transformation.add_constant_scalar(), context, + fact_manager); + break; + case protobufs::Transformation::TransformationCase::kAddDeadBreak: + transformation::Apply(transformation.add_dead_break(), context, + fact_manager); + break; + case protobufs::Transformation::TransformationCase::kAddTypeBoolean: + transformation::Apply(transformation.add_type_boolean(), context, + fact_manager); + break; + case protobufs::Transformation::TransformationCase::kAddTypeFloat: + transformation::Apply(transformation.add_type_float(), context, + fact_manager); + break; + case protobufs::Transformation::TransformationCase::kAddTypeInt: + transformation::Apply(transformation.add_type_int(), context, + fact_manager); + break; + case protobufs::Transformation::TransformationCase::kMoveBlockDown: + transformation::Apply(transformation.move_block_down(), context, + fact_manager); + break; + case protobufs::Transformation::TransformationCase:: + kReplaceBooleanConstantWithConstantBinary: + transformation::Apply( + transformation.replace_boolean_constant_with_constant_binary(), + context, fact_manager); + break; + case protobufs::Transformation::TransformationCase::kSplitBlock: + transformation::Apply(transformation.split_block(), context, + fact_manager); + break; + default: + assert(transformation.transformation_case() == + protobufs::Transformation::TRANSFORMATION_NOT_SET && + "Unhandled transformation type."); + assert(false && "An unset transformation was encountered."); + } +} + +} // namespace + +struct Replayer::Impl { + explicit Impl(spv_target_env env) : target_env(env) {} + + const spv_target_env target_env; // Target environment. + MessageConsumer consumer; // Message consumer. +}; + +Replayer::Replayer(spv_target_env env) : impl_(MakeUnique(env)) {} + +Replayer::~Replayer() = default; + +void Replayer::SetMessageConsumer(MessageConsumer c) { + impl_->consumer = std::move(c); +} + +Replayer::ReplayerResultStatus Replayer::Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const protobufs::TransformationSequence& transformation_sequence_in, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out) const { + // Check compatibility between the library version being linked with and the + // header files being used. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + spvtools::SpirvTools tools(impl_->target_env); + if (!tools.IsValid()) { + impl_->consumer(SPV_MSG_ERROR, nullptr, {}, + "Failed to create SPIRV-Tools interface; stopping."); + return Replayer::ReplayerResultStatus::kFailedToCreateSpirvToolsInterface; + } + + // Initial binary should be valid. + if (!tools.Validate(&binary_in[0], binary_in.size())) { + impl_->consumer(SPV_MSG_INFO, nullptr, {}, + "Initial binary is invalid; stopping."); + return Replayer::ReplayerResultStatus::kInitialBinaryInvalid; + } + + // Build the module from the input binary. + std::unique_ptr ir_context = BuildModule( + impl_->target_env, impl_->consumer, binary_in.data(), binary_in.size()); + assert(ir_context); + + FactManager fact_manager; + if (!fact_manager.AddFacts(initial_facts, ir_context.get())) { + return Replayer::ReplayerResultStatus::kInitialFactsInvalid; + } + + // Consider the transformation proto messages in turn. + for (auto& transformation : transformation_sequence_in.transformation()) { + // Check whether the transformation can be applied. + if (IsApplicable(transformation, ir_context.get(), fact_manager)) { + // The transformation is applicable, so apply it, and copy it to the + // sequence of transformations that were applied. + Apply(transformation, ir_context.get(), &fact_manager); + *transformation_sequence_out->add_transformation() = transformation; + } + } + + // Write out the module as a binary. + ir_context->module()->ToBinary(binary_out, false); + return Replayer::ReplayerResultStatus::kComplete; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/replayer.h b/3rdparty/spirv-tools/source/fuzz/replayer.h new file mode 100644 index 000000000..a45cbb4fd --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/replayer.h @@ -0,0 +1,74 @@ +// 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_FUZZ_REPLAYER_H_ +#define SOURCE_FUZZ_REPLAYER_H_ + +#include +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace fuzz { + +// Transforms a SPIR-V module into a semantically equivalent SPIR-V module by +// applying a series of pre-defined transformations. +class Replayer { + public: + // Possible statuses that can result from running the replayer. + enum ReplayerResultStatus { + kComplete, + kFailedToCreateSpirvToolsInterface, + kInitialBinaryInvalid, + kInitialFactsInvalid, + }; + + // Constructs a replayer from the given target environment. + explicit Replayer(spv_target_env env); + + // Disables copy/move constructor/assignment operations. + Replayer(const Replayer&) = delete; + Replayer(Replayer&&) = delete; + Replayer& operator=(const Replayer&) = delete; + Replayer& operator=(Replayer&&) = delete; + + ~Replayer(); + + // Sets the message consumer to the given |consumer|. The |consumer| will be + // invoked once for each message communicated from the library. + void SetMessageConsumer(MessageConsumer consumer); + + // Transforms |binary_in| to |binary_out| by attempting to apply the + // transformations from |transformation_sequence_in|. Initial facts about the + // input binary and the context in which it will execute are provided via + // |initial_facts|. The transformations that were successfully applied are + // returned via |transformation_sequence_out|. + ReplayerResultStatus Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const protobufs::TransformationSequence& transformation_sequence_in, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out) const; + + private: + struct Impl; // Opaque struct for holding internal data. + std::unique_ptr impl_; // Unique pointer to internal data. +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_REPLAYER_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp b/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp new file mode 100644 index 000000000..cd840d3b6 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp @@ -0,0 +1,39 @@ +// 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 "source/fuzz/uniform_buffer_element_descriptor.h" + +namespace spvtools { +namespace fuzz { + +protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor( + uint32_t uniform_variable_id, std::vector&& indices) { + protobufs::UniformBufferElementDescriptor result; + result.set_uniform_variable_id(uniform_variable_id); + for (auto index : indices) { + result.add_index(index); + } + return result; +} + +bool UniformBufferElementDescriptorEquals::operator()( + const protobufs::UniformBufferElementDescriptor* first, + const protobufs::UniformBufferElementDescriptor* second) const { + return first->uniform_variable_id() == second->uniform_variable_id() && + std::equal(first->index().begin(), first->index().end(), + second->index().begin()); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h b/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h new file mode 100644 index 000000000..b2e596231 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h @@ -0,0 +1,41 @@ +// 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_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ +#define SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ + +#include +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" + +namespace spvtools { +namespace fuzz { + +// Factory method to create a uniform buffer element descriptor message from an +// id and list of indices. +protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor( + uint32_t uniform_variable_id, std::vector&& indices); + +// Equality function for uniform buffer element descriptors. +struct UniformBufferElementDescriptorEquals { + bool operator()( + const protobufs::UniformBufferElementDescriptor* first, + const protobufs::UniformBufferElementDescriptor* second) const; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // #define SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ diff --git a/3rdparty/spirv-tools/source/opt/log.h b/3rdparty/spirv-tools/source/opt/log.h index f87cbf381..68051002e 100644 --- a/3rdparty/spirv-tools/source/opt/log.h +++ b/3rdparty/spirv-tools/source/opt/log.h @@ -54,18 +54,19 @@ // Logs an error message to the consumer saying the given feature is // unimplemented. -#define SPIRV_UNIMPLEMENTED(consumer, feature) \ - do { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "unimplemented: " feature); \ +#define SPIRV_UNIMPLEMENTED(consumer, feature) \ + do { \ + spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, \ + "unimplemented: " feature); \ } while (0) // Logs an error message to the consumer saying the code location // should be unreachable. -#define SPIRV_UNREACHABLE(consumer) \ - do { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "unreachable"); \ +#define SPIRV_UNREACHABLE(consumer) \ + do { \ + spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, "unreachable"); \ } while (0) // Helper macros for concatenating arguments. @@ -154,32 +155,34 @@ inline void Errorf(const MessageConsumer& consumer, const char* source, PP_EXPAND(SPIRV_CONCATENATE(SPIRV_DEBUG_, PP_NARGS(__VA_ARGS__))( \ consumer, __VA_ARGS__)) -#define SPIRV_ASSERT_1(consumer, condition) \ - do { \ - if (!(condition)) { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "assertion failed: " #condition); \ - std::exit(EXIT_FAILURE); \ - } \ +#define SPIRV_ASSERT_1(consumer, condition) \ + do { \ + if (!(condition)) { \ + spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, \ + "assertion failed: " #condition); \ + std::exit(EXIT_FAILURE); \ + } \ } while (0) -#define SPIRV_ASSERT_2(consumer, condition, message) \ - do { \ - if (!(condition)) { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "assertion failed: " message); \ - std::exit(EXIT_FAILURE); \ - } \ +#define SPIRV_ASSERT_2(consumer, condition, message) \ + do { \ + if (!(condition)) { \ + spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, \ + "assertion failed: " message); \ + std::exit(EXIT_FAILURE); \ + } \ } while (0) -#define SPIRV_ASSERT_more(consumer, condition, format, ...) \ - do { \ - if (!(condition)) { \ - spvtools::Logf(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "assertion failed: " format, \ - __VA_ARGS__); \ - std::exit(EXIT_FAILURE); \ - } \ +#define SPIRV_ASSERT_more(consumer, condition, format, ...) \ + do { \ + if (!(condition)) { \ + spvtools::Logf(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, \ + "assertion failed: " format, __VA_ARGS__); \ + std::exit(EXIT_FAILURE); \ + } \ } while (0) #define SPIRV_ASSERT_3(consumer, condition, format, ...) \ @@ -191,16 +194,17 @@ inline void Errorf(const MessageConsumer& consumer, const char* source, #define SPIRV_ASSERT_5(consumer, condition, format, ...) \ SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__) -#define SPIRV_DEBUG_1(consumer, message) \ - do { \ - spvtools::Log(consumer, SPV_MSG_DEBUG, __FILE__, {__LINE__, 0, 0}, \ - message); \ +#define SPIRV_DEBUG_1(consumer, message) \ + do { \ + spvtools::Log(consumer, SPV_MSG_DEBUG, __FILE__, \ + {static_cast(__LINE__), 0, 0}, message); \ } while (0) -#define SPIRV_DEBUG_more(consumer, format, ...) \ - do { \ - spvtools::Logf(consumer, SPV_MSG_DEBUG, __FILE__, {__LINE__, 0, 0}, \ - format, __VA_ARGS__); \ +#define SPIRV_DEBUG_more(consumer, format, ...) \ + do { \ + spvtools::Logf(consumer, SPV_MSG_DEBUG, __FILE__, \ + {static_cast(__LINE__), 0, 0}, format, \ + __VA_ARGS__); \ } while (0) #define SPIRV_DEBUG_2(consumer, format, ...) \ diff --git a/3rdparty/spirv-tools/source/val/validate_builtins.cpp b/3rdparty/spirv-tools/source/val/validate_builtins.cpp index 06560655d..a9bf716e5 100644 --- a/3rdparty/spirv-tools/source/val/validate_builtins.cpp +++ b/3rdparty/spirv-tools/source/val/validate_builtins.cpp @@ -211,6 +211,17 @@ class BuiltInsValidator { spv_result_t ValidateSMBuiltinsAtDefinition(const Decoration& decoration, const Instruction& inst); + // Used for SubgroupEqMask, SubgroupGeMask, SubgroupGtMask, SubgroupLtMask, + // SubgroupLeMask. + spv_result_t ValidateI32Vec4InputAtDefinition(const Decoration& decoration, + const Instruction& inst); + // Used for SubgroupLocalInvocationId, SubgroupSize. + spv_result_t ValidateI32InputAtDefinition(const Decoration& decoration, + const Instruction& inst); + // Used for SubgroupId, NumSubgroups. + spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration, + const Instruction& inst); + // The following section contains functions which are called when id defined // by |referenced_inst| is // 1. referenced by |referenced_from_inst| @@ -333,6 +344,11 @@ class BuiltInsValidator { const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst); + // Used for SubgroupId and NumSubgroups. + spv_result_t ValidateComputeI32InputAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); spv_result_t ValidateSMBuiltinsAtReference( const Decoration& decoration, const Instruction& built_in_inst, @@ -2603,6 +2619,171 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " cannot be used as a member decoration "; + } + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 32-bit int " + "vector. " + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidateComputeI32InputAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute || + execution_model == SpvExecutionModelTaskNV || + execution_model == SpvExecutionModelMeshNV; + if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be used only with GLCompute execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back( + std::bind(&BuiltInsValidator::ValidateComputeI32InputAtReference, this, + decoration, built_in_inst, referenced_from_inst, + std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " cannot be used as a member decoration "; + } + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 32-bit int. " << message; + })) { + return error; + } + + const SpvStorageClass storage_class = GetStorageClass(inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, inst, inst, inst) << " " + << GetStorageClassDesc(inst); + } + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " cannot be used as a member decoration "; + } + if (spv_result_t error = ValidateI32Vec( + decoration, inst, 4, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 4-component 32-bit int " + "vector. " + << message; + })) { + return error; + } + + const SpvStorageClass storage_class = GetStorageClass(inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, inst, inst, inst) << " " + << GetStorageClassDesc(inst); + } + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { @@ -2788,6 +2969,21 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInSamplePosition: { return ValidateSamplePositionAtDefinition(decoration, inst); } + case SpvBuiltInSubgroupId: + case SpvBuiltInNumSubgroups: { + return ValidateComputeI32InputAtDefinition(decoration, inst); + } + case SpvBuiltInSubgroupLocalInvocationId: + case SpvBuiltInSubgroupSize: { + return ValidateI32InputAtDefinition(decoration, inst); + } + case SpvBuiltInSubgroupEqMask: + case SpvBuiltInSubgroupGeMask: + case SpvBuiltInSubgroupGtMask: + case SpvBuiltInSubgroupLeMask: + case SpvBuiltInSubgroupLtMask: { + return ValidateI32Vec4InputAtDefinition(decoration, inst); + } case SpvBuiltInTessCoord: { return ValidateTessCoordAtDefinition(decoration, inst); } @@ -2821,17 +3017,8 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInEnqueuedWorkgroupSize: case SpvBuiltInGlobalOffset: case SpvBuiltInGlobalLinearId: - case SpvBuiltInSubgroupSize: case SpvBuiltInSubgroupMaxSize: - case SpvBuiltInNumSubgroups: case SpvBuiltInNumEnqueuedSubgroups: - case SpvBuiltInSubgroupId: - case SpvBuiltInSubgroupLocalInvocationId: - case SpvBuiltInSubgroupEqMaskKHR: - case SpvBuiltInSubgroupGeMaskKHR: - case SpvBuiltInSubgroupGtMaskKHR: - case SpvBuiltInSubgroupLeMaskKHR: - case SpvBuiltInSubgroupLtMaskKHR: case SpvBuiltInBaseVertex: case SpvBuiltInBaseInstance: case SpvBuiltInDrawIndex: diff --git a/3rdparty/spirv-tools/source/val/validate_memory.cpp b/3rdparty/spirv-tools/source/val/validate_memory.cpp index e141309a2..af6b5c289 100644 --- a/3rdparty/spirv-tools/source/val/validate_memory.cpp +++ b/3rdparty/spirv-tools/source/val/validate_memory.cpp @@ -422,6 +422,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { << "OpVariable Initializer '" << _.getIdName(initializer_id) << "' is not a constant or module-scope variable."; } + if (initializer->type_id() != result_type->GetOperandAs(2u)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Initializer type must match the type pointed to by the Result " + "Type"; + } } const auto storage_class = diff --git a/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt index 88635c734..2e4bca576 100644 --- a/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt @@ -17,7 +17,8 @@ if (${SPIRV_BUILD_FUZZER}) set(SOURCES fuzz_test_util.h - fuzzer_test.cpp + fuzzer_replayer_test.cpp + fact_manager_test.cpp fuzz_test_util.cpp transformation_add_constant_boolean_test.cpp transformation_add_constant_scalar_test.cpp diff --git a/3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp b/3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp new file mode 100644 index 000000000..0209a608c --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp @@ -0,0 +1,534 @@ +// 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 "source/fuzz/fact_manager.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +using opt::analysis::BoolConstant; +using opt::analysis::FloatConstant; +using opt::analysis::IntConstant; +using opt::analysis::ScalarConstant; + +using opt::analysis::Bool; +using opt::analysis::Float; +using opt::analysis::Integer; +using opt::analysis::Type; + +bool AddFactHelper( + FactManager* fact_manager, opt::IRContext* context, + std::vector&& words, + const protobufs::UniformBufferElementDescriptor& descriptor) { + protobufs::FactConstantUniform constant_uniform_fact; + for (auto word : words) { + constant_uniform_fact.add_constant_word(word); + } + *constant_uniform_fact.mutable_uniform_buffer_element_descriptor() = + descriptor; + protobufs::Fact fact; + *fact.mutable_constant_uniform_fact() = constant_uniform_fact; + return fact_manager->AddFact(fact, context); +} + +TEST(FactManagerTest, ConstantsAvailableViaUniforms) { + std::string shader = R"( + OpCapability Shader + OpCapability Int64 + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 0 + %11 = OpTypeInt 32 1 + %12 = OpTypeInt 64 0 + %13 = OpTypeInt 64 1 + %15 = OpTypeFloat 32 + %16 = OpTypeFloat 64 + %17 = OpConstant %11 5 + %18 = OpConstant %11 20 + %19 = OpTypeVector %10 4 + %20 = OpConstant %11 6 + %21 = OpTypeVector %12 4 + %22 = OpConstant %11 10 + %23 = OpTypeVector %11 4 + + %102 = OpTypeStruct %10 %10 %23 + %101 = OpTypePointer Uniform %102 + %100 = OpVariable %101 Uniform + + %203 = OpTypeArray %23 %17 + %202 = OpTypeArray %203 %18 + %201 = OpTypePointer Uniform %202 + %200 = OpVariable %201 Uniform + + %305 = OpTypeStruct %16 %16 %16 %11 %16 + %304 = OpTypeStruct %16 %16 %305 + %303 = OpTypeStruct %304 + %302 = OpTypeStruct %10 %303 + %301 = OpTypePointer Uniform %302 + %300 = OpVariable %301 Uniform + + %400 = OpVariable %101 Uniform + + %500 = OpVariable %201 Uniform + + %604 = OpTypeArray %13 %20 + %603 = OpTypeArray %604 %20 + %602 = OpTypeArray %603 %20 + %601 = OpTypePointer Uniform %602 + %600 = OpVariable %601 Uniform + + %703 = OpTypeArray %13 %20 + %702 = OpTypeArray %703 %20 + %701 = OpTypePointer Uniform %702 + %700 = OpVariable %701 Uniform + + %802 = OpTypeStruct %702 %602 %19 %202 %302 + %801 = OpTypePointer Uniform %802 + %800 = OpVariable %801 Uniform + + %902 = OpTypeStruct %702 %802 %19 %202 %302 + %901 = OpTypePointer Uniform %902 + %900 = OpVariable %901 Uniform + + %1003 = OpTypeStruct %802 + %1002 = OpTypeArray %1003 %20 + %1001 = OpTypePointer Uniform %1002 + %1000 = OpVariable %1001 Uniform + + %1101 = OpTypePointer Uniform %21 + %1100 = OpVariable %1101 Uniform + + %1202 = OpTypeArray %21 %20 + %1201 = OpTypePointer Uniform %1202 + %1200 = OpVariable %1201 Uniform + + %1302 = OpTypeArray %21 %20 + %1301 = OpTypePointer Uniform %1302 + %1300 = OpVariable %1301 Uniform + + %1402 = OpTypeArray %15 %22 + %1401 = OpTypePointer Uniform %1402 + %1400 = OpVariable %1401 Uniform + + %1501 = OpTypePointer Uniform %1402 + %1500 = OpVariable %1501 Uniform + + %1602 = OpTypeArray %1402 %22 + %1601 = OpTypePointer Uniform %1602 + %1600 = OpVariable %1601 Uniform + + %1704 = OpTypeStruct %16 %16 %16 + %1703 = OpTypeArray %1704 %22 + %1702 = OpTypeArray %1703 %22 + %1701 = OpTypePointer Uniform %1702 + %1700 = OpVariable %1701 Uniform + + %1800 = OpVariable %1701 Uniform + + %1906 = OpTypeStruct %16 + %1905 = OpTypeStruct %1906 + %1904 = OpTypeStruct %1905 + %1903 = OpTypeStruct %1904 + %1902 = OpTypeStruct %1903 + %1901 = OpTypePointer Uniform %1902 + %1900 = OpVariable %1901 Uniform + + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + uint32_t buffer_int32_min[1]; + uint32_t buffer_int64_1[2]; + uint32_t buffer_int64_max[2]; + uint32_t buffer_uint64_1[2]; + uint32_t buffer_uint64_max[2]; + uint32_t buffer_float_10[1]; + uint32_t buffer_double_10[2]; + uint32_t buffer_double_20[2]; + + { + int32_t temp = std::numeric_limits::min(); + std::memcpy(&buffer_int32_min, &temp, sizeof(temp)); + } + + { + int64_t temp = 1; + std::memcpy(&buffer_int64_1, &temp, sizeof(temp)); + } + + { + int64_t temp = std::numeric_limits::max(); + std::memcpy(&buffer_int64_max, &temp, sizeof(temp)); + } + + { + uint64_t temp = 1; + std::memcpy(&buffer_uint64_1, &temp, sizeof(temp)); + } + + { + uint64_t temp = std::numeric_limits::max(); + std::memcpy(&buffer_uint64_max, &temp, sizeof(temp)); + } + + { + float temp = 10.0f; + std::memcpy(&buffer_float_10, &temp, sizeof(float)); + } + + { + double temp = 10.0; + std::memcpy(&buffer_double_10, &temp, sizeof(temp)); + } + + { + double temp = 20.0; + std::memcpy(&buffer_double_20, &temp, sizeof(temp)); + } + + FactManager fact_manager; + + uint32_t type_int32_id = 11; + uint32_t type_int64_id = 13; + uint32_t type_uint32_id = 10; + uint32_t type_uint64_id = 12; + uint32_t type_float_id = 15; + uint32_t type_double_id = 16; + + // Initially there should be no facts about uniforms. + ASSERT_TRUE(fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_uint32_id) + .empty()); + + // 100[2][3] == int(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(100, {2, 3}))); + + // 200[1][2][3] == int(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(200, {1, 2, 3}))); + + // 300[1][0][2][3] == int(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(300, {1, 0, 2, 3}))); + + // 400[2][3] = int32_min + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]}, + MakeUniformBufferElementDescriptor(400, {2, 3}))); + + // 500[1][2][3] = int32_min + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]}, + MakeUniformBufferElementDescriptor(500, {1, 2, 3}))); + + // 600[1][2][3] = int64_max + ASSERT_TRUE(AddFactHelper( + &fact_manager, context.get(), {buffer_int64_max[0], buffer_int64_max[1]}, + MakeUniformBufferElementDescriptor(600, {1, 2, 3}))); + + // 700[1][1] = int64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), + {buffer_int64_max[0], buffer_int64_max[1]}, + MakeUniformBufferElementDescriptor(700, {1, 1}))); + + // 800[2][3] = uint(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(800, {2, 3}))); + + // 900[1][2][3] = uint(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(900, {1, 2, 3}))); + + // 1000[1][0][2][3] = uint(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(1000, {1, 0, 2, 3}))); + + // 1100[0] = uint64(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), + {buffer_uint64_1[0], buffer_uint64_1[1]}, + MakeUniformBufferElementDescriptor(1100, {0}))); + + // 1200[0][0] = uint64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), + {buffer_uint64_max[0], buffer_uint64_max[1]}, + MakeUniformBufferElementDescriptor(1200, {0, 0}))); + + // 1300[1][0] = uint64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), + {buffer_uint64_max[0], buffer_uint64_max[1]}, + MakeUniformBufferElementDescriptor(1300, {1, 0}))); + + // 1400[6] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(1400, {6}))); + + // 1500[7] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(1500, {7}))); + + // 1600[9][9] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(1600, {9, 9}))); + + // 1700[9][9][1] = double(10.0) + ASSERT_TRUE(AddFactHelper( + &fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]}, + MakeUniformBufferElementDescriptor(1700, {9, 9, 1}))); + + // 1800[9][9][2] = double(10.0) + ASSERT_TRUE(AddFactHelper( + &fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]}, + MakeUniformBufferElementDescriptor(1800, {9, 9, 2}))); + + // 1900[0][0][0][0][0] = double(20.0) + ASSERT_TRUE(AddFactHelper( + &fact_manager, context.get(), {buffer_double_20[0], buffer_double_20[1]}, + MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0}))); + + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 50, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int32_min[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 51, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int64_id, 52, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint32_id, 53, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint64_id, 54, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint64_id, 55, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_float_10[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_float_id, 56, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_double_id, 57, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_double_id, 58, operands)); + + // A duplicate of the constant with id 59. + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 59, operands)); + + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); + + // Constants 1 and int32_min are available. + ASSERT_EQ(2, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_int32_id) + .size()); + // Constant int64_max is available. + ASSERT_EQ(1, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_int64_id) + .size()); + // Constant 1u is available. + ASSERT_EQ(1, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_uint32_id) + .size()); + // Constants 1u and uint64_max are available. + ASSERT_EQ(2, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_uint64_id) + .size()); + // Constant 10.0 is available. + ASSERT_EQ(1, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_float_id) + .size()); + // Constants 10.0 and 20.0 are available. + ASSERT_EQ(2, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_double_id) + .size()); + + ASSERT_EQ(std::numeric_limits::max(), + context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + context.get(), type_int64_id)[0]) + ->AsIntConstant() + ->GetS64()); + ASSERT_EQ(1, context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + context.get(), type_uint32_id)[0]) + ->AsIntConstant() + ->GetU32()); + ASSERT_EQ(10.0f, + context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + context.get(), type_float_id)[0]) + ->AsFloatConstant() + ->GetFloat()); + const std::vector& double_constant_ids = + fact_manager.GetConstantsAvailableFromUniformsForType(context.get(), + type_double_id); + ASSERT_EQ(10.0, context->get_constant_mgr() + ->FindDeclaredConstant(double_constant_ids[0]) + ->AsFloatConstant() + ->GetDouble()); + ASSERT_EQ(20.0, context->get_constant_mgr() + ->FindDeclaredConstant(double_constant_ids[1]) + ->AsFloatConstant() + ->GetDouble()); + + const std::vector + descriptors_for_double_10 = fact_manager.GetUniformDescriptorsForConstant( + context.get(), double_constant_ids[0]); + ASSERT_EQ(2, descriptors_for_double_10.size()); + { + auto temp = MakeUniformBufferElementDescriptor(1700, {9, 9, 1}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_10[0])); + } + { + auto temp = MakeUniformBufferElementDescriptor(1800, {9, 9, 2}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_10[1])); + } + const std::vector + descriptors_for_double_20 = fact_manager.GetUniformDescriptorsForConstant( + context.get(), double_constant_ids[1]); + ASSERT_EQ(1, descriptors_for_double_20.size()); + { + auto temp = MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_20[0])); + } + + auto constant_1_id = fact_manager.GetConstantFromUniformDescriptor( + context.get(), MakeUniformBufferElementDescriptor(1800, {9, 9, 2})); + ASSERT_TRUE(constant_1_id); + + auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor( + context.get(), MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0})); + ASSERT_TRUE(constant_2_id); + + ASSERT_EQ(double_constant_ids[0], constant_1_id); + + ASSERT_EQ(double_constant_ids[1], constant_2_id); +} + +TEST(FactManagerTest, TwoConstantsWithSameValue) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "buf" + OpMemberName %10 0 "a" + OpName %12 "" + OpDecorate %8 RelaxedPrecision + OpMemberDecorate %10 0 RelaxedPrecision + OpMemberDecorate %10 0 Offset 0 + OpDecorate %10 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %20 = OpConstant %6 1 + %10 = OpTypeStruct %6 + %11 = OpTypePointer Uniform %10 + %12 = OpVariable %11 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto uniform_buffer_element_descriptor = + MakeUniformBufferElementDescriptor(12, {0}); + + // 12[0] = int(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1}, + uniform_buffer_element_descriptor)); + auto constants = + fact_manager.GetConstantsAvailableFromUniformsForType(context.get(), 6); + ASSERT_EQ(1, constants.size()); + ASSERT_TRUE(constants[0] == 9 || constants[0] == 20); + + auto constant = fact_manager.GetConstantFromUniformDescriptor( + context.get(), uniform_buffer_element_descriptor); + ASSERT_TRUE(constant == 9 || constant == 20); + + // Because the constants with ids 9 and 20 are equal, we should get the same + // single uniform buffer element descriptor when we look up the descriptors + // for either one of them. + for (auto constant_id : {9u, 20u}) { + auto descriptors = fact_manager.GetUniformDescriptorsForConstant( + context.get(), constant_id); + ASSERT_EQ(1, descriptors.size()); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &uniform_buffer_element_descriptor, &descriptors[0])); + } +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/fuzz/fuzzer_test.cpp b/3rdparty/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp similarity index 89% rename from 3rdparty/spirv-tools/test/fuzz/fuzzer_test.cpp rename to 3rdparty/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp index 069777ff3..3adf76621 100644 --- a/3rdparty/spirv-tools/test/fuzz/fuzzer_test.cpp +++ b/3rdparty/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include "source/fuzz/fuzzer.h" +#include "source/fuzz/replayer.h" #include "test/fuzz/fuzz_test_util.h" namespace spvtools { @@ -21,9 +22,11 @@ namespace { // Assembles the given |shader| text, and then runs the fuzzer |num_runs| // times, using successive seeds starting from |initial_seed|. Checks that -// the binary produced after each fuzzer run is valid. -void RunFuzzer(const std::string& shader, uint32_t initial_seed, - uint32_t num_runs) { +// the binary produced after each fuzzer run is valid, and that replaying +// the transformations that were applied during fuzzing leads to an +// identical binary. +void RunFuzzerAndReplayer(const std::string& shader, uint32_t initial_seed, + uint32_t num_runs) { const auto env = SPV_ENV_UNIVERSAL_1_3; std::vector binary_in; @@ -33,19 +36,38 @@ void RunFuzzer(const std::string& shader, uint32_t initial_seed, for (uint32_t seed = initial_seed; seed < initial_seed + num_runs; seed++) { protobufs::FactSequence initial_facts; - std::vector binary_out; - protobufs::TransformationSequence transformation_sequence_out; + std::vector fuzzer_binary_out; + protobufs::TransformationSequence fuzzer_transformation_sequence_out; spvtools::FuzzerOptions fuzzer_options; spvFuzzerOptionsSetRandomSeed(fuzzer_options, seed); Fuzzer fuzzer(env); - fuzzer.Run(binary_in, initial_facts, &binary_out, - &transformation_sequence_out, fuzzer_options); - ASSERT_TRUE(t.Validate(binary_out)); + fuzzer.Run(binary_in, initial_facts, &fuzzer_binary_out, + &fuzzer_transformation_sequence_out, fuzzer_options); + ASSERT_TRUE(t.Validate(fuzzer_binary_out)); + + std::vector replayer_binary_out; + protobufs::TransformationSequence replayer_transformation_sequence_out; + + Replayer replayer(env); + replayer.Run(binary_in, initial_facts, fuzzer_transformation_sequence_out, + &replayer_binary_out, &replayer_transformation_sequence_out); + + // After replaying the transformations applied by the fuzzer, exactly those + // transformations should have been applied, and the binary resulting from + // replay should be identical to that which resulted from fuzzing. + std::string fuzzer_transformations_string; + std::string replayer_transformations_string; + fuzzer_transformation_sequence_out.SerializeToString( + &fuzzer_transformations_string); + replayer_transformation_sequence_out.SerializeToString( + &replayer_transformations_string); + ASSERT_EQ(fuzzer_transformations_string, replayer_transformations_string); + ASSERT_EQ(fuzzer_binary_out, replayer_binary_out); } } -TEST(FuzzerTest, Miscellaneous1) { +TEST(FuzzerReplayerTest, Miscellaneous1) { // The SPIR-V came from this GLSL: // // #version 310 es @@ -211,10 +233,10 @@ TEST(FuzzerTest, Miscellaneous1) { // Do 10 fuzzer runs, starting from an initial seed of 0 (seed value chosen // arbitrarily). - RunFuzzer(shader, 0, 10); + RunFuzzerAndReplayer(shader, 0, 10); } -TEST(FuzzerTest, Miscellaneous2) { +TEST(FuzzerReplayerTest, Miscellaneous2) { // The SPIR-V came from this GLSL, which was then optimized using spirv-opt // with the -O argument: // @@ -456,7 +478,7 @@ TEST(FuzzerTest, Miscellaneous2) { // Do 10 fuzzer runs, starting from an initial seed of 10 (seed value chosen // arbitrarily). - RunFuzzer(shader, 10, 10); + RunFuzzerAndReplayer(shader, 10, 10); } } // namespace diff --git a/3rdparty/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp b/3rdparty/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp index ae98b93de..4f89487d5 100644 --- a/3rdparty/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp +++ b/3rdparty/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp @@ -3811,7 +3811,7 @@ OpName %output "output" %6 = OpTypeFunction %void %float = OpTypeFloat 32 %_ptr_Private_float = OpTypePointer Private %float -%initializer = OpVariable %_ptr_Private_float Private +%initializer = OpConstant %float 0 %live = OpVariable %_ptr_Private_float Private %initializer %_ptr_Output_float = OpTypePointer Output %float %output = OpVariable %_ptr_Output_float Output diff --git a/3rdparty/spirv-tools/test/opt/dead_variable_elim_test.cpp b/3rdparty/spirv-tools/test/opt/dead_variable_elim_test.cpp index fca13a8e2..a55ee62a5 100644 --- a/3rdparty/spirv-tools/test/opt/dead_variable_elim_test.cpp +++ b/3rdparty/spirv-tools/test/opt/dead_variable_elim_test.cpp @@ -217,7 +217,7 @@ OpName %initializer "initializer" %6 = OpTypeFunction %void %float = OpTypeFloat 32 %_ptr_Private_float = OpTypePointer Private %float -%initializer = OpVariable %_ptr_Private_float Private +%initializer = OpConstant %float 0 %live = OpVariable %_ptr_Private_float Private %initializer %main = OpFunction %void None %6 %9 = OpLabel diff --git a/3rdparty/spirv-tools/test/val/val_builtins_test.cpp b/3rdparty/spirv-tools/test/val/val_builtins_test.cpp index df048adc2..e3eca09aa 100644 --- a/3rdparty/spirv-tools/test/val/val_builtins_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_builtins_test.cpp @@ -52,6 +52,8 @@ using ::testing::Values; using ::testing::ValuesIn; using ValidateBuiltIns = spvtest::ValidateBase; +using ValidateVulkanSubgroupBuiltIns = spvtest::ValidateBase< + std::tuple>; using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult = spvtest::ValidateBase>; @@ -3080,6 +3082,226 @@ TEST_F(ValidateBuiltIns, GetUnderlyingTypeNoAssert) { "type")); } +TEST_P(ValidateVulkanSubgroupBuiltIns, 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 = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.capabilities_ += R"( +OpCapability GroupNonUniformBallot +)"; + + 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_ptr = OpTypePointer " << storage_class << " " + << data_type << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + after_types << "\n"; + generator.after_types_ = after_types.str(); + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = execution_model; + if (strncmp(storage_class, "Input", 5) == 0 || + strncmp(storage_class, "Output", 6) == 0) { + entry_point.interfaces = "%built_in_var"; + } + entry_point.body = + std::string("%ld = OpLoad ") + data_type + " %built_in_var\n"; + + std::ostringstream execution_modes; + if (0 == std::strcmp(execution_model, "Fragment")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " OriginUpperLeft\n"; + if (0 == std::strcmp(built_in, "FragDepth")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " DepthReplacing\n"; + } + } + if (0 == std::strcmp(execution_model, "Geometry")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " InputPoints\n"; + execution_modes << "OpExecutionMode %" << entry_point.name + << " OutputPoints\n"; + } + if (0 == std::strcmp(execution_model, "GLCompute")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " LocalSize 1 1 1\n"; + } + entry_point.execution_modes = execution_modes.str(); + + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_1)); + 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_SUITE_P( + SubgroupMaskNotVec4, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask", + "SubgroupLeMask", "SubgroupLtMask"), + Values("GLCompute"), Values("Input"), Values("%u32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit int vector")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupMaskNotU32, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask", + "SubgroupLeMask", "SubgroupLtMask"), + Values("GLCompute"), Values("Input"), Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit int vector")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupMaskNotInput, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask", + "SubgroupLeMask", "SubgroupLtMask"), + Values("GLCompute"), Values("Output", "Workgroup", "Private"), + Values("%u32vec4"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class")))); + +INSTANTIATE_TEST_SUITE_P(SubgroupMaskOk, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupEqMask", "SubgroupGeMask", + "SubgroupGtMask", "SubgroupLeMask", + "SubgroupLtMask"), + Values("GLCompute"), Values("Input"), + Values("%u32vec4"), + Values(TestResult(SPV_SUCCESS, "")))); + +TEST_F(ValidateBuiltIns, SubgroupMaskMemberDecorate) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniformBallot +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +OpMemberDecorate %struct 0 BuiltIn SubgroupEqMask +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "BuiltIn SubgroupEqMask cannot be used as a member decoration")); +} + +INSTANTIATE_TEST_SUITE_P( + SubgroupInvocationIdAndSizeNotU32, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), + Values("GLCompute"), Values("Input"), Values("%f32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupInvocationIdAndSizeNotInput, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), + Values("GLCompute"), Values("Output", "Workgroup", "Private"), + Values("%u32"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupInvocationIdAndSizeOk, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), + Values("GLCompute"), Values("Input"), Values("%u32"), + Values(TestResult(SPV_SUCCESS, "")))); + +TEST_F(ValidateBuiltIns, SubgroupSizeMemberDecorate) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +OpMemberDecorate %struct 0 BuiltIn SubgroupSize +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("BuiltIn SubgroupSize cannot be used as a member decoration")); +} + +INSTANTIATE_TEST_SUITE_P( + SubgroupNumAndIdNotU32, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"), + Values("Input"), Values("%f32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupNumAndIdNotInput, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"), + Values("Output", "Workgroup", "Private"), Values("%u32"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class")))); + +INSTANTIATE_TEST_SUITE_P(SubgroupNumAndIdOk, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupId", "NumSubgroups"), + Values("GLCompute"), Values("Input"), + Values("%u32"), + Values(TestResult(SPV_SUCCESS, "")))); + +TEST_F(ValidateBuiltIns, SubgroupIdMemberDecorate) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +OpMemberDecorate %struct 0 BuiltIn SubgroupId +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("BuiltIn SubgroupId cannot be used as a member decoration")); +} + } // 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 490ffa88b..f10582209 100644 --- a/3rdparty/spirv-tools/test/val/val_memory_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_memory_test.cpp @@ -3543,6 +3543,29 @@ OpFunctionEnd INSTANTIATE_TEST_SUITE_P(PointerComparisons, ValidatePointerComparisons, Values("OpPtrEqual", "OpPtrNotEqual", "OpPtrDiff")); +TEST_F(ValidateMemory, VariableInitializerWrongType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%ptr_wg_int = OpTypePointer Workgroup %int +%ptr_wg_float = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%ptr_private_wg_float = OpTypePointer Private %ptr_wg_float +%priv_var = OpVariable %ptr_private_wg_float Private %wg_var +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Initializer type must match the type pointed to by " + "the Result Type")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/tools/fuzz/fuzz.cpp b/3rdparty/spirv-tools/tools/fuzz/fuzz.cpp index 2a31a2009..089dc4e03 100644 --- a/3rdparty/spirv-tools/tools/fuzz/fuzz.cpp +++ b/3rdparty/spirv-tools/tools/fuzz/fuzz.cpp @@ -21,6 +21,7 @@ #include "source/fuzz/fuzzer.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/replayer.h" #include "source/opt/build_module.h" #include "source/opt/ir_context.h" #include "source/opt/log.h" @@ -32,7 +33,11 @@ namespace { // Status and actions to perform after parsing command-line arguments. -enum class FuzzActions { CONTINUE, STOP }; +enum class FuzzActions { + FUZZ, // Run the fuzzer to apply transformations in a randomized fashion. + REPLAY, // Replay an existing sequence of transformations. + STOP // Do nothing. +}; struct FuzzStatus { FuzzActions action; @@ -60,6 +65,9 @@ Options (in lexicographical order): -h, --help Print this help. + --replay + File from which to read a sequence of transformations to replay + (instead of fuzzing) --seed Unsigned 32-bit integer seed to control random number generation. @@ -90,6 +98,7 @@ bool EndsWithSpv(const std::string& filename) { FuzzStatus ParseFlags(int argc, const char** argv, std::string* in_binary_file, std::string* out_binary_file, + std::string* replay_transformations_file, spvtools::FuzzerOptions* fuzzer_options) { uint32_t positional_arg_index = 0; @@ -110,6 +119,9 @@ FuzzStatus ParseFlags(int argc, const char** argv, std::string* in_binary_file, PrintUsage(argv[0]); return {FuzzActions::STOP, 1}; } + } else if (0 == strncmp(cur_arg, "--replay=", sizeof("--replay=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + *replay_transformations_file = std::string(split_flag.second); } else if (0 == strncmp(cur_arg, "--seed=", sizeof("--seed=") - 1)) { const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); char* end = nullptr; @@ -158,7 +170,64 @@ FuzzStatus ParseFlags(int argc, const char** argv, std::string* in_binary_file, return {FuzzActions::STOP, 1}; } - return {FuzzActions::CONTINUE, 0}; + if (!replay_transformations_file->empty()) { + // A replay transformations file was given, thus the tool is being invoked + // in replay mode. + return {FuzzActions::REPLAY, 0}; + } + + return {FuzzActions::FUZZ, 0}; +} + +bool Replay(const spv_target_env& target_env, + const std::vector& binary_in, + const spvtools::fuzz::protobufs::FactSequence& initial_facts, + const std::string& replay_transformations_file, + std::vector* binary_out, + spvtools::fuzz::protobufs::TransformationSequence* + transformations_applied) { + std::ifstream existing_transformations_file; + existing_transformations_file.open(replay_transformations_file, + std::ios::in | std::ios::binary); + spvtools::fuzz::protobufs::TransformationSequence + existing_transformation_sequence; + auto parse_success = existing_transformation_sequence.ParseFromIstream( + &existing_transformations_file); + existing_transformations_file.close(); + if (!parse_success) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "Error reading transformations for replay"); + return false; + } + spvtools::fuzz::Replayer replayer(target_env); + replayer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + auto replay_result_status = + replayer.Run(binary_in, initial_facts, existing_transformation_sequence, + binary_out, transformations_applied); + if (replay_result_status != + spvtools::fuzz::Replayer::ReplayerResultStatus::kComplete) { + return false; + } + return true; +} + +bool Fuzz(const spv_target_env& target_env, + const spvtools::FuzzerOptions& fuzzer_options, + const std::vector& binary_in, + const spvtools::fuzz::protobufs::FactSequence& initial_facts, + std::vector* binary_out, + spvtools::fuzz::protobufs::TransformationSequence* + transformations_applied) { + spvtools::fuzz::Fuzzer fuzzer(target_env); + fuzzer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + auto fuzz_result_status = fuzzer.Run(binary_in, initial_facts, binary_out, + transformations_applied, fuzzer_options); + if (fuzz_result_status != + spvtools::fuzz::Fuzzer::FuzzerResultStatus::kComplete) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error running fuzzer"); + return false; + } + return true; } } // namespace @@ -168,12 +237,12 @@ const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_3; int main(int argc, const char** argv) { std::string in_binary_file; std::string out_binary_file; + std::string replay_transformations_file; - spv_target_env target_env = kDefaultEnvironment; spvtools::FuzzerOptions fuzzer_options; FuzzStatus status = ParseFlags(argc, argv, &in_binary_file, &out_binary_file, - &fuzzer_options); + &replay_transformations_file, &fuzzer_options); if (status.action == FuzzActions::STOP) { return status.code; @@ -205,15 +274,25 @@ int main(int argc, const char** argv) { std::vector binary_out; spvtools::fuzz::protobufs::TransformationSequence transformations_applied; - spvtools::fuzz::Fuzzer fuzzer(target_env); - fuzzer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); - auto fuzz_result_status = - fuzzer.Run(binary_in, initial_facts, &binary_out, - &transformations_applied, fuzzer_options); - if (fuzz_result_status != - spvtools::fuzz::Fuzzer::FuzzerResultStatus::kComplete) { - spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error running fuzzer"); - return 1; + spv_target_env target_env = kDefaultEnvironment; + + switch (status.action) { + case FuzzActions::FUZZ: + if (!Fuzz(target_env, fuzzer_options, binary_in, initial_facts, + &binary_out, &transformations_applied)) { + return 1; + } + break; + case FuzzActions::REPLAY: + if (!Replay(target_env, binary_in, initial_facts, + replay_transformations_file, &binary_out, + &transformations_applied)) { + return 1; + } + break; + default: + assert(false && "Unknown fuzzer action."); + break; } if (!WriteFile(out_binary_file.c_str(), "wb", binary_out.data(),