Updated spirv-tools.

This commit is contained in:
Бранимир Караџић 2022-03-05 17:40:54 -08:00
parent 971f86f370
commit 1e978cc3db
19 changed files with 705 additions and 313 deletions

View File

@ -1 +1 @@
"v2022.2-dev", "SPIRV-Tools v2022.2-dev 8f96b8ade7aed1a3448c9cd0294449e7a41b91f7"
"v2022.2-dev", "SPIRV-Tools v2022.2-dev da9e2f0400ece7d68b44d7c7126cac808dfcf5c3"

View File

@ -56,6 +56,7 @@ static const SpvCapability pygen_variable_caps_Shader[] = {SpvCapabilityShader};
static const SpvCapability pygen_variable_caps_ShaderBitInstructions[] = {SpvCapabilityShader, SpvCapabilityBitInstructions};
static const SpvCapability pygen_variable_caps_ShaderClockKHR[] = {SpvCapabilityShaderClockKHR};
static const SpvCapability pygen_variable_caps_SparseResidency[] = {SpvCapabilitySparseResidency};
static const SpvCapability pygen_variable_caps_SplitBarrierINTEL[] = {SpvCapabilitySplitBarrierINTEL};
static const SpvCapability pygen_variable_caps_SubgroupAvcMotionEstimationINTEL[] = {SpvCapabilitySubgroupAvcMotionEstimationINTEL};
static const SpvCapability pygen_variable_caps_SubgroupAvcMotionEstimationINTELSubgroupAvcMotionEstimationChromaINTEL[] = {SpvCapabilitySubgroupAvcMotionEstimationINTEL, SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL};
static const SpvCapability pygen_variable_caps_SubgroupAvcMotionEstimationINTELSubgroupAvcMotionEstimationIntraINTEL[] = {SpvCapabilitySubgroupAvcMotionEstimationINTEL, SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL};
@ -509,7 +510,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
{"BeginInvocationInterlockEXT", SpvOpBeginInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu},
{"EndInvocationInterlockEXT", SpvOpEndInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu},
{"DemoteToHelperInvocation", SpvOpDemoteToHelperInvocation, 1, pygen_variable_caps_DemoteToHelperInvocation, 0, {}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu},
{"DemoteToHelperInvocationEXT", SpvOpDemoteToHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocation, 0, {}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu},
{"DemoteToHelperInvocationEXT", SpvOpDemoteToHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocationEXT, 0, {}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu},
{"IsHelperInvocationEXT", SpvOpIsHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocationEXT, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, 0xffffffffu, 0xffffffffu},
{"ConvertUToImageNV", SpvOpConvertUToImageNV, 1, pygen_variable_caps_BindlessTextureNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"ConvertUToSamplerNV", SpvOpConvertUToSamplerNV, 1, pygen_variable_caps_BindlessTextureNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
@ -758,5 +759,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
{"TypeBufferSurfaceINTEL", SpvOpTypeBufferSurfaceINTEL, 1, pygen_variable_caps_VectorComputeINTEL, 2, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ACCESS_QUALIFIER}, 1, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"TypeStructContinuedINTEL", SpvOpTypeStructContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"ConstantCompositeContinuedINTEL", SpvOpConstantCompositeContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"SpecConstantCompositeContinuedINTEL", SpvOpSpecConstantCompositeContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}
{"SpecConstantCompositeContinuedINTEL", SpvOpSpecConstantCompositeContinuedINTEL, 1, pygen_variable_caps_LongConstantCompositeINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"ControlBarrierArriveINTEL", SpvOpControlBarrierArriveINTEL, 1, pygen_variable_caps_SplitBarrierINTEL, 3, {SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
{"ControlBarrierWaitINTEL", SpvOpControlBarrierWaitINTEL, 1, pygen_variable_caps_SplitBarrierINTEL, 3, {SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}
};

View File

@ -98,6 +98,8 @@ const char* ExtensionToString(Extension extension) {
return "SPV_INTEL_optnone";
case Extension::kSPV_INTEL_shader_integer_functions2:
return "SPV_INTEL_shader_integer_functions2";
case Extension::kSPV_INTEL_split_barrier:
return "SPV_INTEL_split_barrier";
case Extension::kSPV_INTEL_subgroups:
return "SPV_INTEL_subgroups";
case Extension::kSPV_INTEL_unstructured_loop_controls:
@ -205,8 +207,8 @@ const char* ExtensionToString(Extension extension) {
bool GetExtensionFromString(const char* str, Extension* extension) {
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_atomic_float16_add", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_shader_atomic_float_min_max", "SPV_EXT_shader_image_int64", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_arbitrary_precision_fixed_point", "SPV_INTEL_arbitrary_precision_floating_point", "SPV_INTEL_arbitrary_precision_integers", "SPV_INTEL_blocking_pipes", "SPV_INTEL_debug_module", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_float_controls2", "SPV_INTEL_fp_fast_math_mode", "SPV_INTEL_fpga_buffer_location", "SPV_INTEL_fpga_cluster_attributes", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_accesses", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_inline_assembly", "SPV_INTEL_io_pipes", "SPV_INTEL_kernel_attributes", "SPV_INTEL_long_constant_composite", "SPV_INTEL_loop_fuse", "SPV_INTEL_media_block_io", "SPV_INTEL_memory_access_aliasing", "SPV_INTEL_optnone", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_INTEL_usm_storage_classes", "SPV_INTEL_variable_length_array", "SPV_INTEL_vector_compute", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_bit_instructions", "SPV_KHR_device_group", "SPV_KHR_expect_assume", "SPV_KHR_float_controls", "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_fragment_shading_rate", "SPV_KHR_integer_dot_product", "SPV_KHR_linkonce_odr", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_non_semantic_info", "SPV_KHR_physical_storage_buffer", "SPV_KHR_post_depth_coverage", "SPV_KHR_ray_query", "SPV_KHR_ray_tracing", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_clock", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_KHR_workgroup_memory_explicit_layout", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_bindless_texture", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_ray_tracing_motion_blur", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_atomic_float16_add, Extension::kSPV_EXT_shader_atomic_float_add, Extension::kSPV_EXT_shader_atomic_float_min_max, Extension::kSPV_EXT_shader_image_int64, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_arbitrary_precision_fixed_point, Extension::kSPV_INTEL_arbitrary_precision_floating_point, Extension::kSPV_INTEL_arbitrary_precision_integers, Extension::kSPV_INTEL_blocking_pipes, Extension::kSPV_INTEL_debug_module, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_float_controls2, Extension::kSPV_INTEL_fp_fast_math_mode, Extension::kSPV_INTEL_fpga_buffer_location, Extension::kSPV_INTEL_fpga_cluster_attributes, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_accesses, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_inline_assembly, Extension::kSPV_INTEL_io_pipes, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_long_constant_composite, Extension::kSPV_INTEL_loop_fuse, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_memory_access_aliasing, Extension::kSPV_INTEL_optnone, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_INTEL_usm_storage_classes, Extension::kSPV_INTEL_variable_length_array, Extension::kSPV_INTEL_vector_compute, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_bit_instructions, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_expect_assume, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_fragment_shader_barycentric, Extension::kSPV_KHR_fragment_shading_rate, Extension::kSPV_KHR_integer_dot_product, Extension::kSPV_KHR_linkonce_odr, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_non_semantic_info, Extension::kSPV_KHR_physical_storage_buffer, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_ray_query, Extension::kSPV_KHR_ray_tracing, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_clock, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_KHR_workgroup_memory_explicit_layout, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_bindless_texture, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_ray_tracing_motion_blur, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_atomic_float16_add", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_shader_atomic_float_min_max", "SPV_EXT_shader_image_int64", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_arbitrary_precision_fixed_point", "SPV_INTEL_arbitrary_precision_floating_point", "SPV_INTEL_arbitrary_precision_integers", "SPV_INTEL_blocking_pipes", "SPV_INTEL_debug_module", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_float_controls2", "SPV_INTEL_fp_fast_math_mode", "SPV_INTEL_fpga_buffer_location", "SPV_INTEL_fpga_cluster_attributes", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_accesses", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_inline_assembly", "SPV_INTEL_io_pipes", "SPV_INTEL_kernel_attributes", "SPV_INTEL_long_constant_composite", "SPV_INTEL_loop_fuse", "SPV_INTEL_media_block_io", "SPV_INTEL_memory_access_aliasing", "SPV_INTEL_optnone", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_split_barrier", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_INTEL_usm_storage_classes", "SPV_INTEL_variable_length_array", "SPV_INTEL_vector_compute", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_bit_instructions", "SPV_KHR_device_group", "SPV_KHR_expect_assume", "SPV_KHR_float_controls", "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_fragment_shading_rate", "SPV_KHR_integer_dot_product", "SPV_KHR_linkonce_odr", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_non_semantic_info", "SPV_KHR_physical_storage_buffer", "SPV_KHR_post_depth_coverage", "SPV_KHR_ray_query", "SPV_KHR_ray_tracing", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_clock", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_KHR_workgroup_memory_explicit_layout", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_bindless_texture", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_ray_tracing_motion_blur", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_atomic_float16_add, Extension::kSPV_EXT_shader_atomic_float_add, Extension::kSPV_EXT_shader_atomic_float_min_max, Extension::kSPV_EXT_shader_image_int64, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_arbitrary_precision_fixed_point, Extension::kSPV_INTEL_arbitrary_precision_floating_point, Extension::kSPV_INTEL_arbitrary_precision_integers, Extension::kSPV_INTEL_blocking_pipes, Extension::kSPV_INTEL_debug_module, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_float_controls2, Extension::kSPV_INTEL_fp_fast_math_mode, Extension::kSPV_INTEL_fpga_buffer_location, Extension::kSPV_INTEL_fpga_cluster_attributes, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_accesses, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_inline_assembly, Extension::kSPV_INTEL_io_pipes, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_long_constant_composite, Extension::kSPV_INTEL_loop_fuse, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_memory_access_aliasing, Extension::kSPV_INTEL_optnone, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_split_barrier, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_INTEL_usm_storage_classes, Extension::kSPV_INTEL_variable_length_array, Extension::kSPV_INTEL_vector_compute, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_bit_instructions, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_expect_assume, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_fragment_shader_barycentric, Extension::kSPV_KHR_fragment_shading_rate, Extension::kSPV_KHR_integer_dot_product, Extension::kSPV_KHR_linkonce_odr, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_non_semantic_info, Extension::kSPV_KHR_physical_storage_buffer, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_ray_query, Extension::kSPV_KHR_ray_tracing, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_clock, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_KHR_workgroup_memory_explicit_layout, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_bindless_texture, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_ray_tracing_motion_blur, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
const auto b = std::begin(known_ext_strs);
const auto e = std::end(known_ext_strs);
const auto found = std::equal_range(
@ -612,6 +614,8 @@ const char* CapabilityToString(SpvCapability capability) {
return "AtomicFloat16AddEXT";
case SpvCapabilityDebugInfoModuleINTEL:
return "DebugInfoModuleINTEL";
case SpvCapabilitySplitBarrierINTEL:
return "SplitBarrierINTEL";
case SpvCapabilityMax:
assert(0 && "Attempting to convert SpvCapabilityMax to string");
return "";

View File

@ -47,6 +47,7 @@ kSPV_INTEL_media_block_io,
kSPV_INTEL_memory_access_aliasing,
kSPV_INTEL_optnone,
kSPV_INTEL_shader_integer_functions2,
kSPV_INTEL_split_barrier,
kSPV_INTEL_subgroups,
kSPV_INTEL_unstructured_loop_controls,
kSPV_INTEL_usm_storage_classes,

View File

@ -164,6 +164,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_media_block_io[]
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_memory_access_aliasing[] = {spvtools::Extension::kSPV_INTEL_memory_access_aliasing};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_optnone[] = {spvtools::Extension::kSPV_INTEL_optnone};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_shader_integer_functions2[] = {spvtools::Extension::kSPV_INTEL_shader_integer_functions2};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_split_barrier[] = {spvtools::Extension::kSPV_INTEL_split_barrier};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_subgroups[] = {spvtools::Extension::kSPV_INTEL_subgroups};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_unstructured_loop_controls[] = {spvtools::Extension::kSPV_INTEL_unstructured_loop_controls};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_usm_storage_classes[] = {spvtools::Extension::kSPV_INTEL_usm_storage_classes};
@ -1155,7 +1156,8 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"LongConstantCompositeINTEL", 6089, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_long_constant_composite, {}, 0xffffffffu, 0xffffffffu},
{"OptNoneINTEL", 6094, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_optnone, {}, 0xffffffffu, 0xffffffffu},
{"AtomicFloat16AddEXT", 6095, 0, nullptr, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float16_add, {}, 0xffffffffu, 0xffffffffu},
{"DebugInfoModuleINTEL", 6114, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_debug_module, {}, 0xffffffffu, 0xffffffffu}
{"DebugInfoModuleINTEL", 6114, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_debug_module, {}, 0xffffffffu, 0xffffffffu},
{"SplitBarrierINTEL", 6141, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_split_barrier, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_RayQueryIntersectionEntries[] = {

View File

@ -13,11 +13,23 @@
// limitations under the License.
#include "source/opt/def_use_manager.h"
#include "source/util/make_unique.h"
namespace spvtools {
namespace opt {
namespace analysis {
// Don't compact before we have a reasonable number of ids allocated (~32kb).
static const size_t kCompactThresholdMinTotalIds = (8 * 1024);
// Compact when fewer than this fraction of the storage is used (should be 2^n
// for performance).
static const size_t kCompactThresholdFractionFreeIds = 8;
DefUseManager::DefUseManager() {
use_pool_ = MakeUnique<UseListPool>();
used_id_pool_ = MakeUnique<UsedIdListPool>();
}
void DefUseManager::AnalyzeInstDef(Instruction* inst) {
const uint32_t def_id = inst->result_id();
if (def_id != 0) {
@ -34,15 +46,15 @@ void DefUseManager::AnalyzeInstDef(Instruction* inst) {
}
void DefUseManager::AnalyzeInstUse(Instruction* inst) {
// It might have existed before.
EraseUseRecordsOfOperandIds(inst);
// Create entry for the given instruction. Note that the instruction may
// not have any in-operands. In such cases, we still need a entry for those
// instructions so this manager knows it has seen the instruction later.
auto* used_ids = &inst_to_used_ids_[inst];
if (used_ids->size()) {
EraseUseRecordsOfOperandIds(inst);
used_ids = &inst_to_used_ids_[inst];
}
used_ids->clear(); // It might have existed before.
UsedIdList& used_ids =
inst_to_used_id_.insert({inst, UsedIdList(used_id_pool_.get())})
.first->second;
for (uint32_t i = 0; i < inst->NumOperands(); ++i) {
switch (inst->GetOperand(i).type) {
@ -54,8 +66,17 @@ void DefUseManager::AnalyzeInstUse(Instruction* inst) {
uint32_t use_id = inst->GetSingleWordOperand(i);
Instruction* def = GetDef(use_id);
assert(def && "Definition is not registered.");
id_to_users_.insert(UserEntry{def, inst});
used_ids->push_back(use_id);
// Add to inst's use records
used_ids.push_back(use_id);
// Add to the users, taking care to avoid adding duplicates. We know
// the duplicate for this instruction will always be at the tail.
UseList& list = inst_to_users_.insert({def, UseList(use_pool_.get())})
.first->second;
if (list.empty() || list.back() != inst) {
list.push_back(inst);
}
} break;
default:
break;
@ -94,23 +115,6 @@ const Instruction* DefUseManager::GetDef(uint32_t id) const {
return iter->second;
}
DefUseManager::IdToUsersMap::const_iterator DefUseManager::UsersBegin(
const Instruction* def) const {
return id_to_users_.lower_bound(
UserEntry{const_cast<Instruction*>(def), nullptr});
}
bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter,
const IdToUsersMap::const_iterator& cached_end,
const Instruction* inst) const {
return (iter != cached_end && iter->def == inst);
}
bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter,
const Instruction* inst) const {
return UsersNotEnd(iter, id_to_users_.end(), inst);
}
bool DefUseManager::WhileEachUser(
const Instruction* def, const std::function<bool(Instruction*)>& f) const {
// Ensure that |def| has been registered.
@ -118,9 +122,11 @@ bool DefUseManager::WhileEachUser(
"Definition is not registered.");
if (!def->HasResultId()) return true;
auto end = id_to_users_.end();
for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) {
if (!f(iter->user)) return false;
auto iter = inst_to_users_.find(def);
if (iter != inst_to_users_.end()) {
for (Instruction* user : iter->second) {
if (!f(user)) return false;
}
}
return true;
}
@ -151,14 +157,15 @@ bool DefUseManager::WhileEachUse(
"Definition is not registered.");
if (!def->HasResultId()) return true;
auto end = id_to_users_.end();
for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) {
Instruction* user = iter->user;
for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) {
const Operand& op = user->GetOperand(idx);
if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) {
if (def->result_id() == op.words[0]) {
if (!f(user, idx)) return false;
auto iter = inst_to_users_.find(def);
if (iter != inst_to_users_.end()) {
for (Instruction* user : iter->second) {
for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) {
const Operand& op = user->GetOperand(idx);
if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) {
if (def->result_id() == op.words[0]) {
if (!f(user, idx)) return false;
}
}
}
}
@ -230,17 +237,18 @@ void DefUseManager::AnalyzeDefUse(Module* module) {
}
void DefUseManager::ClearInst(Instruction* inst) {
auto iter = inst_to_used_ids_.find(inst);
if (iter != inst_to_used_ids_.end()) {
if (inst_to_used_id_.find(inst) != inst_to_used_id_.end()) {
EraseUseRecordsOfOperandIds(inst);
if (inst->result_id() != 0) {
// Remove all uses of this inst.
auto users_begin = UsersBegin(inst);
auto end = id_to_users_.end();
auto new_end = users_begin;
for (; UsersNotEnd(new_end, end, inst); ++new_end) {
uint32_t const result_id = inst->result_id();
if (result_id != 0) {
// For each using instruction, remove result_id from their used ids.
auto iter = inst_to_users_.find(inst);
if (iter != inst_to_users_.end()) {
for (Instruction* use : iter->second) {
inst_to_used_id_.at(use).remove_first(result_id);
}
inst_to_users_.erase(iter);
}
id_to_users_.erase(users_begin, new_end);
id_to_def_.erase(inst->result_id());
}
}
@ -249,16 +257,48 @@ void DefUseManager::ClearInst(Instruction* inst) {
void DefUseManager::EraseUseRecordsOfOperandIds(const Instruction* inst) {
// Go through all ids used by this instruction, remove this instruction's
// uses of them.
auto iter = inst_to_used_ids_.find(inst);
if (iter != inst_to_used_ids_.end()) {
for (auto use_id : iter->second) {
id_to_users_.erase(
UserEntry{GetDef(use_id), const_cast<Instruction*>(inst)});
auto iter = inst_to_used_id_.find(inst);
if (iter != inst_to_used_id_.end()) {
const UsedIdList& used_ids = iter->second;
for (uint32_t def_id : used_ids) {
auto def_iter = inst_to_users_.find(GetDef(def_id));
if (def_iter != inst_to_users_.end()) {
def_iter->second.remove_first(const_cast<Instruction*>(inst));
}
}
inst_to_used_id_.erase(inst);
// If we're using only a fraction of the space in used_ids_, compact storage
// to prevent memory usage from being unbounded.
if (used_id_pool_->total_nodes() > kCompactThresholdMinTotalIds &&
used_id_pool_->used_nodes() <
used_id_pool_->total_nodes() / kCompactThresholdFractionFreeIds) {
CompactStorage();
}
inst_to_used_ids_.erase(iter);
}
}
void DefUseManager::CompactStorage() {
CompactUseRecords();
CompactUsedIds();
}
void DefUseManager::CompactUseRecords() {
std::unique_ptr<UseListPool> new_pool = MakeUnique<UseListPool>();
for (auto& iter : inst_to_users_) {
iter.second.move_nodes(new_pool.get());
}
use_pool_ = std::move(new_pool);
}
void DefUseManager::CompactUsedIds() {
std::unique_ptr<UsedIdListPool> new_pool = MakeUnique<UsedIdListPool>();
for (auto& iter : inst_to_used_id_) {
iter.second.move_nodes(new_pool.get());
}
used_id_pool_ = std::move(new_pool);
}
bool CompareAndPrintDifferences(const DefUseManager& lhs,
const DefUseManager& rhs) {
bool same = true;
@ -277,34 +317,52 @@ bool CompareAndPrintDifferences(const DefUseManager& lhs,
same = false;
}
if (lhs.id_to_users_ != rhs.id_to_users_) {
for (auto p : lhs.id_to_users_) {
if (rhs.id_to_users_.count(p) == 0) {
printf("Diff in id_to_users: missing value in rhs\n");
}
for (const auto& l : lhs.inst_to_used_id_) {
std::set<uint32_t> ul, ur;
lhs.ForEachUse(l.first,
[&ul](Instruction*, uint32_t id) { ul.insert(id); });
rhs.ForEachUse(l.first,
[&ur](Instruction*, uint32_t id) { ur.insert(id); });
if (ul.size() != ur.size()) {
printf(
"Diff in inst_to_used_id_: different number of used ids (%zu != %zu)",
ul.size(), ur.size());
same = false;
} else if (ul != ur) {
printf("Diff in inst_to_used_id_: different used ids\n");
same = false;
}
for (auto p : rhs.id_to_users_) {
if (lhs.id_to_users_.count(p) == 0) {
printf("Diff in id_to_users: missing value in lhs\n");
}
}
for (const auto& r : rhs.inst_to_used_id_) {
auto iter_l = lhs.inst_to_used_id_.find(r.first);
if (r.second.empty() &&
!(iter_l == lhs.inst_to_used_id_.end() || iter_l->second.empty())) {
printf("Diff in inst_to_used_id_: unexpected instr in rhs\n");
same = false;
}
same = false;
}
if (lhs.inst_to_used_ids_ != rhs.inst_to_used_ids_) {
for (auto p : lhs.inst_to_used_ids_) {
if (rhs.inst_to_used_ids_.count(p.first) == 0) {
printf("Diff in inst_to_used_ids: missing value in rhs\n");
}
for (const auto& l : lhs.inst_to_users_) {
std::set<Instruction*> ul, ur;
lhs.ForEachUser(l.first, [&ul](Instruction* use) { ul.insert(use); });
rhs.ForEachUser(l.first, [&ur](Instruction* use) { ur.insert(use); });
if (ul.size() != ur.size()) {
printf("Diff in inst_to_users_: different number of users (%zu != %zu)",
ul.size(), ur.size());
same = false;
} else if (ul != ur) {
printf("Diff in inst_to_users_: different users\n");
same = false;
}
}
for (const auto& r : rhs.inst_to_users_) {
auto iter_l = lhs.inst_to_users_.find(r.first);
if (r.second.empty() &&
!(iter_l == lhs.inst_to_users_.end() || iter_l->second.empty())) {
printf("Diff in inst_to_users_: unexpected instr in rhs\n");
same = false;
}
for (auto p : rhs.inst_to_used_ids_) {
if (lhs.inst_to_used_ids_.count(p.first) == 0) {
printf("Diff in inst_to_used_ids: missing value in lhs\n");
}
}
same = false;
}
return same;
}

View File

@ -21,6 +21,7 @@
#include "source/opt/instruction.h"
#include "source/opt/module.h"
#include "source/util/pooled_linked_list.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
@ -49,50 +50,6 @@ inline bool operator<(const Use& lhs, const Use& rhs) {
return lhs.operand_index < rhs.operand_index;
}
// Definition should never be null. User can be null, however, such an entry
// should be used only for searching (e.g. all users of a particular definition)
// and never stored in a container.
struct UserEntry {
Instruction* def;
Instruction* user;
};
inline bool operator==(const UserEntry& lhs, const UserEntry& rhs) {
return lhs.def == rhs.def && lhs.user == rhs.user;
}
// Orders UserEntry for use in associative containers (i.e. less than ordering).
//
// The definition of an UserEntry is treated as the major key and the users as
// the minor key so that all the users of a particular definition are
// consecutive in a container.
//
// A null user always compares less than a real user. This is done to provide
// easy values to search for the beginning of the users of a particular
// definition (i.e. using {def, nullptr}).
struct UserEntryLess {
bool operator()(const UserEntry& lhs, const UserEntry& rhs) const {
// If lhs.def and rhs.def are both null, fall through to checking the
// second entries.
if (!lhs.def && rhs.def) return true;
if (lhs.def && !rhs.def) return false;
// If neither definition is null, then compare unique ids.
if (lhs.def && rhs.def) {
if (lhs.def->unique_id() < rhs.def->unique_id()) return true;
if (rhs.def->unique_id() < lhs.def->unique_id()) return false;
}
// Return false on equality.
if (!lhs.user && !rhs.user) return false;
if (!lhs.user) return true;
if (!rhs.user) return false;
// If neither user is null then compare unique ids.
return lhs.user->unique_id() < rhs.user->unique_id();
}
};
// A class for analyzing and managing defs and uses in an Module.
class DefUseManager {
public:
@ -102,7 +59,7 @@ class DefUseManager {
// will be communicated to the outside via the given message |consumer|. This
// instance only keeps a reference to the |consumer|, so the |consumer| should
// outlive this instance.
DefUseManager(Module* module) { AnalyzeDefUse(module); }
DefUseManager(Module* module) : DefUseManager() { AnalyzeDefUse(module); }
DefUseManager(const DefUseManager&) = delete;
DefUseManager(DefUseManager&&) = delete;
@ -214,35 +171,36 @@ class DefUseManager {
// uses.
void UpdateDefUse(Instruction* inst);
// Compacts any internal storage to save memory.
void CompactStorage();
private:
using IdToUsersMap = std::set<UserEntry, UserEntryLess>;
using InstToUsedIdsMap =
std::unordered_map<const Instruction*, std::vector<uint32_t>>;
using UseList = spvtools::utils::PooledLinkedList<Instruction*>;
using UseListPool = spvtools::utils::PooledLinkedListNodes<Instruction*>;
// Stores linked lists of Instructions using a def.
using InstToUsersMap = std::unordered_map<const Instruction*, UseList>;
// Returns the first location that {|def|, nullptr} could be inserted into the
// users map without violating ordering.
IdToUsersMap::const_iterator UsersBegin(const Instruction* def) const;
using UsedIdList = spvtools::utils::PooledLinkedList<uint32_t>;
using UsedIdListPool = spvtools::utils::PooledLinkedListNodes<uint32_t>;
// Stores mapping from instruction to their UsedIdRange.
using InstToUsedIdMap = std::unordered_map<const Instruction*, UsedIdList>;
// Returns true if |iter| has not reached the end of |def|'s users.
//
// In the first version |iter| is compared against the end of the map for
// validity before other checks. In the second version, |iter| is compared
// against |cached_end| for validity before other checks. This allows caching
// the map's end which is a performance improvement on some platforms.
bool UsersNotEnd(const IdToUsersMap::const_iterator& iter,
const Instruction* def) const;
bool UsersNotEnd(const IdToUsersMap::const_iterator& iter,
const IdToUsersMap::const_iterator& cached_end,
const Instruction* def) const;
DefUseManager();
// Analyzes the defs and uses in the given |module| and populates data
// structures in this class. Does nothing if |module| is nullptr.
void AnalyzeDefUse(Module* module);
IdToDefMap id_to_def_; // Mapping from ids to their definitions
IdToUsersMap id_to_users_; // Mapping from ids to their users
// Mapping from instructions to the ids used in the instruction.
InstToUsedIdsMap inst_to_used_ids_;
// Removes unused entries in used_records_ and used_ids_.
void CompactUseRecords();
void CompactUsedIds();
IdToDefMap id_to_def_; // Mapping from ids to their definitions
InstToUsersMap inst_to_users_; // Map from def to uses.
std::unique_ptr<UseListPool> use_pool_;
std::unique_ptr<UsedIdListPool> used_id_pool_;
InstToUsedIdMap inst_to_used_id_; // Map from instruction to used ids.
};
} // namespace analysis

View File

@ -41,6 +41,8 @@ namespace spvtools {
namespace opt {
void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
set = Analysis(set & ~valid_analyses_);
if (set & kAnalysisDefUse) {
BuildDefUseManager();
}

View File

@ -867,8 +867,7 @@ inline IRContext::Analysis operator|(IRContext::Analysis lhs,
inline IRContext::Analysis& operator|=(IRContext::Analysis& lhs,
IRContext::Analysis rhs) {
lhs = static_cast<IRContext::Analysis>(static_cast<int>(lhs) |
static_cast<int>(rhs));
lhs = lhs | rhs;
return lhs;
}

View File

@ -189,7 +189,8 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
module_->SetMemoryModel(std::move(spv_inst));
} else if (opcode == SpvOpEntryPoint) {
module_->AddEntryPoint(std::move(spv_inst));
} else if (opcode == SpvOpExecutionMode) {
} else if (opcode == SpvOpExecutionMode ||
opcode == SpvOpExecutionModeId) {
module_->AddExecutionMode(std::move(spv_inst));
} else if (IsDebug1Inst(opcode)) {
module_->AddDebug1Inst(std::move(spv_inst));

View File

@ -431,6 +431,7 @@ bool MergeReturnPass::BreakFromConstruct(
std::list<BasicBlock*>* order, Instruction* break_merge_inst) {
// Make sure the CFG is build here. If we don't then it becomes very hard
// to know which new blocks need to be updated.
context()->InvalidateAnalyses(IRContext::kAnalysisCFG);
context()->BuildInvalidAnalyses(IRContext::kAnalysisCFG);
// When predicating, be aware of whether this block is a header block, a

View File

@ -21,6 +21,7 @@
#include <string>
#include <unordered_set>
#include "source/util/hash_combine.h"
#include "source/util/make_unique.h"
#include "spirv/unified1/spirv.h"
@ -28,6 +29,7 @@ namespace spvtools {
namespace opt {
namespace analysis {
using spvtools::utils::hash_combine;
using U32VecVec = std::vector<std::vector<uint32_t>>;
namespace {
@ -182,23 +184,26 @@ bool Type::operator==(const Type& other) const {
}
}
void Type::GetHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const {
if (!seen->insert(this).second) {
return;
size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const {
// Linear search through a dense, cache coherent vector is faster than O(log
// n) search in a complex data structure (eg std::set) for the generally small
// number of nodes. It also skips the overhead of an new/delete per Type
// (when inserting/removing from a set).
if (std::find(seen->begin(), seen->end(), this) != seen->end()) {
return hash;
}
words->push_back(kind_);
seen->push_back(this);
hash = hash_combine(hash, uint32_t(kind_));
for (const auto& d : decorations_) {
for (auto w : d) {
words->push_back(w);
}
hash = hash_combine(hash, d);
}
switch (kind_) {
#define DeclareKindCase(type) \
case k##type: \
As##type()->GetExtraHashWords(words, seen); \
#define DeclareKindCase(type) \
case k##type: \
hash = As##type()->ComputeExtraStateHash(hash, seen); \
break
DeclareKindCase(Void);
DeclareKindCase(Bool);
@ -232,18 +237,13 @@ void Type::GetHashWords(std::vector<uint32_t>* words,
break;
}
seen->erase(this);
seen->pop_back();
return hash;
}
size_t Type::HashValue() const {
std::u32string h;
std::vector<uint32_t> words;
GetHashWords(&words);
for (auto w : words) {
h.push_back(w);
}
return std::hash<std::u32string>()(h);
SeenTypes seen;
return ComputeHashValue(0, &seen);
}
bool Integer::IsSameImpl(const Type* that, IsSameCache*) const {
@ -258,10 +258,8 @@ std::string Integer::str() const {
return oss.str();
}
void Integer::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>*) const {
words->push_back(width_);
words->push_back(signed_);
size_t Integer::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
return hash_combine(hash, width_, signed_);
}
bool Float::IsSameImpl(const Type* that, IsSameCache*) const {
@ -275,9 +273,8 @@ std::string Float::str() const {
return oss.str();
}
void Float::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>*) const {
words->push_back(width_);
size_t Float::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
return hash_combine(hash, width_);
}
Vector::Vector(const Type* type, uint32_t count)
@ -299,10 +296,11 @@ std::string Vector::str() const {
return oss.str();
}
void Vector::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const {
element_type_->GetHashWords(words, seen);
words->push_back(count_);
size_t Vector::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
// prefer form that doesn't require push/pop from stack: add state and
// make tail call.
hash = hash_combine(hash, count_);
return element_type_->ComputeHashValue(hash, seen);
}
Matrix::Matrix(const Type* type, uint32_t count)
@ -324,10 +322,9 @@ std::string Matrix::str() const {
return oss.str();
}
void Matrix::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const {
element_type_->GetHashWords(words, seen);
words->push_back(count_);
size_t Matrix::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
hash = hash_combine(hash, count_);
return element_type_->ComputeHashValue(hash, seen);
}
Image::Image(Type* type, SpvDim dimen, uint32_t d, bool array, bool multisample,
@ -362,16 +359,10 @@ std::string Image::str() const {
return oss.str();
}
void Image::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const {
sampled_type_->GetHashWords(words, seen);
words->push_back(dim_);
words->push_back(depth_);
words->push_back(arrayed_);
words->push_back(ms_);
words->push_back(sampled_);
words->push_back(format_);
words->push_back(access_qualifier_);
size_t Image::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
hash = hash_combine(hash, uint32_t(dim_), depth_, arrayed_, ms_, sampled_,
uint32_t(format_), uint32_t(access_qualifier_));
return sampled_type_->ComputeHashValue(hash, seen);
}
bool SampledImage::IsSameImpl(const Type* that, IsSameCache* seen) const {
@ -387,9 +378,8 @@ std::string SampledImage::str() const {
return oss.str();
}
void SampledImage::GetExtraHashWords(
std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
image_type_->GetHashWords(words, seen);
size_t SampledImage::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
return image_type_->ComputeHashValue(hash, seen);
}
Array::Array(const Type* type, const Array::LengthInfo& length_info_arg)
@ -422,11 +412,9 @@ std::string Array::str() const {
return oss.str();
}
void Array::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const {
element_type_->GetHashWords(words, seen);
words->insert(words->end(), length_info_.words.begin(),
length_info_.words.end());
size_t Array::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
hash = hash_combine(hash, length_info_.words);
return element_type_->ComputeHashValue(hash, seen);
}
void Array::ReplaceElementType(const Type* type) { element_type_ = type; }
@ -449,9 +437,8 @@ std::string RuntimeArray::str() const {
return oss.str();
}
void RuntimeArray::GetExtraHashWords(
std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
element_type_->GetHashWords(words, seen);
size_t RuntimeArray::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
return element_type_->ComputeHashValue(hash, seen);
}
void RuntimeArray::ReplaceElementType(const Type* type) {
@ -508,19 +495,14 @@ std::string Struct::str() const {
return oss.str();
}
void Struct::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const {
size_t Struct::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
for (auto* t : element_types_) {
t->GetHashWords(words, seen);
hash = t->ComputeHashValue(hash, seen);
}
for (const auto& pair : element_decorations_) {
words->push_back(pair.first);
for (const auto& d : pair.second) {
for (auto w : d) {
words->push_back(w);
}
}
hash = hash_combine(hash, pair.first, pair.second);
}
return hash;
}
bool Opaque::IsSameImpl(const Type* that, IsSameCache*) const {
@ -535,11 +517,8 @@ std::string Opaque::str() const {
return oss.str();
}
void Opaque::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>*) const {
for (auto c : name_) {
words->push_back(static_cast<char32_t>(c));
}
size_t Opaque::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
return hash_combine(hash, name_);
}
Pointer::Pointer(const Type* type, SpvStorageClass sc)
@ -568,10 +547,9 @@ std::string Pointer::str() const {
return os.str();
}
void Pointer::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const {
pointee_type_->GetHashWords(words, seen);
words->push_back(storage_class_);
size_t Pointer::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
hash = hash_combine(hash, uint32_t(storage_class_));
return pointee_type_->ComputeHashValue(hash, seen);
}
void Pointer::SetPointeeType(const Type* type) { pointee_type_ = type; }
@ -605,12 +583,11 @@ std::string Function::str() const {
return oss.str();
}
void Function::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const {
return_type_->GetHashWords(words, seen);
size_t Function::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
for (const auto* t : param_types_) {
t->GetHashWords(words, seen);
hash = t->ComputeHashValue(hash, seen);
}
return return_type_->ComputeHashValue(hash, seen);
}
void Function::SetReturnType(const Type* type) { return_type_ = type; }
@ -627,9 +604,8 @@ std::string Pipe::str() const {
return oss.str();
}
void Pipe::GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>*) const {
words->push_back(access_qualifier_);
size_t Pipe::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
return hash_combine(hash, uint32_t(access_qualifier_));
}
bool ForwardPointer::IsSameImpl(const Type* that, IsSameCache*) const {
@ -652,11 +628,11 @@ std::string ForwardPointer::str() const {
return oss.str();
}
void ForwardPointer::GetExtraHashWords(
std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
words->push_back(target_id_);
words->push_back(storage_class_);
if (pointer_) pointer_->GetHashWords(words, seen);
size_t ForwardPointer::ComputeExtraStateHash(size_t hash,
SeenTypes* seen) const {
hash = hash_combine(hash, target_id_, uint32_t(storage_class_));
if (pointer_) hash = pointer_->ComputeHashValue(hash, seen);
return hash;
}
CooperativeMatrixNV::CooperativeMatrixNV(const Type* type, const uint32_t scope,
@ -680,12 +656,10 @@ std::string CooperativeMatrixNV::str() const {
return oss.str();
}
void CooperativeMatrixNV::GetExtraHashWords(
std::vector<uint32_t>* words, std::unordered_set<const Type*>* pSet) const {
component_type_->GetHashWords(words, pSet);
words->push_back(scope_id_);
words->push_back(rows_id_);
words->push_back(columns_id_);
size_t CooperativeMatrixNV::ComputeExtraStateHash(size_t hash,
SeenTypes* seen) const {
hash = hash_combine(hash, scope_id_, rows_id_, columns_id_);
return component_type_->ComputeHashValue(hash, seen);
}
bool CooperativeMatrixNV::IsSameImpl(const Type* that,

View File

@ -28,6 +28,7 @@
#include "source/latest_version_spirv_header.h"
#include "source/opt/instruction.h"
#include "source/util/small_vector.h"
#include "spirv-tools/libspirv.h"
namespace spvtools {
@ -67,6 +68,8 @@ class Type {
public:
typedef std::set<std::pair<const Pointer*, const Pointer*>> IsSameCache;
using SeenTypes = spvtools::utils::SmallVector<const Type*, 8>;
// Available subtypes.
//
// When adding a new derived class of Type, please add an entry to the enum.
@ -155,21 +158,7 @@ class Type {
// Returns the hash value of this type.
size_t HashValue() const;
// Adds the necessary words to compute a hash value of this type to |words|.
void GetHashWords(std::vector<uint32_t>* words) const {
std::unordered_set<const Type*> seen;
GetHashWords(words, &seen);
}
// Adds the necessary words to compute a hash value of this type to |words|.
void GetHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* seen) const;
// Adds necessary extra words for a subtype to calculate a hash value into
// |words|.
virtual void GetExtraHashWords(
std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const = 0;
size_t ComputeHashValue(size_t hash, SeenTypes* seen) const;
// A bunch of methods for casting this type to a given type. Returns this if the
// cast can be done, nullptr otherwise.
@ -205,6 +194,10 @@ class Type {
DeclareCastMethod(RayQueryKHR)
#undef DeclareCastMethod
protected:
// Add any type-specific state to |hash| and returns new hash.
virtual size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const = 0;
protected:
// Decorations attached to this type. Each decoration is encoded as a vector
// of uint32_t numbers. The first uint32_t number is the decoration value,
@ -233,8 +226,7 @@ class Integer : public Type {
uint32_t width() const { return width_; }
bool IsSigned() const { return signed_; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -254,8 +246,7 @@ class Float : public Type {
const Float* AsFloat() const override { return this; }
uint32_t width() const { return width_; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -275,8 +266,7 @@ class Vector : public Type {
Vector* AsVector() override { return this; }
const Vector* AsVector() const override { return this; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -297,8 +287,7 @@ class Matrix : public Type {
Matrix* AsMatrix() override { return this; }
const Matrix* AsMatrix() const override { return this; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -328,8 +317,7 @@ class Image : public Type {
SpvImageFormat format() const { return format_; }
SpvAccessQualifier access_qualifier() const { return access_qualifier_; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -356,8 +344,7 @@ class SampledImage : public Type {
const Type* image_type() const { return image_type_; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -400,8 +387,7 @@ class Array : public Type {
Array* AsArray() override { return this; }
const Array* AsArray() const override { return this; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void ReplaceElementType(const Type* element_type);
@ -423,8 +409,7 @@ class RuntimeArray : public Type {
RuntimeArray* AsRuntimeArray() override { return this; }
const RuntimeArray* AsRuntimeArray() const override { return this; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void ReplaceElementType(const Type* element_type);
@ -460,8 +445,7 @@ class Struct : public Type {
Struct* AsStruct() override { return this; }
const Struct* AsStruct() const override { return this; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -492,8 +476,7 @@ class Opaque : public Type {
const std::string& name() const { return name_; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -513,8 +496,7 @@ class Pointer : public Type {
Pointer* AsPointer() override { return this; }
const Pointer* AsPointer() const override { return this; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void SetPointeeType(const Type* type);
@ -540,8 +522,7 @@ class Function : public Type {
const std::vector<const Type*>& param_types() const { return param_types_; }
std::vector<const Type*>& param_types() { return param_types_; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>*) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
void SetReturnType(const Type* type);
@ -565,8 +546,7 @@ class Pipe : public Type {
SpvAccessQualifier access_qualifier() const { return access_qualifier_; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -593,8 +573,7 @@ class ForwardPointer : public Type {
ForwardPointer* AsForwardPointer() override { return this; }
const ForwardPointer* AsForwardPointer() const override { return this; }
void GetExtraHashWords(std::vector<uint32_t>* words,
std::unordered_set<const Type*>* pSet) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
private:
bool IsSameImpl(const Type* that, IsSameCache*) const override;
@ -617,8 +596,7 @@ class CooperativeMatrixNV : public Type {
return this;
}
void GetExtraHashWords(std::vector<uint32_t>*,
std::unordered_set<const Type*>*) const override;
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
const Type* component_type() const { return component_type_; }
uint32_t scope_id() const { return scope_id_; }
@ -634,24 +612,25 @@ class CooperativeMatrixNV : public Type {
const uint32_t columns_id_;
};
#define DefineParameterlessType(type, name) \
class type : public Type { \
public: \
type() : Type(k##type) {} \
type(const type&) = default; \
\
std::string str() const override { return #name; } \
\
type* As##type() override { return this; } \
const type* As##type() const override { return this; } \
\
void GetExtraHashWords(std::vector<uint32_t>*, \
std::unordered_set<const Type*>*) const override {} \
\
private: \
bool IsSameImpl(const Type* that, IsSameCache*) const override { \
return that->As##type() && HasSameDecorations(that); \
} \
#define DefineParameterlessType(type, name) \
class type : public Type { \
public: \
type() : Type(k##type) {} \
type(const type&) = default; \
\
std::string str() const override { return #name; } \
\
type* As##type() override { return this; } \
const type* As##type() const override { return this; } \
\
size_t ComputeExtraStateHash(size_t hash, SeenTypes*) const override { \
return hash; \
} \
\
private: \
bool IsSameImpl(const Type* that, IsSameCache*) const override { \
return that->As##type() && HasSameDecorations(that); \
} \
}
DefineParameterlessType(Void, void);
DefineParameterlessType(Bool, bool);

View File

@ -0,0 +1,53 @@
// Copyright (c) 2022 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_UTIL_HASH_COMBINE_H_
#define SOURCE_UTIL_HASH_COMBINE_H_
#include <cstddef>
#include <functional>
#include <vector>
namespace spvtools {
namespace utils {
// Helpers for incrementally computing hashes.
// For reference, see
// http://open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
template <typename T>
inline size_t hash_combine(std::size_t seed, const T& val) {
return seed ^ (std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
template <typename T>
inline size_t hash_combine(std::size_t hash, const std::vector<T>& vals) {
for (const T& val : vals) {
hash = hash_combine(hash, val);
}
return hash;
}
inline size_t hash_combine(std::size_t hash) { return hash; }
template <typename T, typename... Types>
inline size_t hash_combine(std::size_t hash, const T& val,
const Types&... args) {
return hash_combine(hash_combine(hash, val), args...);
}
} // namespace utils
} // namespace spvtools
#endif // SOURCE_UTIL_HASH_COMBINE_H_

View File

@ -0,0 +1,236 @@
// Copyright (c) 2021 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_UTIL_POOLED_LINKED_LIST_H_
#define SOURCE_UTIL_POOLED_LINKED_LIST_H_
#include <cstdint>
#include <vector>
namespace spvtools {
namespace utils {
// Shared storage of nodes for PooledLinkedList.
template <typename T>
class PooledLinkedListNodes {
public:
struct Node {
Node(T e, int32_t n = -1) : element(e), next(n) {}
T element = {};
int32_t next = -1;
};
PooledLinkedListNodes() = default;
PooledLinkedListNodes(const PooledLinkedListNodes&) = delete;
PooledLinkedListNodes& operator=(const PooledLinkedListNodes&) = delete;
PooledLinkedListNodes(PooledLinkedListNodes&& that) {
*this = std::move(that);
}
PooledLinkedListNodes& operator=(PooledLinkedListNodes&& that) {
vec_ = std::move(that.vec_);
free_nodes_ = that.free_nodes_;
return *this;
}
size_t total_nodes() { return vec_.size(); }
size_t free_nodes() { return free_nodes_; }
size_t used_nodes() { return total_nodes() - free_nodes(); }
private:
template <typename ListT>
friend class PooledLinkedList;
Node& at(int32_t index) { return vec_[index]; }
const Node& at(int32_t index) const { return vec_[index]; }
int32_t insert(T element) {
int32_t index = int32_t(vec_.size());
vec_.emplace_back(element);
return index;
}
std::vector<Node> vec_;
size_t free_nodes_ = 0;
};
// Implements a linked-list where list nodes come from a shared pool. This is
// meant to be used in scenarios where it is desirable to avoid many small
// allocations.
//
// Instead of pointers, the list uses indices to allow the underlying storage
// to be modified without needing to modify the list. When removing elements
// from the list, nodes are not deleted or recycled: to reclaim unused space,
// perform a sequence of |move_nodes| operations into a temporary pool, which
// then is moved into the old pool.
//
// This does *not* attempt to implement a full stl-compatible interface.
template <typename T>
class PooledLinkedList {
public:
using NodePool = PooledLinkedListNodes<T>;
using Node = typename NodePool::Node;
PooledLinkedList() = delete;
PooledLinkedList(NodePool* nodes) : nodes_(nodes) {}
// Shared iterator implementation (for iterator and const_iterator).
template <typename ElementT, typename PoolT>
class iterator_base {
public:
iterator_base(const iterator_base& i)
: nodes_(i.nodes_), index_(i.index_) {}
iterator_base& operator++() {
index_ = nodes_->at(index_).next;
return *this;
}
iterator_base& operator=(const iterator_base& i) {
nodes_ = i.nodes_;
index_ = i.index_;
return *this;
}
ElementT& operator*() const { return nodes_->at(index_).element; }
ElementT* operator->() const { return &nodes_->at(index_).element; }
friend inline bool operator==(const iterator_base& lhs,
const iterator_base& rhs) {
return lhs.nodes_ == rhs.nodes_ && lhs.index_ == rhs.index_;
}
friend inline bool operator!=(const iterator_base& lhs,
const iterator_base& rhs) {
return lhs.nodes_ != rhs.nodes_ || lhs.index_ != rhs.index_;
}
// Define standard iterator types needs so this class can be
// used with <algorithms>.
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = ElementT;
using pointer = ElementT*;
using const_pointer = const ElementT*;
using reference = ElementT&;
using const_reference = const ElementT&;
using size_type = size_t;
private:
friend PooledLinkedList;
iterator_base(PoolT* pool, int32_t index) : nodes_(pool), index_(index) {}
PoolT* nodes_;
int32_t index_ = -1;
};
using iterator = iterator_base<T, std::vector<Node>>;
using const_iterator = iterator_base<const T, const std::vector<Node>>;
bool empty() const { return head_ == -1; }
T& front() { return nodes_->at(head_).element; }
T& back() { return nodes_->at(tail_).element; }
const T& front() const { return nodes_->at(head_).element; }
const T& back() const { return nodes_->at(tail_).element; }
iterator begin() { return iterator(&nodes_->vec_, head_); }
iterator end() { return iterator(&nodes_->vec_, -1); }
const_iterator begin() const { return const_iterator(&nodes_->vec_, head_); }
const_iterator end() const { return const_iterator(&nodes_->vec_, -1); }
// Inserts |element| at the back of the list.
void push_back(T element) {
int32_t new_tail = nodes_->insert(element);
if (head_ == -1) {
head_ = new_tail;
tail_ = new_tail;
} else {
nodes_->at(tail_).next = new_tail;
tail_ = new_tail;
}
}
// Removes the first occurrence of |element| from the list.
// Returns if |element| was removed.
bool remove_first(T element) {
int32_t* prev_next = &head_;
for (int32_t prev_index = -1, index = head_; index != -1; /**/) {
auto& node = nodes_->at(index);
if (node.element == element) {
// Snip from of the list, optionally fixing up tail pointer.
if (tail_ == index) {
assert(node.next == -1);
tail_ = prev_index;
}
*prev_next = node.next;
nodes_->free_nodes_++;
return true;
} else {
prev_next = &node.next;
}
prev_index = index;
index = node.next;
}
return false;
}
// Returns the PooledLinkedListNodes that owns this list's nodes.
NodePool* pool() { return nodes_; }
// Moves the nodes in this list into |new_pool|, providing a way to compact
// storage and reclaim unused space.
//
// Upon completing a sequence of |move_nodes| calls, you must ensure you
// retain ownership of the new storage your lists point to. Example usage:
//
// unique_ptr<NodePool> new_pool = ...;
// for (PooledLinkedList& list : lists) {
// list.move_to(new_pool);
// }
// my_pool_ = std::move(new_pool);
void move_nodes(NodePool* new_pool) {
// Be sure to construct the list in the same order, instead of simply
// doing a sequence of push_backs.
int32_t prev_entry = -1;
int32_t nodes_freed = 0;
for (int32_t index = head_; index != -1; nodes_freed++) {
const auto& node = nodes_->at(index);
int32_t this_entry = new_pool->insert(node.element);
index = node.next;
if (prev_entry == -1) {
head_ = this_entry;
} else {
new_pool->at(prev_entry).next = this_entry;
}
prev_entry = this_entry;
}
tail_ = prev_entry;
// Update our old pool's free count, now we're a member of the new pool.
nodes_->free_nodes_ += nodes_freed;
nodes_ = new_pool;
}
private:
NodePool* nodes_;
int32_t head_ = -1;
int32_t tail_ = -1;
};
} // namespace utils
} // namespace spvtools
#endif // SOURCE_UTIL_POOLED_LINKED_LIST_H_

View File

@ -333,6 +333,15 @@ class SmallVector {
++size_;
}
void pop_back() {
if (large_data_) {
large_data_->pop_back();
} else {
--size_;
small_data_[size_].~T();
}
}
template <class InputIt>
iterator insert(iterator pos, InputIt first, InputIt last) {
size_t element_idx = (pos - begin());

View File

@ -147,6 +147,24 @@ bool DoesDebugInfoOperandMatchExpectation(
return true;
}
// Overload for NonSemanticShaderDebugInfo100Instructions.
bool DoesDebugInfoOperandMatchExpectation(
const ValidationState_t& _,
const std::function<bool(NonSemanticShaderDebugInfo100Instructions)>&
expectation,
const Instruction* inst, uint32_t word_index) {
if (inst->words().size() <= word_index) return false;
auto* debug_inst = _.FindDef(inst->word(word_index));
if (debug_inst->opcode() != SpvOpExtInst ||
(debug_inst->ext_inst_type() !=
SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) ||
!expectation(
NonSemanticShaderDebugInfo100Instructions(debug_inst->word(4)))) {
return false;
}
return true;
}
// Check that the operand of a debug info instruction |inst| at |word_index|
// is a result id of an debug info instruction whose debug instruction type
// is |expected_debug_inst|.
@ -223,6 +241,18 @@ spv_result_t ValidateOperandDebugType(
const Instruction* inst, uint32_t word_index,
const std::function<std::string()>& ext_inst_name,
bool allow_template_param) {
// Check for NonSemanticShaderDebugInfo100 specific types.
if (inst->ext_inst_type() ==
SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
std::function<bool(NonSemanticShaderDebugInfo100Instructions)> expectation =
[](NonSemanticShaderDebugInfo100Instructions dbg_inst) {
return dbg_inst == NonSemanticShaderDebugInfo100DebugTypeMatrix;
};
if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
return SPV_SUCCESS;
}
// Check for common types.
std::function<bool(CommonDebugInfoInstructions)> expectation =
[&allow_template_param](CommonDebugInfoInstructions dbg_inst) {
if (allow_template_param &&
@ -2719,6 +2749,86 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
auto num_words = inst->words().size();
// Handle any non-common NonSemanticShaderDebugInfo instructions.
if (vulkanDebugInfo) {
const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
switch (ext_inst_key) {
// The following block of instructions will be handled by the common
// validation.
case NonSemanticShaderDebugInfo100DebugInfoNone:
case NonSemanticShaderDebugInfo100DebugCompilationUnit:
case NonSemanticShaderDebugInfo100DebugTypeBasic:
case NonSemanticShaderDebugInfo100DebugTypePointer:
case NonSemanticShaderDebugInfo100DebugTypeQualifier:
case NonSemanticShaderDebugInfo100DebugTypeArray:
case NonSemanticShaderDebugInfo100DebugTypeVector:
case NonSemanticShaderDebugInfo100DebugTypedef:
case NonSemanticShaderDebugInfo100DebugTypeFunction:
case NonSemanticShaderDebugInfo100DebugTypeEnum:
case NonSemanticShaderDebugInfo100DebugTypeComposite:
case NonSemanticShaderDebugInfo100DebugTypeMember:
case NonSemanticShaderDebugInfo100DebugTypeInheritance:
case NonSemanticShaderDebugInfo100DebugTypePtrToMember:
case NonSemanticShaderDebugInfo100DebugTypeTemplate:
case NonSemanticShaderDebugInfo100DebugTypeTemplateParameter:
case NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter:
case NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack:
case NonSemanticShaderDebugInfo100DebugGlobalVariable:
case NonSemanticShaderDebugInfo100DebugFunctionDeclaration:
case NonSemanticShaderDebugInfo100DebugFunction:
case NonSemanticShaderDebugInfo100DebugLexicalBlock:
case NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator:
case NonSemanticShaderDebugInfo100DebugScope:
case NonSemanticShaderDebugInfo100DebugNoScope:
case NonSemanticShaderDebugInfo100DebugInlinedAt:
case NonSemanticShaderDebugInfo100DebugLocalVariable:
case NonSemanticShaderDebugInfo100DebugInlinedVariable:
case NonSemanticShaderDebugInfo100DebugDeclare:
case NonSemanticShaderDebugInfo100DebugValue:
case NonSemanticShaderDebugInfo100DebugOperation:
case NonSemanticShaderDebugInfo100DebugExpression:
case NonSemanticShaderDebugInfo100DebugMacroDef:
case NonSemanticShaderDebugInfo100DebugMacroUndef:
case NonSemanticShaderDebugInfo100DebugImportedEntity:
case NonSemanticShaderDebugInfo100DebugSource:
break;
case NonSemanticShaderDebugInfo100DebugTypeMatrix: {
CHECK_DEBUG_OPERAND("Vector Type", CommonDebugInfoDebugTypeVector, 5);
CHECK_CONST_UINT_OPERAND("Vector Count", 6);
uint32_t vector_count = inst->word(6);
uint64_t const_val;
if (!_.GetConstantValUint64(vector_count, &const_val)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< ext_inst_name()
<< ": Vector Count must be 32-bit integer OpConstant";
}
vector_count = const_val & 0xffffffff;
if (!vector_count || vector_count > 4) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< ext_inst_name() << ": Vector Count must be positive "
<< "integer less than or equal to 4";
}
break;
}
// TODO: Add validation rules for remaining cases as well.
case NonSemanticShaderDebugInfo100DebugFunctionDefinition:
case NonSemanticShaderDebugInfo100DebugSourceContinued:
case NonSemanticShaderDebugInfo100DebugLine:
case NonSemanticShaderDebugInfo100DebugNoLine:
case NonSemanticShaderDebugInfo100DebugBuildIdentifier:
case NonSemanticShaderDebugInfo100DebugStoragePath:
case NonSemanticShaderDebugInfo100DebugEntryPoint:
break;
case NonSemanticShaderDebugInfo100InstructionsMax:
assert(0);
break;
}
}
// Handle any non-common OpenCL insts, then common
if (ext_inst_type != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
OpenCLDebugInfo100Instructions(ext_inst_index) !=

View File

@ -596,23 +596,23 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
}
}
}
}
// Vulkan Appendix A: Check that if contains initializer, then
// storage class is Output, Private, or Function.
if (inst->operands().size() > 3 && storage_class != SpvStorageClassOutput &&
storage_class != SpvStorageClassPrivate &&
storage_class != SpvStorageClassFunction) {
if (spvIsVulkanEnv(_.context()->target_env)) {
// Initializers in Vulkan are only allowed in some storage clases
if (inst->operands().size() > 3) {
if (storage_class == SpvStorageClassWorkgroup) {
auto init_id = inst->GetOperandAs<uint32_t>(3);
auto init = _.FindDef(init_id);
if (init->opcode() != SpvOpConstantNull) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Variable initializers in Workgroup storage class are "
"limited to OpConstantNull";
<< _.VkErrorID(4734) << "OpVariable, <id> '"
<< _.getIdName(inst->id())
<< "', initializers are limited to OpConstantNull in "
"Workgroup "
"storage class";
}
} else {
} else if (storage_class != SpvStorageClassOutput &&
storage_class != SpvStorageClassPrivate &&
storage_class != SpvStorageClassFunction) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< _.VkErrorID(4651) << "OpVariable, <id> '"
<< _.getIdName(inst->id())

View File

@ -1882,6 +1882,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04732);
case 4733:
return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733);
case 4734:
return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04734);
case 4780:
return VUID_WRAP(VUID-StandaloneSpirv-Result-04780);
case 4915: