Updated spirv-tools.

This commit is contained in:
Бранимир Караџић
2023-01-14 18:27:08 -08:00
parent 41c35878a7
commit 2d52b5f9af
232 changed files with 12089 additions and 9369 deletions

View File

@@ -1 +1 @@
"v2022.5-dev", "SPIRV-Tools v2022.5-dev 01f246880b501c751d62ad543d886e08bfa756b5"
"v2022.5-dev", "SPIRV-Tools v2022.5-dev 466c6a4e95f6c2ebd61040d6fe2f6418e45b7e20"

File diff suppressed because it is too large Load Diff

View File

@@ -78,6 +78,10 @@ const char* ExtensionToString(Extension extension) {
return "SPV_INTEL_fpga_buffer_location";
case Extension::kSPV_INTEL_fpga_cluster_attributes:
return "SPV_INTEL_fpga_cluster_attributes";
case Extension::kSPV_INTEL_fpga_dsp_control:
return "SPV_INTEL_fpga_dsp_control";
case Extension::kSPV_INTEL_fpga_invocation_pipelining_attributes:
return "SPV_INTEL_fpga_invocation_pipelining_attributes";
case Extension::kSPV_INTEL_fpga_loop_controls:
return "SPV_INTEL_fpga_loop_controls";
case Extension::kSPV_INTEL_fpga_memory_accesses:
@@ -104,6 +108,8 @@ const char* ExtensionToString(Extension extension) {
return "SPV_INTEL_memory_access_aliasing";
case Extension::kSPV_INTEL_optnone:
return "SPV_INTEL_optnone";
case Extension::kSPV_INTEL_runtime_aligned:
return "SPV_INTEL_runtime_aligned";
case Extension::kSPV_INTEL_shader_integer_functions2:
return "SPV_INTEL_shader_integer_functions2";
case Extension::kSPV_INTEL_split_barrier:
@@ -202,6 +208,8 @@ const char* ExtensionToString(Extension extension) {
return "SPV_NV_sample_mask_override_coverage";
case Extension::kSPV_NV_shader_image_footprint:
return "SPV_NV_shader_image_footprint";
case Extension::kSPV_NV_shader_invocation_reorder:
return "SPV_NV_shader_invocation_reorder";
case Extension::kSPV_NV_shader_sm_builtins:
return "SPV_NV_shader_sm_builtins";
case Extension::kSPV_NV_shader_subgroup_partitioned:
@@ -221,8 +229,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_early_and_late_fragment_tests", "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_ARM_core_builtins", "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_mesh_shader", "SPV_EXT_opacity_micromap", "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_cull_mask", "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_rotate", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_uniform_group_instructions", "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_early_and_late_fragment_tests, 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_ARM_core_builtins, 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_mesh_shader, Extension::kSPV_EXT_opacity_micromap, 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_cull_mask, 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_rotate, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_uniform_group_instructions, 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_early_and_late_fragment_tests", "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_ARM_core_builtins", "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_mesh_shader", "SPV_EXT_opacity_micromap", "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_dsp_control", "SPV_INTEL_fpga_invocation_pipelining_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_runtime_aligned", "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_cull_mask", "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_rotate", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_uniform_group_instructions", "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_invocation_reorder", "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_early_and_late_fragment_tests, 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_ARM_core_builtins, 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_mesh_shader, Extension::kSPV_EXT_opacity_micromap, 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_dsp_control, Extension::kSPV_INTEL_fpga_invocation_pipelining_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_runtime_aligned, 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_cull_mask, 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_rotate, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_uniform_group_instructions, 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_invocation_reorder, 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(
@@ -236,414 +244,422 @@ const char* ExtensionToString(Extension extension) {
}
const char* CapabilityToString(SpvCapability capability) {
const char* CapabilityToString(spv::Capability capability) {
switch (capability) {
case SpvCapabilityMatrix:
case spv::Capability::Matrix:
return "Matrix";
case SpvCapabilityShader:
case spv::Capability::Shader:
return "Shader";
case SpvCapabilityGeometry:
case spv::Capability::Geometry:
return "Geometry";
case SpvCapabilityTessellation:
case spv::Capability::Tessellation:
return "Tessellation";
case SpvCapabilityAddresses:
case spv::Capability::Addresses:
return "Addresses";
case SpvCapabilityLinkage:
case spv::Capability::Linkage:
return "Linkage";
case SpvCapabilityKernel:
case spv::Capability::Kernel:
return "Kernel";
case SpvCapabilityVector16:
case spv::Capability::Vector16:
return "Vector16";
case SpvCapabilityFloat16Buffer:
case spv::Capability::Float16Buffer:
return "Float16Buffer";
case SpvCapabilityFloat16:
case spv::Capability::Float16:
return "Float16";
case SpvCapabilityFloat64:
case spv::Capability::Float64:
return "Float64";
case SpvCapabilityInt64:
case spv::Capability::Int64:
return "Int64";
case SpvCapabilityInt64Atomics:
case spv::Capability::Int64Atomics:
return "Int64Atomics";
case SpvCapabilityImageBasic:
case spv::Capability::ImageBasic:
return "ImageBasic";
case SpvCapabilityImageReadWrite:
case spv::Capability::ImageReadWrite:
return "ImageReadWrite";
case SpvCapabilityImageMipmap:
case spv::Capability::ImageMipmap:
return "ImageMipmap";
case SpvCapabilityPipes:
case spv::Capability::Pipes:
return "Pipes";
case SpvCapabilityGroups:
case spv::Capability::Groups:
return "Groups";
case SpvCapabilityDeviceEnqueue:
case spv::Capability::DeviceEnqueue:
return "DeviceEnqueue";
case SpvCapabilityLiteralSampler:
case spv::Capability::LiteralSampler:
return "LiteralSampler";
case SpvCapabilityAtomicStorage:
case spv::Capability::AtomicStorage:
return "AtomicStorage";
case SpvCapabilityInt16:
case spv::Capability::Int16:
return "Int16";
case SpvCapabilityTessellationPointSize:
case spv::Capability::TessellationPointSize:
return "TessellationPointSize";
case SpvCapabilityGeometryPointSize:
case spv::Capability::GeometryPointSize:
return "GeometryPointSize";
case SpvCapabilityImageGatherExtended:
case spv::Capability::ImageGatherExtended:
return "ImageGatherExtended";
case SpvCapabilityStorageImageMultisample:
case spv::Capability::StorageImageMultisample:
return "StorageImageMultisample";
case SpvCapabilityUniformBufferArrayDynamicIndexing:
case spv::Capability::UniformBufferArrayDynamicIndexing:
return "UniformBufferArrayDynamicIndexing";
case SpvCapabilitySampledImageArrayDynamicIndexing:
case spv::Capability::SampledImageArrayDynamicIndexing:
return "SampledImageArrayDynamicIndexing";
case SpvCapabilityStorageBufferArrayDynamicIndexing:
case spv::Capability::StorageBufferArrayDynamicIndexing:
return "StorageBufferArrayDynamicIndexing";
case SpvCapabilityStorageImageArrayDynamicIndexing:
case spv::Capability::StorageImageArrayDynamicIndexing:
return "StorageImageArrayDynamicIndexing";
case SpvCapabilityClipDistance:
case spv::Capability::ClipDistance:
return "ClipDistance";
case SpvCapabilityCullDistance:
case spv::Capability::CullDistance:
return "CullDistance";
case SpvCapabilityImageCubeArray:
case spv::Capability::ImageCubeArray:
return "ImageCubeArray";
case SpvCapabilitySampleRateShading:
case spv::Capability::SampleRateShading:
return "SampleRateShading";
case SpvCapabilityImageRect:
case spv::Capability::ImageRect:
return "ImageRect";
case SpvCapabilitySampledRect:
case spv::Capability::SampledRect:
return "SampledRect";
case SpvCapabilityGenericPointer:
case spv::Capability::GenericPointer:
return "GenericPointer";
case SpvCapabilityInt8:
case spv::Capability::Int8:
return "Int8";
case SpvCapabilityInputAttachment:
case spv::Capability::InputAttachment:
return "InputAttachment";
case SpvCapabilitySparseResidency:
case spv::Capability::SparseResidency:
return "SparseResidency";
case SpvCapabilityMinLod:
case spv::Capability::MinLod:
return "MinLod";
case SpvCapabilitySampled1D:
case spv::Capability::Sampled1D:
return "Sampled1D";
case SpvCapabilityImage1D:
case spv::Capability::Image1D:
return "Image1D";
case SpvCapabilitySampledCubeArray:
case spv::Capability::SampledCubeArray:
return "SampledCubeArray";
case SpvCapabilitySampledBuffer:
case spv::Capability::SampledBuffer:
return "SampledBuffer";
case SpvCapabilityImageBuffer:
case spv::Capability::ImageBuffer:
return "ImageBuffer";
case SpvCapabilityImageMSArray:
case spv::Capability::ImageMSArray:
return "ImageMSArray";
case SpvCapabilityStorageImageExtendedFormats:
case spv::Capability::StorageImageExtendedFormats:
return "StorageImageExtendedFormats";
case SpvCapabilityImageQuery:
case spv::Capability::ImageQuery:
return "ImageQuery";
case SpvCapabilityDerivativeControl:
case spv::Capability::DerivativeControl:
return "DerivativeControl";
case SpvCapabilityInterpolationFunction:
case spv::Capability::InterpolationFunction:
return "InterpolationFunction";
case SpvCapabilityTransformFeedback:
case spv::Capability::TransformFeedback:
return "TransformFeedback";
case SpvCapabilityGeometryStreams:
case spv::Capability::GeometryStreams:
return "GeometryStreams";
case SpvCapabilityStorageImageReadWithoutFormat:
case spv::Capability::StorageImageReadWithoutFormat:
return "StorageImageReadWithoutFormat";
case SpvCapabilityStorageImageWriteWithoutFormat:
case spv::Capability::StorageImageWriteWithoutFormat:
return "StorageImageWriteWithoutFormat";
case SpvCapabilityMultiViewport:
case spv::Capability::MultiViewport:
return "MultiViewport";
case SpvCapabilitySubgroupDispatch:
case spv::Capability::SubgroupDispatch:
return "SubgroupDispatch";
case SpvCapabilityNamedBarrier:
case spv::Capability::NamedBarrier:
return "NamedBarrier";
case SpvCapabilityPipeStorage:
case spv::Capability::PipeStorage:
return "PipeStorage";
case SpvCapabilityGroupNonUniform:
case spv::Capability::GroupNonUniform:
return "GroupNonUniform";
case SpvCapabilityGroupNonUniformVote:
case spv::Capability::GroupNonUniformVote:
return "GroupNonUniformVote";
case SpvCapabilityGroupNonUniformArithmetic:
case spv::Capability::GroupNonUniformArithmetic:
return "GroupNonUniformArithmetic";
case SpvCapabilityGroupNonUniformBallot:
case spv::Capability::GroupNonUniformBallot:
return "GroupNonUniformBallot";
case SpvCapabilityGroupNonUniformShuffle:
case spv::Capability::GroupNonUniformShuffle:
return "GroupNonUniformShuffle";
case SpvCapabilityGroupNonUniformShuffleRelative:
case spv::Capability::GroupNonUniformShuffleRelative:
return "GroupNonUniformShuffleRelative";
case SpvCapabilityGroupNonUniformClustered:
case spv::Capability::GroupNonUniformClustered:
return "GroupNonUniformClustered";
case SpvCapabilityGroupNonUniformQuad:
case spv::Capability::GroupNonUniformQuad:
return "GroupNonUniformQuad";
case SpvCapabilityShaderLayer:
case spv::Capability::ShaderLayer:
return "ShaderLayer";
case SpvCapabilityShaderViewportIndex:
case spv::Capability::ShaderViewportIndex:
return "ShaderViewportIndex";
case SpvCapabilityUniformDecoration:
case spv::Capability::UniformDecoration:
return "UniformDecoration";
case SpvCapabilityCoreBuiltinsARM:
case spv::Capability::CoreBuiltinsARM:
return "CoreBuiltinsARM";
case SpvCapabilityFragmentShadingRateKHR:
case spv::Capability::FragmentShadingRateKHR:
return "FragmentShadingRateKHR";
case SpvCapabilitySubgroupBallotKHR:
case spv::Capability::SubgroupBallotKHR:
return "SubgroupBallotKHR";
case SpvCapabilityDrawParameters:
case spv::Capability::DrawParameters:
return "DrawParameters";
case SpvCapabilityWorkgroupMemoryExplicitLayoutKHR:
case spv::Capability::WorkgroupMemoryExplicitLayoutKHR:
return "WorkgroupMemoryExplicitLayoutKHR";
case SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR:
case spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR:
return "WorkgroupMemoryExplicitLayout8BitAccessKHR";
case SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR:
case spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR:
return "WorkgroupMemoryExplicitLayout16BitAccessKHR";
case SpvCapabilitySubgroupVoteKHR:
case spv::Capability::SubgroupVoteKHR:
return "SubgroupVoteKHR";
case SpvCapabilityStorageBuffer16BitAccess:
case spv::Capability::StorageBuffer16BitAccess:
return "StorageBuffer16BitAccess";
case SpvCapabilityUniformAndStorageBuffer16BitAccess:
case spv::Capability::UniformAndStorageBuffer16BitAccess:
return "UniformAndStorageBuffer16BitAccess";
case SpvCapabilityStoragePushConstant16:
case spv::Capability::StoragePushConstant16:
return "StoragePushConstant16";
case SpvCapabilityStorageInputOutput16:
case spv::Capability::StorageInputOutput16:
return "StorageInputOutput16";
case SpvCapabilityDeviceGroup:
case spv::Capability::DeviceGroup:
return "DeviceGroup";
case SpvCapabilityMultiView:
case spv::Capability::MultiView:
return "MultiView";
case SpvCapabilityVariablePointersStorageBuffer:
case spv::Capability::VariablePointersStorageBuffer:
return "VariablePointersStorageBuffer";
case SpvCapabilityVariablePointers:
case spv::Capability::VariablePointers:
return "VariablePointers";
case SpvCapabilityAtomicStorageOps:
case spv::Capability::AtomicStorageOps:
return "AtomicStorageOps";
case SpvCapabilitySampleMaskPostDepthCoverage:
case spv::Capability::SampleMaskPostDepthCoverage:
return "SampleMaskPostDepthCoverage";
case SpvCapabilityStorageBuffer8BitAccess:
case spv::Capability::StorageBuffer8BitAccess:
return "StorageBuffer8BitAccess";
case SpvCapabilityUniformAndStorageBuffer8BitAccess:
case spv::Capability::UniformAndStorageBuffer8BitAccess:
return "UniformAndStorageBuffer8BitAccess";
case SpvCapabilityStoragePushConstant8:
case spv::Capability::StoragePushConstant8:
return "StoragePushConstant8";
case SpvCapabilityDenormPreserve:
case spv::Capability::DenormPreserve:
return "DenormPreserve";
case SpvCapabilityDenormFlushToZero:
case spv::Capability::DenormFlushToZero:
return "DenormFlushToZero";
case SpvCapabilitySignedZeroInfNanPreserve:
case spv::Capability::SignedZeroInfNanPreserve:
return "SignedZeroInfNanPreserve";
case SpvCapabilityRoundingModeRTE:
case spv::Capability::RoundingModeRTE:
return "RoundingModeRTE";
case SpvCapabilityRoundingModeRTZ:
case spv::Capability::RoundingModeRTZ:
return "RoundingModeRTZ";
case SpvCapabilityRayQueryProvisionalKHR:
case spv::Capability::RayQueryProvisionalKHR:
return "RayQueryProvisionalKHR";
case SpvCapabilityRayQueryKHR:
case spv::Capability::RayQueryKHR:
return "RayQueryKHR";
case SpvCapabilityRayTraversalPrimitiveCullingKHR:
case spv::Capability::RayTraversalPrimitiveCullingKHR:
return "RayTraversalPrimitiveCullingKHR";
case SpvCapabilityRayTracingKHR:
case spv::Capability::RayTracingKHR:
return "RayTracingKHR";
case SpvCapabilityFloat16ImageAMD:
case spv::Capability::Float16ImageAMD:
return "Float16ImageAMD";
case SpvCapabilityImageGatherBiasLodAMD:
case spv::Capability::ImageGatherBiasLodAMD:
return "ImageGatherBiasLodAMD";
case SpvCapabilityFragmentMaskAMD:
case spv::Capability::FragmentMaskAMD:
return "FragmentMaskAMD";
case SpvCapabilityStencilExportEXT:
case spv::Capability::StencilExportEXT:
return "StencilExportEXT";
case SpvCapabilityImageReadWriteLodAMD:
case spv::Capability::ImageReadWriteLodAMD:
return "ImageReadWriteLodAMD";
case SpvCapabilityInt64ImageEXT:
case spv::Capability::Int64ImageEXT:
return "Int64ImageEXT";
case SpvCapabilityShaderClockKHR:
case spv::Capability::ShaderClockKHR:
return "ShaderClockKHR";
case SpvCapabilitySampleMaskOverrideCoverageNV:
case spv::Capability::SampleMaskOverrideCoverageNV:
return "SampleMaskOverrideCoverageNV";
case SpvCapabilityGeometryShaderPassthroughNV:
case spv::Capability::GeometryShaderPassthroughNV:
return "GeometryShaderPassthroughNV";
case SpvCapabilityShaderViewportIndexLayerEXT:
case spv::Capability::ShaderViewportIndexLayerEXT:
return "ShaderViewportIndexLayerEXT";
case SpvCapabilityShaderViewportMaskNV:
case spv::Capability::ShaderViewportMaskNV:
return "ShaderViewportMaskNV";
case SpvCapabilityShaderStereoViewNV:
case spv::Capability::ShaderStereoViewNV:
return "ShaderStereoViewNV";
case SpvCapabilityPerViewAttributesNV:
case spv::Capability::PerViewAttributesNV:
return "PerViewAttributesNV";
case SpvCapabilityFragmentFullyCoveredEXT:
case spv::Capability::FragmentFullyCoveredEXT:
return "FragmentFullyCoveredEXT";
case SpvCapabilityMeshShadingNV:
case spv::Capability::MeshShadingNV:
return "MeshShadingNV";
case SpvCapabilityImageFootprintNV:
case spv::Capability::ImageFootprintNV:
return "ImageFootprintNV";
case SpvCapabilityMeshShadingEXT:
case spv::Capability::MeshShadingEXT:
return "MeshShadingEXT";
case SpvCapabilityFragmentBarycentricKHR:
case spv::Capability::FragmentBarycentricKHR:
return "FragmentBarycentricKHR";
case SpvCapabilityComputeDerivativeGroupQuadsNV:
case spv::Capability::ComputeDerivativeGroupQuadsNV:
return "ComputeDerivativeGroupQuadsNV";
case SpvCapabilityFragmentDensityEXT:
case spv::Capability::FragmentDensityEXT:
return "FragmentDensityEXT";
case SpvCapabilityGroupNonUniformPartitionedNV:
case spv::Capability::GroupNonUniformPartitionedNV:
return "GroupNonUniformPartitionedNV";
case SpvCapabilityShaderNonUniform:
case spv::Capability::ShaderNonUniform:
return "ShaderNonUniform";
case SpvCapabilityRuntimeDescriptorArray:
case spv::Capability::RuntimeDescriptorArray:
return "RuntimeDescriptorArray";
case SpvCapabilityInputAttachmentArrayDynamicIndexing:
case spv::Capability::InputAttachmentArrayDynamicIndexing:
return "InputAttachmentArrayDynamicIndexing";
case SpvCapabilityUniformTexelBufferArrayDynamicIndexing:
case spv::Capability::UniformTexelBufferArrayDynamicIndexing:
return "UniformTexelBufferArrayDynamicIndexing";
case SpvCapabilityStorageTexelBufferArrayDynamicIndexing:
case spv::Capability::StorageTexelBufferArrayDynamicIndexing:
return "StorageTexelBufferArrayDynamicIndexing";
case SpvCapabilityUniformBufferArrayNonUniformIndexing:
case spv::Capability::UniformBufferArrayNonUniformIndexing:
return "UniformBufferArrayNonUniformIndexing";
case SpvCapabilitySampledImageArrayNonUniformIndexing:
case spv::Capability::SampledImageArrayNonUniformIndexing:
return "SampledImageArrayNonUniformIndexing";
case SpvCapabilityStorageBufferArrayNonUniformIndexing:
case spv::Capability::StorageBufferArrayNonUniformIndexing:
return "StorageBufferArrayNonUniformIndexing";
case SpvCapabilityStorageImageArrayNonUniformIndexing:
case spv::Capability::StorageImageArrayNonUniformIndexing:
return "StorageImageArrayNonUniformIndexing";
case SpvCapabilityInputAttachmentArrayNonUniformIndexing:
case spv::Capability::InputAttachmentArrayNonUniformIndexing:
return "InputAttachmentArrayNonUniformIndexing";
case SpvCapabilityUniformTexelBufferArrayNonUniformIndexing:
case spv::Capability::UniformTexelBufferArrayNonUniformIndexing:
return "UniformTexelBufferArrayNonUniformIndexing";
case SpvCapabilityStorageTexelBufferArrayNonUniformIndexing:
case spv::Capability::StorageTexelBufferArrayNonUniformIndexing:
return "StorageTexelBufferArrayNonUniformIndexing";
case SpvCapabilityRayTracingNV:
case spv::Capability::RayTracingNV:
return "RayTracingNV";
case SpvCapabilityRayTracingMotionBlurNV:
case spv::Capability::RayTracingMotionBlurNV:
return "RayTracingMotionBlurNV";
case SpvCapabilityVulkanMemoryModel:
case spv::Capability::VulkanMemoryModel:
return "VulkanMemoryModel";
case SpvCapabilityVulkanMemoryModelDeviceScope:
case spv::Capability::VulkanMemoryModelDeviceScope:
return "VulkanMemoryModelDeviceScope";
case SpvCapabilityPhysicalStorageBufferAddresses:
case spv::Capability::PhysicalStorageBufferAddresses:
return "PhysicalStorageBufferAddresses";
case SpvCapabilityComputeDerivativeGroupLinearNV:
case spv::Capability::ComputeDerivativeGroupLinearNV:
return "ComputeDerivativeGroupLinearNV";
case SpvCapabilityRayTracingProvisionalKHR:
case spv::Capability::RayTracingProvisionalKHR:
return "RayTracingProvisionalKHR";
case SpvCapabilityCooperativeMatrixNV:
case spv::Capability::CooperativeMatrixNV:
return "CooperativeMatrixNV";
case SpvCapabilityFragmentShaderSampleInterlockEXT:
case spv::Capability::FragmentShaderSampleInterlockEXT:
return "FragmentShaderSampleInterlockEXT";
case SpvCapabilityFragmentShaderShadingRateInterlockEXT:
case spv::Capability::FragmentShaderShadingRateInterlockEXT:
return "FragmentShaderShadingRateInterlockEXT";
case SpvCapabilityShaderSMBuiltinsNV:
case spv::Capability::ShaderSMBuiltinsNV:
return "ShaderSMBuiltinsNV";
case SpvCapabilityFragmentShaderPixelInterlockEXT:
case spv::Capability::FragmentShaderPixelInterlockEXT:
return "FragmentShaderPixelInterlockEXT";
case SpvCapabilityDemoteToHelperInvocation:
case spv::Capability::DemoteToHelperInvocation:
return "DemoteToHelperInvocation";
case SpvCapabilityRayTracingOpacityMicromapEXT:
case spv::Capability::RayTracingOpacityMicromapEXT:
return "RayTracingOpacityMicromapEXT";
case SpvCapabilityBindlessTextureNV:
case spv::Capability::ShaderInvocationReorderNV:
return "ShaderInvocationReorderNV";
case spv::Capability::BindlessTextureNV:
return "BindlessTextureNV";
case SpvCapabilitySubgroupShuffleINTEL:
case spv::Capability::SubgroupShuffleINTEL:
return "SubgroupShuffleINTEL";
case SpvCapabilitySubgroupBufferBlockIOINTEL:
case spv::Capability::SubgroupBufferBlockIOINTEL:
return "SubgroupBufferBlockIOINTEL";
case SpvCapabilitySubgroupImageBlockIOINTEL:
case spv::Capability::SubgroupImageBlockIOINTEL:
return "SubgroupImageBlockIOINTEL";
case SpvCapabilitySubgroupImageMediaBlockIOINTEL:
case spv::Capability::SubgroupImageMediaBlockIOINTEL:
return "SubgroupImageMediaBlockIOINTEL";
case SpvCapabilityRoundToInfinityINTEL:
case spv::Capability::RoundToInfinityINTEL:
return "RoundToInfinityINTEL";
case SpvCapabilityFloatingPointModeINTEL:
case spv::Capability::FloatingPointModeINTEL:
return "FloatingPointModeINTEL";
case SpvCapabilityIntegerFunctions2INTEL:
case spv::Capability::IntegerFunctions2INTEL:
return "IntegerFunctions2INTEL";
case SpvCapabilityFunctionPointersINTEL:
case spv::Capability::FunctionPointersINTEL:
return "FunctionPointersINTEL";
case SpvCapabilityIndirectReferencesINTEL:
case spv::Capability::IndirectReferencesINTEL:
return "IndirectReferencesINTEL";
case SpvCapabilityAsmINTEL:
case spv::Capability::AsmINTEL:
return "AsmINTEL";
case SpvCapabilityAtomicFloat32MinMaxEXT:
case spv::Capability::AtomicFloat32MinMaxEXT:
return "AtomicFloat32MinMaxEXT";
case SpvCapabilityAtomicFloat64MinMaxEXT:
case spv::Capability::AtomicFloat64MinMaxEXT:
return "AtomicFloat64MinMaxEXT";
case SpvCapabilityAtomicFloat16MinMaxEXT:
case spv::Capability::AtomicFloat16MinMaxEXT:
return "AtomicFloat16MinMaxEXT";
case SpvCapabilityVectorComputeINTEL:
case spv::Capability::VectorComputeINTEL:
return "VectorComputeINTEL";
case SpvCapabilityVectorAnyINTEL:
case spv::Capability::VectorAnyINTEL:
return "VectorAnyINTEL";
case SpvCapabilityExpectAssumeKHR:
case spv::Capability::ExpectAssumeKHR:
return "ExpectAssumeKHR";
case SpvCapabilitySubgroupAvcMotionEstimationINTEL:
case spv::Capability::SubgroupAvcMotionEstimationINTEL:
return "SubgroupAvcMotionEstimationINTEL";
case SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL:
case spv::Capability::SubgroupAvcMotionEstimationIntraINTEL:
return "SubgroupAvcMotionEstimationIntraINTEL";
case SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL:
case spv::Capability::SubgroupAvcMotionEstimationChromaINTEL:
return "SubgroupAvcMotionEstimationChromaINTEL";
case SpvCapabilityVariableLengthArrayINTEL:
case spv::Capability::VariableLengthArrayINTEL:
return "VariableLengthArrayINTEL";
case SpvCapabilityFunctionFloatControlINTEL:
case spv::Capability::FunctionFloatControlINTEL:
return "FunctionFloatControlINTEL";
case SpvCapabilityFPGAMemoryAttributesINTEL:
case spv::Capability::FPGAMemoryAttributesINTEL:
return "FPGAMemoryAttributesINTEL";
case SpvCapabilityFPFastMathModeINTEL:
case spv::Capability::FPFastMathModeINTEL:
return "FPFastMathModeINTEL";
case SpvCapabilityArbitraryPrecisionIntegersINTEL:
case spv::Capability::ArbitraryPrecisionIntegersINTEL:
return "ArbitraryPrecisionIntegersINTEL";
case SpvCapabilityArbitraryPrecisionFloatingPointINTEL:
case spv::Capability::ArbitraryPrecisionFloatingPointINTEL:
return "ArbitraryPrecisionFloatingPointINTEL";
case SpvCapabilityUnstructuredLoopControlsINTEL:
case spv::Capability::UnstructuredLoopControlsINTEL:
return "UnstructuredLoopControlsINTEL";
case SpvCapabilityFPGALoopControlsINTEL:
case spv::Capability::FPGALoopControlsINTEL:
return "FPGALoopControlsINTEL";
case SpvCapabilityKernelAttributesINTEL:
case spv::Capability::KernelAttributesINTEL:
return "KernelAttributesINTEL";
case SpvCapabilityFPGAKernelAttributesINTEL:
case spv::Capability::FPGAKernelAttributesINTEL:
return "FPGAKernelAttributesINTEL";
case SpvCapabilityFPGAMemoryAccessesINTEL:
case spv::Capability::FPGAMemoryAccessesINTEL:
return "FPGAMemoryAccessesINTEL";
case SpvCapabilityFPGAClusterAttributesINTEL:
case spv::Capability::FPGAClusterAttributesINTEL:
return "FPGAClusterAttributesINTEL";
case SpvCapabilityLoopFuseINTEL:
case spv::Capability::LoopFuseINTEL:
return "LoopFuseINTEL";
case SpvCapabilityMemoryAccessAliasingINTEL:
case spv::Capability::FPGADSPControlINTEL:
return "FPGADSPControlINTEL";
case spv::Capability::MemoryAccessAliasingINTEL:
return "MemoryAccessAliasingINTEL";
case SpvCapabilityFPGABufferLocationINTEL:
case spv::Capability::FPGAInvocationPipeliningAttributesINTEL:
return "FPGAInvocationPipeliningAttributesINTEL";
case spv::Capability::FPGABufferLocationINTEL:
return "FPGABufferLocationINTEL";
case SpvCapabilityArbitraryPrecisionFixedPointINTEL:
case spv::Capability::ArbitraryPrecisionFixedPointINTEL:
return "ArbitraryPrecisionFixedPointINTEL";
case SpvCapabilityUSMStorageClassesINTEL:
case spv::Capability::USMStorageClassesINTEL:
return "USMStorageClassesINTEL";
case SpvCapabilityIOPipesINTEL:
case spv::Capability::RuntimeAlignedAttributeINTEL:
return "RuntimeAlignedAttributeINTEL";
case spv::Capability::IOPipesINTEL:
return "IOPipesINTEL";
case SpvCapabilityBlockingPipesINTEL:
case spv::Capability::BlockingPipesINTEL:
return "BlockingPipesINTEL";
case SpvCapabilityFPGARegINTEL:
case spv::Capability::FPGARegINTEL:
return "FPGARegINTEL";
case SpvCapabilityDotProductInputAll:
case spv::Capability::DotProductInputAll:
return "DotProductInputAll";
case SpvCapabilityDotProductInput4x8Bit:
case spv::Capability::DotProductInput4x8Bit:
return "DotProductInput4x8Bit";
case SpvCapabilityDotProductInput4x8BitPacked:
case spv::Capability::DotProductInput4x8BitPacked:
return "DotProductInput4x8BitPacked";
case SpvCapabilityDotProduct:
case spv::Capability::DotProduct:
return "DotProduct";
case SpvCapabilityRayCullMaskKHR:
case spv::Capability::RayCullMaskKHR:
return "RayCullMaskKHR";
case SpvCapabilityBitInstructions:
case spv::Capability::BitInstructions:
return "BitInstructions";
case SpvCapabilityGroupNonUniformRotateKHR:
case spv::Capability::GroupNonUniformRotateKHR:
return "GroupNonUniformRotateKHR";
case SpvCapabilityAtomicFloat32AddEXT:
case spv::Capability::AtomicFloat32AddEXT:
return "AtomicFloat32AddEXT";
case SpvCapabilityAtomicFloat64AddEXT:
case spv::Capability::AtomicFloat64AddEXT:
return "AtomicFloat64AddEXT";
case SpvCapabilityLongConstantCompositeINTEL:
case spv::Capability::LongConstantCompositeINTEL:
return "LongConstantCompositeINTEL";
case SpvCapabilityOptNoneINTEL:
case spv::Capability::OptNoneINTEL:
return "OptNoneINTEL";
case SpvCapabilityAtomicFloat16AddEXT:
case spv::Capability::AtomicFloat16AddEXT:
return "AtomicFloat16AddEXT";
case SpvCapabilityDebugInfoModuleINTEL:
case spv::Capability::DebugInfoModuleINTEL:
return "DebugInfoModuleINTEL";
case SpvCapabilitySplitBarrierINTEL:
case spv::Capability::SplitBarrierINTEL:
return "SplitBarrierINTEL";
case SpvCapabilityGroupUniformArithmeticKHR:
case spv::Capability::GroupUniformArithmeticKHR:
return "GroupUniformArithmeticKHR";
case SpvCapabilityMax:
assert(0 && "Attempting to convert SpvCapabilityMax to string");
case spv::Capability::Max:
assert(0 && "Attempting to convert spv::Capability::Max to string");
return "";
}

View File

@@ -37,6 +37,8 @@ kSPV_INTEL_float_controls2,
kSPV_INTEL_fp_fast_math_mode,
kSPV_INTEL_fpga_buffer_location,
kSPV_INTEL_fpga_cluster_attributes,
kSPV_INTEL_fpga_dsp_control,
kSPV_INTEL_fpga_invocation_pipelining_attributes,
kSPV_INTEL_fpga_loop_controls,
kSPV_INTEL_fpga_memory_accesses,
kSPV_INTEL_fpga_memory_attributes,
@@ -50,6 +52,7 @@ kSPV_INTEL_loop_fuse,
kSPV_INTEL_media_block_io,
kSPV_INTEL_memory_access_aliasing,
kSPV_INTEL_optnone,
kSPV_INTEL_runtime_aligned,
kSPV_INTEL_shader_integer_functions2,
kSPV_INTEL_split_barrier,
kSPV_INTEL_subgroups,
@@ -99,6 +102,7 @@ kSPV_NV_ray_tracing,
kSPV_NV_ray_tracing_motion_blur,
kSPV_NV_sample_mask_override_coverage,
kSPV_NV_shader_image_footprint,
kSPV_NV_shader_invocation_reorder,
kSPV_NV_shader_sm_builtins,
kSPV_NV_shader_subgroup_partitioned,
kSPV_NV_shading_rate,

View File

@@ -33,4 +33,5 @@
{32, "TornadoVM", "SPIRV Beehive Toolkit", "TornadoVM SPIRV Beehive Toolkit"},
{33, "DragonJoker", "ShaderWriter", "DragonJoker ShaderWriter"},
{34, "Rayan Hatout", "SPIRVSmith", "Rayan Hatout SPIRVSmith"},
{35, "Saarland University", "Shady", "Saarland University Shady"},
{35, "Saarland University", "Shady", "Saarland University Shady"},
{36, "Taichi Graphics", "Taichi", "Taichi Graphics Taichi"},

View File

@@ -1,5 +1,5 @@
static const SpvCapability pygen_variable_caps_Float64[] = {SpvCapabilityFloat64};
static const SpvCapability pygen_variable_caps_InterpolationFunction[] = {SpvCapabilityInterpolationFunction};
static const spv::Capability pygen_variable_caps_Float64[] = {spv::Capability::Float64};
static const spv::Capability pygen_variable_caps_InterpolationFunction[] = {spv::Capability::InterpolationFunction};
static const spv_ext_inst_desc_t glsl_entries[] = {
{"Round", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}},

View File

@@ -1,7 +1,7 @@
static const spv_ext_inst_desc_t nonsemantic_clspvreflection_entries[] = {
{"Kernel", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}},
{"Kernel", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}},
{"ArgumentInfo", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}},
{"ArgumentStorageBuffer", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}},
{"ArgumentUniform", 4, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}},
@@ -35,5 +35,10 @@ static const spv_ext_inst_desc_t nonsemantic_clspvreflection_entries[] = {
{"ImageArgumentInfoChannelOrderUniform", 32, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}},
{"ImageArgumentInfoChannelDataTypeUniform", 33, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}},
{"ArgumentStorageTexelBuffer", 34, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}},
{"ArgumentUniformTexelBuffer", 35, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}
{"ArgumentUniformTexelBuffer", 35, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}},
{"ConstantDataPointerPushConstant", 36, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}},
{"ProgramScopeVariablePointerPushConstant", 37, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}},
{"PrintfInfo", 38, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}},
{"PrintfBufferStorageBuffer", 39, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}},
{"PrintfBufferPointerPushConstant", 40, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}
};

View File

@@ -1,129 +1,133 @@
static const SpvCapability pygen_variable_caps_Addresses[] = {SpvCapabilityAddresses};
static const SpvCapability pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL[] = {SpvCapabilityArbitraryPrecisionFixedPointINTEL};
static const SpvCapability pygen_variable_caps_AsmINTEL[] = {SpvCapabilityAsmINTEL};
static const SpvCapability pygen_variable_caps_AtomicStorage[] = {SpvCapabilityAtomicStorage};
static const SpvCapability pygen_variable_caps_BindlessTextureNV[] = {SpvCapabilityBindlessTextureNV};
static const SpvCapability pygen_variable_caps_ClipDistance[] = {SpvCapabilityClipDistance};
static const SpvCapability pygen_variable_caps_ComputeDerivativeGroupLinearNV[] = {SpvCapabilityComputeDerivativeGroupLinearNV};
static const SpvCapability pygen_variable_caps_ComputeDerivativeGroupQuadsNV[] = {SpvCapabilityComputeDerivativeGroupQuadsNV};
static const SpvCapability pygen_variable_caps_CoreBuiltinsARM[] = {SpvCapabilityCoreBuiltinsARM};
static const SpvCapability pygen_variable_caps_CullDistance[] = {SpvCapabilityCullDistance};
static const SpvCapability pygen_variable_caps_DenormFlushToZero[] = {SpvCapabilityDenormFlushToZero};
static const SpvCapability pygen_variable_caps_DenormPreserve[] = {SpvCapabilityDenormPreserve};
static const SpvCapability pygen_variable_caps_DeviceEnqueue[] = {SpvCapabilityDeviceEnqueue};
static const SpvCapability pygen_variable_caps_DeviceGroup[] = {SpvCapabilityDeviceGroup};
static const SpvCapability pygen_variable_caps_DrawParameters[] = {SpvCapabilityDrawParameters};
static const SpvCapability pygen_variable_caps_DrawParametersMeshShadingNVMeshShadingEXT[] = {SpvCapabilityDrawParameters, SpvCapabilityMeshShadingNV, SpvCapabilityMeshShadingEXT};
static const SpvCapability pygen_variable_caps_FPFastMathModeINTEL[] = {SpvCapabilityFPFastMathModeINTEL};
static const SpvCapability pygen_variable_caps_FPGABufferLocationINTEL[] = {SpvCapabilityFPGABufferLocationINTEL};
static const SpvCapability pygen_variable_caps_FPGAClusterAttributesINTEL[] = {SpvCapabilityFPGAClusterAttributesINTEL};
static const SpvCapability pygen_variable_caps_FPGAKernelAttributesINTEL[] = {SpvCapabilityFPGAKernelAttributesINTEL};
static const SpvCapability pygen_variable_caps_FPGALoopControlsINTEL[] = {SpvCapabilityFPGALoopControlsINTEL};
static const SpvCapability pygen_variable_caps_FPGAMemoryAccessesINTEL[] = {SpvCapabilityFPGAMemoryAccessesINTEL};
static const SpvCapability pygen_variable_caps_FPGAMemoryAttributesINTEL[] = {SpvCapabilityFPGAMemoryAttributesINTEL};
static const SpvCapability pygen_variable_caps_FragmentBarycentricNVFragmentBarycentricKHR[] = {SpvCapabilityFragmentBarycentricNV, SpvCapabilityFragmentBarycentricKHR};
static const SpvCapability pygen_variable_caps_FragmentDensityEXTShadingRateNV[] = {SpvCapabilityFragmentDensityEXT, SpvCapabilityShadingRateNV};
static const SpvCapability pygen_variable_caps_FragmentFullyCoveredEXT[] = {SpvCapabilityFragmentFullyCoveredEXT};
static const SpvCapability pygen_variable_caps_FragmentShaderPixelInterlockEXT[] = {SpvCapabilityFragmentShaderPixelInterlockEXT};
static const SpvCapability pygen_variable_caps_FragmentShaderSampleInterlockEXT[] = {SpvCapabilityFragmentShaderSampleInterlockEXT};
static const SpvCapability pygen_variable_caps_FragmentShaderShadingRateInterlockEXT[] = {SpvCapabilityFragmentShaderShadingRateInterlockEXT};
static const SpvCapability pygen_variable_caps_FragmentShadingRateKHR[] = {SpvCapabilityFragmentShadingRateKHR};
static const SpvCapability pygen_variable_caps_FunctionFloatControlINTEL[] = {SpvCapabilityFunctionFloatControlINTEL};
static const SpvCapability pygen_variable_caps_FunctionPointersINTEL[] = {SpvCapabilityFunctionPointersINTEL};
static const SpvCapability pygen_variable_caps_GenericPointer[] = {SpvCapabilityGenericPointer};
static const SpvCapability pygen_variable_caps_Geometry[] = {SpvCapabilityGeometry};
static const SpvCapability pygen_variable_caps_GeometryMeshShadingNVMeshShadingEXT[] = {SpvCapabilityGeometry, SpvCapabilityMeshShadingNV, SpvCapabilityMeshShadingEXT};
static const SpvCapability pygen_variable_caps_GeometryShaderLayerShaderViewportIndexLayerEXTMeshShadingNVMeshShadingEXT[] = {SpvCapabilityGeometry, SpvCapabilityShaderLayer, SpvCapabilityShaderViewportIndexLayerEXT, SpvCapabilityMeshShadingNV, SpvCapabilityMeshShadingEXT};
static const SpvCapability pygen_variable_caps_GeometryTessellation[] = {SpvCapabilityGeometry, SpvCapabilityTessellation};
static const SpvCapability pygen_variable_caps_GeometryTessellationMeshShadingNVMeshShadingEXT[] = {SpvCapabilityGeometry, SpvCapabilityTessellation, SpvCapabilityMeshShadingNV, SpvCapabilityMeshShadingEXT};
static const SpvCapability pygen_variable_caps_GeometryTessellationRayTracingNVRayTracingKHRMeshShadingNVMeshShadingEXT[] = {SpvCapabilityGeometry, SpvCapabilityTessellation, SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR, SpvCapabilityMeshShadingNV, SpvCapabilityMeshShadingEXT};
static const SpvCapability pygen_variable_caps_GeometryShaderPassthroughNV[] = {SpvCapabilityGeometryShaderPassthroughNV};
static const SpvCapability pygen_variable_caps_GeometryStreams[] = {SpvCapabilityGeometryStreams};
static const SpvCapability pygen_variable_caps_GroupNonUniform[] = {SpvCapabilityGroupNonUniform};
static const SpvCapability pygen_variable_caps_GroupNonUniformClustered[] = {SpvCapabilityGroupNonUniformClustered};
static const SpvCapability pygen_variable_caps_GroupNonUniformPartitionedNV[] = {SpvCapabilityGroupNonUniformPartitionedNV};
static const SpvCapability pygen_variable_caps_IOPipesINTEL[] = {SpvCapabilityIOPipesINTEL};
static const SpvCapability pygen_variable_caps_ImageBasic[] = {SpvCapabilityImageBasic};
static const SpvCapability pygen_variable_caps_ImageBuffer[] = {SpvCapabilityImageBuffer};
static const SpvCapability pygen_variable_caps_ImageBufferShaderNonUniform[] = {SpvCapabilityImageBuffer, SpvCapabilityShaderNonUniform};
static const SpvCapability pygen_variable_caps_ImageGatherExtended[] = {SpvCapabilityImageGatherExtended};
static const SpvCapability pygen_variable_caps_IndirectReferencesINTEL[] = {SpvCapabilityIndirectReferencesINTEL};
static const SpvCapability pygen_variable_caps_InputAttachment[] = {SpvCapabilityInputAttachment};
static const SpvCapability pygen_variable_caps_InputAttachmentShaderNonUniform[] = {SpvCapabilityInputAttachment, SpvCapabilityShaderNonUniform};
static const SpvCapability pygen_variable_caps_Int64[] = {SpvCapabilityInt64};
static const SpvCapability pygen_variable_caps_Int64ImageEXT[] = {SpvCapabilityInt64ImageEXT};
static const SpvCapability pygen_variable_caps_Int8[] = {SpvCapabilityInt8};
static const SpvCapability pygen_variable_caps_Kernel[] = {SpvCapabilityKernel};
static const SpvCapability pygen_variable_caps_KernelGroupNonUniform[] = {SpvCapabilityKernel, SpvCapabilityGroupNonUniform};
static const SpvCapability pygen_variable_caps_KernelGroupNonUniformSubgroupBallotKHR[] = {SpvCapabilityKernel, SpvCapabilityGroupNonUniform, SpvCapabilitySubgroupBallotKHR};
static const SpvCapability pygen_variable_caps_KernelGroupNonUniformArithmeticGroupNonUniformBallot[] = {SpvCapabilityKernel, SpvCapabilityGroupNonUniformArithmetic, SpvCapabilityGroupNonUniformBallot};
static const SpvCapability pygen_variable_caps_KernelAttributesINTEL[] = {SpvCapabilityKernelAttributesINTEL};
static const SpvCapability pygen_variable_caps_Linkage[] = {SpvCapabilityLinkage};
static const SpvCapability pygen_variable_caps_LoopFuseINTEL[] = {SpvCapabilityLoopFuseINTEL};
static const SpvCapability pygen_variable_caps_Matrix[] = {SpvCapabilityMatrix};
static const SpvCapability pygen_variable_caps_MemoryAccessAliasingINTEL[] = {SpvCapabilityMemoryAccessAliasingINTEL};
static const SpvCapability pygen_variable_caps_MeshShadingEXT[] = {SpvCapabilityMeshShadingEXT};
static const SpvCapability pygen_variable_caps_MeshShadingNV[] = {SpvCapabilityMeshShadingNV};
static const SpvCapability pygen_variable_caps_MeshShadingNVMeshShadingEXT[] = {SpvCapabilityMeshShadingNV, SpvCapabilityMeshShadingEXT};
static const SpvCapability pygen_variable_caps_MinLod[] = {SpvCapabilityMinLod};
static const SpvCapability pygen_variable_caps_MultiView[] = {SpvCapabilityMultiView};
static const SpvCapability pygen_variable_caps_MultiViewport[] = {SpvCapabilityMultiViewport};
static const SpvCapability pygen_variable_caps_MultiViewportShaderViewportIndexShaderViewportIndexLayerEXTMeshShadingNVMeshShadingEXT[] = {SpvCapabilityMultiViewport, SpvCapabilityShaderViewportIndex, SpvCapabilityShaderViewportIndexLayerEXT, SpvCapabilityMeshShadingNV, SpvCapabilityMeshShadingEXT};
static const SpvCapability pygen_variable_caps_OptNoneINTEL[] = {SpvCapabilityOptNoneINTEL};
static const SpvCapability pygen_variable_caps_PerViewAttributesNVMeshShadingNV[] = {SpvCapabilityPerViewAttributesNV, SpvCapabilityMeshShadingNV};
static const SpvCapability pygen_variable_caps_PhysicalStorageBufferAddresses[] = {SpvCapabilityPhysicalStorageBufferAddresses};
static const SpvCapability pygen_variable_caps_Pipes[] = {SpvCapabilityPipes};
static const SpvCapability pygen_variable_caps_RayCullMaskKHR[] = {SpvCapabilityRayCullMaskKHR};
static const SpvCapability pygen_variable_caps_RayQueryKHR[] = {SpvCapabilityRayQueryKHR};
static const SpvCapability pygen_variable_caps_RayQueryKHRRayTracingKHR[] = {SpvCapabilityRayQueryKHR, SpvCapabilityRayTracingKHR};
static const SpvCapability pygen_variable_caps_RayTracingKHR[] = {SpvCapabilityRayTracingKHR};
static const SpvCapability pygen_variable_caps_RayTracingMotionBlurNV[] = {SpvCapabilityRayTracingMotionBlurNV};
static const SpvCapability pygen_variable_caps_RayTracingNV[] = {SpvCapabilityRayTracingNV};
static const SpvCapability pygen_variable_caps_RayTracingNVRayTracingKHR[] = {SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR};
static const SpvCapability pygen_variable_caps_RayTracingOpacityMicromapEXT[] = {SpvCapabilityRayTracingOpacityMicromapEXT};
static const SpvCapability pygen_variable_caps_RayTraversalPrimitiveCullingKHR[] = {SpvCapabilityRayTraversalPrimitiveCullingKHR};
static const SpvCapability pygen_variable_caps_RoundToInfinityINTEL[] = {SpvCapabilityRoundToInfinityINTEL};
static const SpvCapability pygen_variable_caps_RoundingModeRTE[] = {SpvCapabilityRoundingModeRTE};
static const SpvCapability pygen_variable_caps_RoundingModeRTZ[] = {SpvCapabilityRoundingModeRTZ};
static const SpvCapability pygen_variable_caps_SampleMaskOverrideCoverageNV[] = {SpvCapabilitySampleMaskOverrideCoverageNV};
static const SpvCapability pygen_variable_caps_SampleMaskPostDepthCoverage[] = {SpvCapabilitySampleMaskPostDepthCoverage};
static const SpvCapability pygen_variable_caps_SampleRateShading[] = {SpvCapabilitySampleRateShading};
static const SpvCapability pygen_variable_caps_Sampled1D[] = {SpvCapabilitySampled1D};
static const SpvCapability pygen_variable_caps_Sampled1DImage1D[] = {SpvCapabilitySampled1D, SpvCapabilityImage1D};
static const SpvCapability pygen_variable_caps_SampledBuffer[] = {SpvCapabilitySampledBuffer};
static const SpvCapability pygen_variable_caps_SampledBufferImageBuffer[] = {SpvCapabilitySampledBuffer, SpvCapabilityImageBuffer};
static const SpvCapability pygen_variable_caps_SampledBufferShaderNonUniform[] = {SpvCapabilitySampledBuffer, SpvCapabilityShaderNonUniform};
static const SpvCapability pygen_variable_caps_SampledCubeArray[] = {SpvCapabilitySampledCubeArray};
static const SpvCapability pygen_variable_caps_SampledRect[] = {SpvCapabilitySampledRect};
static const SpvCapability pygen_variable_caps_SampledRectImageRect[] = {SpvCapabilitySampledRect, SpvCapabilityImageRect};
static const SpvCapability pygen_variable_caps_Shader[] = {SpvCapabilityShader};
static const SpvCapability pygen_variable_caps_ShaderImageCubeArray[] = {SpvCapabilityShader, SpvCapabilityImageCubeArray};
static const SpvCapability pygen_variable_caps_ShaderKernel[] = {SpvCapabilityShader, SpvCapabilityKernel};
static const SpvCapability pygen_variable_caps_ShaderKernelImageMSArray[] = {SpvCapabilityShader, SpvCapabilityKernel, SpvCapabilityImageMSArray};
static const SpvCapability pygen_variable_caps_ShaderUniformDecoration[] = {SpvCapabilityShader, SpvCapabilityUniformDecoration};
static const SpvCapability pygen_variable_caps_ShaderVectorComputeINTEL[] = {SpvCapabilityShader, SpvCapabilityVectorComputeINTEL};
static const SpvCapability pygen_variable_caps_ShaderNonUniform[] = {SpvCapabilityShaderNonUniform};
static const SpvCapability pygen_variable_caps_ShaderSMBuiltinsNV[] = {SpvCapabilityShaderSMBuiltinsNV};
static const SpvCapability pygen_variable_caps_ShaderStereoViewNV[] = {SpvCapabilityShaderStereoViewNV};
static const SpvCapability pygen_variable_caps_ShaderViewportIndexLayerNV[] = {SpvCapabilityShaderViewportIndexLayerNV};
static const SpvCapability pygen_variable_caps_ShaderViewportMaskNV[] = {SpvCapabilityShaderViewportMaskNV};
static const SpvCapability pygen_variable_caps_ShaderViewportMaskNVMeshShadingNV[] = {SpvCapabilityShaderViewportMaskNV, SpvCapabilityMeshShadingNV};
static const SpvCapability pygen_variable_caps_ShadingRateNVFragmentDensityEXT[] = {SpvCapabilityShadingRateNV, SpvCapabilityFragmentDensityEXT};
static const SpvCapability pygen_variable_caps_SignedZeroInfNanPreserve[] = {SpvCapabilitySignedZeroInfNanPreserve};
static const SpvCapability pygen_variable_caps_StencilExportEXT[] = {SpvCapabilityStencilExportEXT};
static const SpvCapability pygen_variable_caps_StorageBuffer16BitAccessStorageUniformBufferBlock16[] = {SpvCapabilityStorageBuffer16BitAccess, SpvCapabilityStorageUniformBufferBlock16};
static const SpvCapability pygen_variable_caps_StorageBuffer8BitAccess[] = {SpvCapabilityStorageBuffer8BitAccess};
static const SpvCapability pygen_variable_caps_StorageImageExtendedFormats[] = {SpvCapabilityStorageImageExtendedFormats};
static const SpvCapability pygen_variable_caps_SubgroupBallotKHRGroupNonUniformBallot[] = {SpvCapabilitySubgroupBallotKHR, SpvCapabilityGroupNonUniformBallot};
static const SpvCapability pygen_variable_caps_SubgroupDispatch[] = {SpvCapabilitySubgroupDispatch};
static const SpvCapability pygen_variable_caps_Tessellation[] = {SpvCapabilityTessellation};
static const SpvCapability pygen_variable_caps_TransformFeedback[] = {SpvCapabilityTransformFeedback};
static const SpvCapability pygen_variable_caps_USMStorageClassesINTEL[] = {SpvCapabilityUSMStorageClassesINTEL};
static const SpvCapability pygen_variable_caps_VariablePointersStorageBuffer[] = {SpvCapabilityVariablePointersStorageBuffer};
static const SpvCapability pygen_variable_caps_VectorAnyINTEL[] = {SpvCapabilityVectorAnyINTEL};
static const SpvCapability pygen_variable_caps_VectorComputeINTEL[] = {SpvCapabilityVectorComputeINTEL};
static const SpvCapability pygen_variable_caps_VulkanMemoryModel[] = {SpvCapabilityVulkanMemoryModel};
static const SpvCapability pygen_variable_caps_WorkgroupMemoryExplicitLayoutKHR[] = {SpvCapabilityWorkgroupMemoryExplicitLayoutKHR};
static const spv::Capability pygen_variable_caps_Addresses[] = {spv::Capability::Addresses};
static const spv::Capability pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL[] = {spv::Capability::ArbitraryPrecisionFixedPointINTEL};
static const spv::Capability pygen_variable_caps_AsmINTEL[] = {spv::Capability::AsmINTEL};
static const spv::Capability pygen_variable_caps_AtomicStorage[] = {spv::Capability::AtomicStorage};
static const spv::Capability pygen_variable_caps_BindlessTextureNV[] = {spv::Capability::BindlessTextureNV};
static const spv::Capability pygen_variable_caps_ClipDistance[] = {spv::Capability::ClipDistance};
static const spv::Capability pygen_variable_caps_ComputeDerivativeGroupLinearNV[] = {spv::Capability::ComputeDerivativeGroupLinearNV};
static const spv::Capability pygen_variable_caps_ComputeDerivativeGroupQuadsNV[] = {spv::Capability::ComputeDerivativeGroupQuadsNV};
static const spv::Capability pygen_variable_caps_CoreBuiltinsARM[] = {spv::Capability::CoreBuiltinsARM};
static const spv::Capability pygen_variable_caps_CullDistance[] = {spv::Capability::CullDistance};
static const spv::Capability pygen_variable_caps_DenormFlushToZero[] = {spv::Capability::DenormFlushToZero};
static const spv::Capability pygen_variable_caps_DenormPreserve[] = {spv::Capability::DenormPreserve};
static const spv::Capability pygen_variable_caps_DeviceEnqueue[] = {spv::Capability::DeviceEnqueue};
static const spv::Capability pygen_variable_caps_DeviceGroup[] = {spv::Capability::DeviceGroup};
static const spv::Capability pygen_variable_caps_DrawParameters[] = {spv::Capability::DrawParameters};
static const spv::Capability pygen_variable_caps_DrawParametersMeshShadingNVMeshShadingEXT[] = {spv::Capability::DrawParameters, spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_FPFastMathModeINTEL[] = {spv::Capability::FPFastMathModeINTEL};
static const spv::Capability pygen_variable_caps_FPGABufferLocationINTEL[] = {spv::Capability::FPGABufferLocationINTEL};
static const spv::Capability pygen_variable_caps_FPGAClusterAttributesINTEL[] = {spv::Capability::FPGAClusterAttributesINTEL};
static const spv::Capability pygen_variable_caps_FPGADSPControlINTEL[] = {spv::Capability::FPGADSPControlINTEL};
static const spv::Capability pygen_variable_caps_FPGAInvocationPipeliningAttributesINTEL[] = {spv::Capability::FPGAInvocationPipeliningAttributesINTEL};
static const spv::Capability pygen_variable_caps_FPGAKernelAttributesINTEL[] = {spv::Capability::FPGAKernelAttributesINTEL};
static const spv::Capability pygen_variable_caps_FPGALoopControlsINTEL[] = {spv::Capability::FPGALoopControlsINTEL};
static const spv::Capability pygen_variable_caps_FPGAMemoryAccessesINTEL[] = {spv::Capability::FPGAMemoryAccessesINTEL};
static const spv::Capability pygen_variable_caps_FPGAMemoryAttributesINTEL[] = {spv::Capability::FPGAMemoryAttributesINTEL};
static const spv::Capability pygen_variable_caps_FragmentBarycentricNVFragmentBarycentricKHR[] = {spv::Capability::FragmentBarycentricNV, spv::Capability::FragmentBarycentricKHR};
static const spv::Capability pygen_variable_caps_FragmentDensityEXTShadingRateNV[] = {spv::Capability::FragmentDensityEXT, spv::Capability::ShadingRateNV};
static const spv::Capability pygen_variable_caps_FragmentFullyCoveredEXT[] = {spv::Capability::FragmentFullyCoveredEXT};
static const spv::Capability pygen_variable_caps_FragmentShaderPixelInterlockEXT[] = {spv::Capability::FragmentShaderPixelInterlockEXT};
static const spv::Capability pygen_variable_caps_FragmentShaderSampleInterlockEXT[] = {spv::Capability::FragmentShaderSampleInterlockEXT};
static const spv::Capability pygen_variable_caps_FragmentShaderShadingRateInterlockEXT[] = {spv::Capability::FragmentShaderShadingRateInterlockEXT};
static const spv::Capability pygen_variable_caps_FragmentShadingRateKHR[] = {spv::Capability::FragmentShadingRateKHR};
static const spv::Capability pygen_variable_caps_FunctionFloatControlINTEL[] = {spv::Capability::FunctionFloatControlINTEL};
static const spv::Capability pygen_variable_caps_FunctionPointersINTEL[] = {spv::Capability::FunctionPointersINTEL};
static const spv::Capability pygen_variable_caps_GenericPointer[] = {spv::Capability::GenericPointer};
static const spv::Capability pygen_variable_caps_Geometry[] = {spv::Capability::Geometry};
static const spv::Capability pygen_variable_caps_GeometryMeshShadingNVMeshShadingEXT[] = {spv::Capability::Geometry, spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_GeometryShaderLayerShaderViewportIndexLayerEXTMeshShadingNVMeshShadingEXT[] = {spv::Capability::Geometry, spv::Capability::ShaderLayer, spv::Capability::ShaderViewportIndexLayerEXT, spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_GeometryTessellation[] = {spv::Capability::Geometry, spv::Capability::Tessellation};
static const spv::Capability pygen_variable_caps_GeometryTessellationMeshShadingNVMeshShadingEXT[] = {spv::Capability::Geometry, spv::Capability::Tessellation, spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_GeometryTessellationRayTracingNVRayTracingKHRMeshShadingNVMeshShadingEXT[] = {spv::Capability::Geometry, spv::Capability::Tessellation, spv::Capability::RayTracingNV, spv::Capability::RayTracingKHR, spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_GeometryShaderPassthroughNV[] = {spv::Capability::GeometryShaderPassthroughNV};
static const spv::Capability pygen_variable_caps_GeometryStreams[] = {spv::Capability::GeometryStreams};
static const spv::Capability pygen_variable_caps_GroupNonUniform[] = {spv::Capability::GroupNonUniform};
static const spv::Capability pygen_variable_caps_GroupNonUniformClustered[] = {spv::Capability::GroupNonUniformClustered};
static const spv::Capability pygen_variable_caps_GroupNonUniformPartitionedNV[] = {spv::Capability::GroupNonUniformPartitionedNV};
static const spv::Capability pygen_variable_caps_IOPipesINTEL[] = {spv::Capability::IOPipesINTEL};
static const spv::Capability pygen_variable_caps_ImageBasic[] = {spv::Capability::ImageBasic};
static const spv::Capability pygen_variable_caps_ImageBuffer[] = {spv::Capability::ImageBuffer};
static const spv::Capability pygen_variable_caps_ImageBufferShaderNonUniform[] = {spv::Capability::ImageBuffer, spv::Capability::ShaderNonUniform};
static const spv::Capability pygen_variable_caps_ImageGatherExtended[] = {spv::Capability::ImageGatherExtended};
static const spv::Capability pygen_variable_caps_IndirectReferencesINTEL[] = {spv::Capability::IndirectReferencesINTEL};
static const spv::Capability pygen_variable_caps_InputAttachment[] = {spv::Capability::InputAttachment};
static const spv::Capability pygen_variable_caps_InputAttachmentShaderNonUniform[] = {spv::Capability::InputAttachment, spv::Capability::ShaderNonUniform};
static const spv::Capability pygen_variable_caps_Int64[] = {spv::Capability::Int64};
static const spv::Capability pygen_variable_caps_Int64ImageEXT[] = {spv::Capability::Int64ImageEXT};
static const spv::Capability pygen_variable_caps_Int8[] = {spv::Capability::Int8};
static const spv::Capability pygen_variable_caps_Kernel[] = {spv::Capability::Kernel};
static const spv::Capability pygen_variable_caps_KernelGroupNonUniform[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniform};
static const spv::Capability pygen_variable_caps_KernelGroupNonUniformSubgroupBallotKHR[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniform, spv::Capability::SubgroupBallotKHR};
static const spv::Capability pygen_variable_caps_KernelGroupNonUniformArithmeticGroupNonUniformBallot[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniformArithmetic, spv::Capability::GroupNonUniformBallot};
static const spv::Capability pygen_variable_caps_KernelAttributesINTEL[] = {spv::Capability::KernelAttributesINTEL};
static const spv::Capability pygen_variable_caps_Linkage[] = {spv::Capability::Linkage};
static const spv::Capability pygen_variable_caps_LoopFuseINTEL[] = {spv::Capability::LoopFuseINTEL};
static const spv::Capability pygen_variable_caps_Matrix[] = {spv::Capability::Matrix};
static const spv::Capability pygen_variable_caps_MemoryAccessAliasingINTEL[] = {spv::Capability::MemoryAccessAliasingINTEL};
static const spv::Capability pygen_variable_caps_MeshShadingEXT[] = {spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_MeshShadingNV[] = {spv::Capability::MeshShadingNV};
static const spv::Capability pygen_variable_caps_MeshShadingNVMeshShadingEXT[] = {spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_MinLod[] = {spv::Capability::MinLod};
static const spv::Capability pygen_variable_caps_MultiView[] = {spv::Capability::MultiView};
static const spv::Capability pygen_variable_caps_MultiViewport[] = {spv::Capability::MultiViewport};
static const spv::Capability pygen_variable_caps_MultiViewportShaderViewportIndexShaderViewportIndexLayerEXTMeshShadingNVMeshShadingEXT[] = {spv::Capability::MultiViewport, spv::Capability::ShaderViewportIndex, spv::Capability::ShaderViewportIndexLayerEXT, spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
static const spv::Capability pygen_variable_caps_OptNoneINTEL[] = {spv::Capability::OptNoneINTEL};
static const spv::Capability pygen_variable_caps_PerViewAttributesNVMeshShadingNV[] = {spv::Capability::PerViewAttributesNV, spv::Capability::MeshShadingNV};
static const spv::Capability pygen_variable_caps_PhysicalStorageBufferAddresses[] = {spv::Capability::PhysicalStorageBufferAddresses};
static const spv::Capability pygen_variable_caps_Pipes[] = {spv::Capability::Pipes};
static const spv::Capability pygen_variable_caps_RayCullMaskKHR[] = {spv::Capability::RayCullMaskKHR};
static const spv::Capability pygen_variable_caps_RayQueryKHR[] = {spv::Capability::RayQueryKHR};
static const spv::Capability pygen_variable_caps_RayQueryKHRRayTracingKHR[] = {spv::Capability::RayQueryKHR, spv::Capability::RayTracingKHR};
static const spv::Capability pygen_variable_caps_RayTracingKHR[] = {spv::Capability::RayTracingKHR};
static const spv::Capability pygen_variable_caps_RayTracingMotionBlurNV[] = {spv::Capability::RayTracingMotionBlurNV};
static const spv::Capability pygen_variable_caps_RayTracingNV[] = {spv::Capability::RayTracingNV};
static const spv::Capability pygen_variable_caps_RayTracingNVRayTracingKHR[] = {spv::Capability::RayTracingNV, spv::Capability::RayTracingKHR};
static const spv::Capability pygen_variable_caps_RayTracingOpacityMicromapEXT[] = {spv::Capability::RayTracingOpacityMicromapEXT};
static const spv::Capability pygen_variable_caps_RayTraversalPrimitiveCullingKHR[] = {spv::Capability::RayTraversalPrimitiveCullingKHR};
static const spv::Capability pygen_variable_caps_RoundToInfinityINTEL[] = {spv::Capability::RoundToInfinityINTEL};
static const spv::Capability pygen_variable_caps_RoundingModeRTE[] = {spv::Capability::RoundingModeRTE};
static const spv::Capability pygen_variable_caps_RoundingModeRTZ[] = {spv::Capability::RoundingModeRTZ};
static const spv::Capability pygen_variable_caps_RuntimeAlignedAttributeINTEL[] = {spv::Capability::RuntimeAlignedAttributeINTEL};
static const spv::Capability pygen_variable_caps_SampleMaskOverrideCoverageNV[] = {spv::Capability::SampleMaskOverrideCoverageNV};
static const spv::Capability pygen_variable_caps_SampleMaskPostDepthCoverage[] = {spv::Capability::SampleMaskPostDepthCoverage};
static const spv::Capability pygen_variable_caps_SampleRateShading[] = {spv::Capability::SampleRateShading};
static const spv::Capability pygen_variable_caps_Sampled1D[] = {spv::Capability::Sampled1D};
static const spv::Capability pygen_variable_caps_Sampled1DImage1D[] = {spv::Capability::Sampled1D, spv::Capability::Image1D};
static const spv::Capability pygen_variable_caps_SampledBuffer[] = {spv::Capability::SampledBuffer};
static const spv::Capability pygen_variable_caps_SampledBufferImageBuffer[] = {spv::Capability::SampledBuffer, spv::Capability::ImageBuffer};
static const spv::Capability pygen_variable_caps_SampledBufferShaderNonUniform[] = {spv::Capability::SampledBuffer, spv::Capability::ShaderNonUniform};
static const spv::Capability pygen_variable_caps_SampledCubeArray[] = {spv::Capability::SampledCubeArray};
static const spv::Capability pygen_variable_caps_SampledRect[] = {spv::Capability::SampledRect};
static const spv::Capability pygen_variable_caps_SampledRectImageRect[] = {spv::Capability::SampledRect, spv::Capability::ImageRect};
static const spv::Capability pygen_variable_caps_Shader[] = {spv::Capability::Shader};
static const spv::Capability pygen_variable_caps_ShaderImageCubeArray[] = {spv::Capability::Shader, spv::Capability::ImageCubeArray};
static const spv::Capability pygen_variable_caps_ShaderKernel[] = {spv::Capability::Shader, spv::Capability::Kernel};
static const spv::Capability pygen_variable_caps_ShaderKernelImageMSArray[] = {spv::Capability::Shader, spv::Capability::Kernel, spv::Capability::ImageMSArray};
static const spv::Capability pygen_variable_caps_ShaderUniformDecoration[] = {spv::Capability::Shader, spv::Capability::UniformDecoration};
static const spv::Capability pygen_variable_caps_ShaderVectorComputeINTEL[] = {spv::Capability::Shader, spv::Capability::VectorComputeINTEL};
static const spv::Capability pygen_variable_caps_ShaderInvocationReorderNV[] = {spv::Capability::ShaderInvocationReorderNV};
static const spv::Capability pygen_variable_caps_ShaderNonUniform[] = {spv::Capability::ShaderNonUniform};
static const spv::Capability pygen_variable_caps_ShaderSMBuiltinsNV[] = {spv::Capability::ShaderSMBuiltinsNV};
static const spv::Capability pygen_variable_caps_ShaderStereoViewNV[] = {spv::Capability::ShaderStereoViewNV};
static const spv::Capability pygen_variable_caps_ShaderViewportIndexLayerNV[] = {spv::Capability::ShaderViewportIndexLayerNV};
static const spv::Capability pygen_variable_caps_ShaderViewportMaskNV[] = {spv::Capability::ShaderViewportMaskNV};
static const spv::Capability pygen_variable_caps_ShaderViewportMaskNVMeshShadingNV[] = {spv::Capability::ShaderViewportMaskNV, spv::Capability::MeshShadingNV};
static const spv::Capability pygen_variable_caps_ShadingRateNVFragmentDensityEXT[] = {spv::Capability::ShadingRateNV, spv::Capability::FragmentDensityEXT};
static const spv::Capability pygen_variable_caps_SignedZeroInfNanPreserve[] = {spv::Capability::SignedZeroInfNanPreserve};
static const spv::Capability pygen_variable_caps_StencilExportEXT[] = {spv::Capability::StencilExportEXT};
static const spv::Capability pygen_variable_caps_StorageBuffer16BitAccessStorageUniformBufferBlock16[] = {spv::Capability::StorageBuffer16BitAccess, spv::Capability::StorageUniformBufferBlock16};
static const spv::Capability pygen_variable_caps_StorageBuffer8BitAccess[] = {spv::Capability::StorageBuffer8BitAccess};
static const spv::Capability pygen_variable_caps_StorageImageExtendedFormats[] = {spv::Capability::StorageImageExtendedFormats};
static const spv::Capability pygen_variable_caps_SubgroupBallotKHRGroupNonUniformBallot[] = {spv::Capability::SubgroupBallotKHR, spv::Capability::GroupNonUniformBallot};
static const spv::Capability pygen_variable_caps_SubgroupDispatch[] = {spv::Capability::SubgroupDispatch};
static const spv::Capability pygen_variable_caps_Tessellation[] = {spv::Capability::Tessellation};
static const spv::Capability pygen_variable_caps_TransformFeedback[] = {spv::Capability::TransformFeedback};
static const spv::Capability pygen_variable_caps_USMStorageClassesINTEL[] = {spv::Capability::USMStorageClassesINTEL};
static const spv::Capability pygen_variable_caps_VariablePointersStorageBuffer[] = {spv::Capability::VariablePointersStorageBuffer};
static const spv::Capability pygen_variable_caps_VectorAnyINTEL[] = {spv::Capability::VectorAnyINTEL};
static const spv::Capability pygen_variable_caps_VectorComputeINTEL[] = {spv::Capability::VectorComputeINTEL};
static const spv::Capability pygen_variable_caps_VulkanMemoryModel[] = {spv::Capability::VulkanMemoryModel};
static const spv::Capability pygen_variable_caps_WorkgroupMemoryExplicitLayoutKHR[] = {spv::Capability::WorkgroupMemoryExplicitLayoutKHR};
static const spvtools::Extension pygen_variable_exts_SPV_AMD_gpu_shader_half_float_fetch[] = {spvtools::Extension::kSPV_AMD_gpu_shader_half_float_fetch};
static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_ballot[] = {spvtools::Extension::kSPV_AMD_shader_ballot};
@@ -162,6 +166,8 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_float_controls2[]
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fp_fast_math_mode[] = {spvtools::Extension::kSPV_INTEL_fp_fast_math_mode};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_buffer_location[] = {spvtools::Extension::kSPV_INTEL_fpga_buffer_location};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_cluster_attributes[] = {spvtools::Extension::kSPV_INTEL_fpga_cluster_attributes};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_dsp_control[] = {spvtools::Extension::kSPV_INTEL_fpga_dsp_control};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_invocation_pipelining_attributes[] = {spvtools::Extension::kSPV_INTEL_fpga_invocation_pipelining_attributes};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_loop_controls[] = {spvtools::Extension::kSPV_INTEL_fpga_loop_controls};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_memory_accesses[] = {spvtools::Extension::kSPV_INTEL_fpga_memory_accesses};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_fpga_memory_attributes[] = {spvtools::Extension::kSPV_INTEL_fpga_memory_attributes};
@@ -175,6 +181,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_loop_fuse[] = {sp
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_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_runtime_aligned[] = {spvtools::Extension::kSPV_INTEL_runtime_aligned};
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};
@@ -224,6 +231,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing[] = {spv
static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing_motion_blur[] = {spvtools::Extension::kSPV_NV_ray_tracing_motion_blur};
static const spvtools::Extension pygen_variable_exts_SPV_NV_sample_mask_override_coverage[] = {spvtools::Extension::kSPV_NV_sample_mask_override_coverage};
static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_image_footprint[] = {spvtools::Extension::kSPV_NV_shader_image_footprint};
static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_invocation_reorder[] = {spvtools::Extension::kSPV_NV_shader_invocation_reorder};
static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_sm_builtins[] = {spvtools::Extension::kSPV_NV_shader_sm_builtins};
static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_subgroup_partitioned[] = {spvtools::Extension::kSPV_NV_shader_subgroup_partitioned};
static const spvtools::Extension pygen_variable_exts_SPV_NV_stereo_view_rendering[] = {spvtools::Extension::kSPV_NV_stereo_view_rendering};
@@ -281,14 +289,16 @@ static const spv_operand_desc_t pygen_variable_LoopControlEntries[] = {
{"IterationMultiple", 0x0040, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu},
{"PeelCount", 0x0080, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu},
{"PartialCount", 0x0100, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu},
{"InitiationIntervalINTEL", 0x10000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 1, pygen_variable_exts_SPV_INTEL_fpga_loop_controls, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"MaxConcurrencyINTEL", 0x20000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 1, pygen_variable_exts_SPV_INTEL_fpga_loop_controls, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"DependencyArrayINTEL", 0x40000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 1, pygen_variable_exts_SPV_INTEL_fpga_loop_controls, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"PipelineEnableINTEL", 0x80000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 1, pygen_variable_exts_SPV_INTEL_fpga_loop_controls, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"LoopCoalesceINTEL", 0x100000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 1, pygen_variable_exts_SPV_INTEL_fpga_loop_controls, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"MaxInterleavingINTEL", 0x200000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 1, pygen_variable_exts_SPV_INTEL_fpga_loop_controls, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"SpeculatedIterationsINTEL", 0x400000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 1, pygen_variable_exts_SPV_INTEL_fpga_loop_controls, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"NoFusionINTEL", 0x800000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 1, pygen_variable_exts_SPV_INTEL_fpga_loop_controls, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu}
{"InitiationIntervalINTEL", 0x10000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"MaxConcurrencyINTEL", 0x20000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"DependencyArrayINTEL", 0x40000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"PipelineEnableINTEL", 0x80000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"LoopCoalesceINTEL", 0x100000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"MaxInterleavingINTEL", 0x200000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"SpeculatedIterationsINTEL", 0x400000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"NoFusionINTEL", 0x800000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"LoopCountINTEL", 0x1000000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"MaxReinvocationDelayINTEL", 0x2000000, 1, pygen_variable_caps_FPGALoopControlsINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_FunctionControlEntries[] = {
@@ -495,6 +505,7 @@ static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = {
{"NoGlobalOffsetINTEL", 5895, 1, pygen_variable_caps_KernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {}, 0xffffffffu, 0xffffffffu},
{"NumSIMDWorkitemsINTEL", 5896, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"SchedulerTargetFmaxMhzINTEL", 5903, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"StreamingInterfaceINTEL", 6154, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"NamedBarrierCountINTEL", 6417, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu}
};
@@ -526,6 +537,7 @@ static const spv_operand_desc_t pygen_variable_StorageClassEntries[] = {
{"ShaderRecordBufferKHR", 5343, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"PhysicalStorageBuffer", 5349, 1, pygen_variable_caps_PhysicalStorageBufferAddresses, 2, pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
{"PhysicalStorageBufferEXT", 5349, 1, pygen_variable_caps_PhysicalStorageBufferAddresses, 2, pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
{"HitObjectAttributeNV", 5385, 1, pygen_variable_caps_ShaderInvocationReorderNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"TaskPayloadWorkgroupEXT", 5402, 1, pygen_variable_caps_MeshShadingEXT, 1, pygen_variable_exts_SPV_EXT_mesh_shader, {}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu},
{"CodeSectionINTEL", 5605, 1, pygen_variable_caps_FunctionPointersINTEL, 1, pygen_variable_exts_SPV_INTEL_function_pointers, {}, 0xffffffffu, 0xffffffffu},
{"DeviceOnlyINTEL", 5936, 1, pygen_variable_caps_USMStorageClassesINTEL, 1, pygen_variable_exts_SPV_INTEL_usm_storage_classes, {}, 0xffffffffu, 0xffffffffu},
@@ -698,7 +710,8 @@ static const spv_operand_desc_t pygen_variable_FunctionParameterAttributeEntries
{"NoAlias", 4, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"NoCapture", 5, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"NoWrite", 6, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"NoReadWrite", 7, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"NoReadWrite", 7, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"RuntimeAlignedINTEL", 5940, 1, pygen_variable_caps_RuntimeAlignedAttributeINTEL, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
@@ -768,6 +781,7 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
{"RestrictPointerEXT", 5355, 1, pygen_variable_caps_PhysicalStorageBufferAddresses, 2, pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
{"AliasedPointer", 5356, 1, pygen_variable_caps_PhysicalStorageBufferAddresses, 2, pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
{"AliasedPointerEXT", 5356, 1, pygen_variable_caps_PhysicalStorageBufferAddresses, 2, pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
{"HitObjectShaderRecordBufferNV", 5386, 1, pygen_variable_caps_ShaderInvocationReorderNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"BindlessSamplerNV", 5398, 1, pygen_variable_caps_BindlessTextureNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"BindlessImageNV", 5399, 1, pygen_variable_caps_BindlessTextureNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"BoundSamplerNV", 5400, 1, pygen_variable_caps_BindlessTextureNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
@@ -806,8 +820,12 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
{"PrefetchINTEL", 5902, 1, pygen_variable_caps_FPGAMemoryAccessesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"StallEnableINTEL", 5905, 1, pygen_variable_caps_FPGAClusterAttributesINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"FuseLoopsInFunctionINTEL", 5907, 1, pygen_variable_caps_LoopFuseINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"MathOpDSPModeINTEL", 5909, 1, pygen_variable_caps_FPGADSPControlINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"AliasScopeINTEL", 5914, 1, pygen_variable_caps_MemoryAccessAliasingINTEL, 0, nullptr, {SPV_OPERAND_TYPE_ID}, 0xffffffffu, 0xffffffffu},
{"NoAliasINTEL", 5915, 1, pygen_variable_caps_MemoryAccessAliasingINTEL, 0, nullptr, {SPV_OPERAND_TYPE_ID}, 0xffffffffu, 0xffffffffu},
{"InitiationIntervalINTEL", 5917, 1, pygen_variable_caps_FPGAInvocationPipeliningAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"MaxConcurrencyINTEL", 5918, 1, pygen_variable_caps_FPGAInvocationPipeliningAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"PipelineEnableINTEL", 5919, 1, pygen_variable_caps_FPGAInvocationPipeliningAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"BufferLocationINTEL", 5921, 1, pygen_variable_caps_FPGABufferLocationINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"IOPipeStorageINTEL", 5944, 1, pygen_variable_caps_IOPipesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
{"FunctionFloatingPointModeINTEL", 6080, 1, pygen_variable_caps_FunctionFloatControlINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_FPOPERATION_MODE}, 0xffffffffu, 0xffffffffu},
@@ -1146,6 +1164,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"DemoteToHelperInvocation", 5379, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, {}, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu},
{"DemoteToHelperInvocationEXT", 5379, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, {}, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu},
{"RayTracingOpacityMicromapEXT", 5381, 2, pygen_variable_caps_RayQueryKHRRayTracingKHR, 1, pygen_variable_exts_SPV_EXT_opacity_micromap, {}, 0xffffffffu, 0xffffffffu},
{"ShaderInvocationReorderNV", 5383, 1, pygen_variable_caps_RayTracingKHR, 1, pygen_variable_exts_SPV_NV_shader_invocation_reorder, {}, 0xffffffffu, 0xffffffffu},
{"BindlessTextureNV", 5390, 0, nullptr, 1, pygen_variable_exts_SPV_NV_bindless_texture, {}, 0xffffffffu, 0xffffffffu},
{"SubgroupShuffleINTEL", 5568, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
{"SubgroupBufferBlockIOINTEL", 5569, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
@@ -1179,10 +1198,13 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"FPGAMemoryAccessesINTEL", 5898, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_memory_accesses, {}, 0xffffffffu, 0xffffffffu},
{"FPGAClusterAttributesINTEL", 5904, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_cluster_attributes, {}, 0xffffffffu, 0xffffffffu},
{"LoopFuseINTEL", 5906, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_loop_fuse, {}, 0xffffffffu, 0xffffffffu},
{"FPGADSPControlINTEL", 5908, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_dsp_control, {}, 0xffffffffu, 0xffffffffu},
{"MemoryAccessAliasingINTEL", 5910, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_memory_access_aliasing, {}, 0xffffffffu, 0xffffffffu},
{"FPGAInvocationPipeliningAttributesINTEL", 5916, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_invocation_pipelining_attributes, {}, 0xffffffffu, 0xffffffffu},
{"FPGABufferLocationINTEL", 5920, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_buffer_location, {}, 0xffffffffu, 0xffffffffu},
{"ArbitraryPrecisionFixedPointINTEL", 5922, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_arbitrary_precision_fixed_point, {}, 0xffffffffu, 0xffffffffu},
{"USMStorageClassesINTEL", 5935, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_usm_storage_classes, {}, 0xffffffffu, 0xffffffffu},
{"RuntimeAlignedAttributeINTEL", 5939, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_runtime_aligned, {}, 0xffffffffu, 0xffffffffu},
{"IOPipesINTEL", 5943, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_io_pipes, {}, 0xffffffffu, 0xffffffffu},
{"BlockingPipesINTEL", 5945, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_blocking_pipes, {}, 0xffffffffu, 0xffffffffu},
{"FPGARegINTEL", 5948, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_reg, {}, 0xffffffffu, 0xffffffffu},

View File

@@ -36,16 +36,25 @@ namespace spvtools {
// generated by InstrumentPass::GenDebugStreamWrite. This method is utilized
// by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass.
//
// The first member of the debug output buffer contains the next available word
// The 1st member of the debug output buffer contains a set of flags
// controlling the behavior of instrumentation code.
static const int kDebugOutputFlagsOffset = 0;
// Values stored at kDebugOutputFlagsOffset
enum kInstFlags : unsigned int {
kInstBufferOOBEnable = 0x1,
};
// The 2nd member of the debug output buffer contains the next available word
// in the data stream to be written. Shaders will atomically read and update
// this value so as not to overwrite each others records. This value must be
// initialized to zero
static const int kDebugOutputSizeOffset = 0;
static const int kDebugOutputSizeOffset = 1;
// The second member of the output buffer is the start of the stream of records
// The 3rd member of the output buffer is the start of the stream of records
// written by the instrumented shaders. Each record represents a validation
// error. The format of the records is documented below.
static const int kDebugOutputDataOffset = 1;
static const int kDebugOutputDataOffset = 2;
// Common Stream Record Offsets
//

View File

@@ -19,6 +19,7 @@
#include <ostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
@@ -520,8 +521,12 @@ Optimizer::PassToken CreateDeadInsertElimPass();
// interface are considered live and are not eliminated. This mode is needed
// by GPU-Assisted validation instrumentation, where a change in the interface
// is not allowed.
Optimizer::PassToken CreateAggressiveDCEPass();
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface);
//
// If |remove_outputs| is true, allow outputs to be removed from the interface.
// This is only safe if the caller knows that there is no corresponding input
// variable in the following shader. It is false by default.
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface = false,
bool remove_outputs = false);
// Creates a remove-unused-interface-variables pass.
// Removes variables referenced on the |OpEntryPoint| instruction that are not
@@ -887,12 +892,59 @@ Optimizer::PassToken CreateAmdExtToKhrPass();
Optimizer::PassToken CreateInterpolateFixupPass();
// Removes unused components from composite input variables. Current
// implementation just removes trailing unused components from input arrays.
// The pass performs best after maximizing dead code removal. A subsequent dead
// code elimination pass would be beneficial in removing newly unused component
// types.
// implementation just removes trailing unused components from input arrays
// and structs. The pass performs best after maximizing dead code removal.
// A subsequent dead code elimination pass would be beneficial in removing
// newly unused component types.
//
// WARNING: This pass can only be safely applied standalone to vertex shaders
// as it can otherwise cause interface incompatibilities with the preceding
// shader in the pipeline. If applied to non-vertex shaders, the user should
// follow by applying EliminateDeadOutputStores and
// EliminateDeadOutputComponents to the preceding shader.
Optimizer::PassToken CreateEliminateDeadInputComponentsPass();
// Removes unused components from composite output variables. Current
// implementation just removes trailing unused components from output arrays
// and structs. The pass performs best after eliminating dead output stores.
// A subsequent dead code elimination pass would be beneficial in removing
// newly unused component types. Currently only supports vertex and fragment
// shaders.
//
// WARNING: This pass cannot be safely applied standalone as it can cause
// interface incompatibility with the following shader in the pipeline. The
// user should first apply EliminateDeadInputComponents to the following
// shader, then apply EliminateDeadOutputStores to this shader.
Optimizer::PassToken CreateEliminateDeadOutputComponentsPass();
// Removes unused components from composite input variables. This safe
// version will not cause interface incompatibilities since it only changes
// vertex shaders. The current implementation just removes trailing unused
// components from input structs and input arrays. The pass performs best
// after maximizing dead code removal. A subsequent dead code elimination
// pass would be beneficial in removing newly unused component types.
Optimizer::PassToken CreateEliminateDeadInputComponentsSafePass();
// Analyzes shader and populates |live_locs| and |live_builtins|. Best results
// will be obtained if shader has all dead code eliminated first. |live_locs|
// and |live_builtins| are subsequently used when calling
// CreateEliminateDeadOutputStoresPass on the preceding shader. Currently only
// supports tesc, tese, geom, and frag shaders.
Optimizer::PassToken CreateAnalyzeLiveInputPass(
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins);
// Removes stores to output locations not listed in |live_locs| or
// |live_builtins|. Best results are obtained if constant propagation is
// performed first. A subsequent call to ADCE will eliminate any dead code
// created by the removal of the stores. A subsequent call to
// CreateEliminateDeadOutputComponentsPass will eliminate any dead output
// components created by the elimination of the stores. Currently only supports
// vert, tesc, tese, and geom shaders.
Optimizer::PassToken CreateEliminateDeadOutputStoresPass(
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins);
// Creates a convert-to-sampled-image pass to convert images and/or
// samplers with given pairs of descriptor set and binding to sampled image.
// If a pair of an image and a sampler have the same pair of descriptor set and

View File

@@ -78,16 +78,16 @@ spv_result_t spvTextParseMaskOperand(spv_target_env env,
// Associates an opcode with its name.
struct SpecConstantOpcodeEntry {
SpvOp opcode;
spv::Op opcode;
const char* name;
};
// All the opcodes allowed as the operation for OpSpecConstantOp.
// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
// is associated with the name "IAdd".
// The name does not have the usual "Op" prefix. For example opcode
// spv::Op::IAdd is associated with the name "IAdd".
//
// clang-format off
#define CASE(NAME) { SpvOp##NAME, #NAME }
#define CASE(NAME) { spv::Op::Op##NAME, #NAME }
const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
// Conversion
CASE(SConvert),
@@ -173,7 +173,7 @@ bool AssemblyGrammar::isValid() const {
}
CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
const SpvCapability* cap_array, uint32_t count) const {
const spv::Capability* cap_array, uint32_t count) const {
CapabilitySet cap_set;
for (uint32_t i = 0; i < count; ++i) {
spv_operand_desc cap_desc = {};
@@ -194,7 +194,7 @@ spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
return spvOpcodeTableNameLookup(target_env_, opcodeTable_, name, desc);
}
spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
spv_result_t AssemblyGrammar::lookupOpcode(spv::Op opcode,
spv_opcode_desc* desc) const {
return spvOpcodeTableValueLookup(target_env_, opcodeTable_, opcode, desc);
}
@@ -214,7 +214,7 @@ spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
}
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
SpvOp* opcode) const {
spv::Op* opcode) const {
const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
const auto* found =
std::find_if(kOpSpecConstantOpcodes, last,
@@ -226,7 +226,7 @@ spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
return SPV_SUCCESS;
}
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(spv::Op opcode) const {
const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
const auto* found =
std::find_if(kOpSpecConstantOpcodes, last,

View File

@@ -41,7 +41,7 @@ class AssemblyGrammar {
// Removes capabilities not available in the current target environment and
// returns the rest.
CapabilitySet filterCapsAgainstTargetEnv(const SpvCapability* cap_array,
CapabilitySet filterCapsAgainstTargetEnv(const spv::Capability* cap_array,
uint32_t count) const;
// Fills in the desc parameter with the information about the opcode
@@ -52,7 +52,7 @@ class AssemblyGrammar {
// Fills in the desc parameter with the information about the opcode
// of the valid. Returns SPV_SUCCESS if the opcode was found, and
// SPV_ERROR_INVALID_LOOKUP if the opcode does not exist.
spv_result_t lookupOpcode(SpvOp opcode, spv_opcode_desc* desc) const;
spv_result_t lookupOpcode(spv::Op opcode, spv_opcode_desc* desc) const;
// Fills in the desc parameter with the information about the given
// operand. Returns SPV_SUCCESS if the operand was found, and
@@ -82,11 +82,12 @@ class AssemblyGrammar {
// the integer add opcode for OpSpecConstantOp. On success, returns
// SPV_SUCCESS and sends the discovered operation code through the opcode
// parameter. On failure, returns SPV_ERROR_INVALID_LOOKUP.
spv_result_t lookupSpecConstantOpcode(const char* name, SpvOp* opcode) const;
spv_result_t lookupSpecConstantOpcode(const char* name,
spv::Op* opcode) const;
// Returns SPV_SUCCESS if the given opcode is valid as the opcode operand
// to OpSpecConstantOp.
spv_result_t lookupSpecConstantOpcode(SpvOp opcode) const;
spv_result_t lookupSpecConstantOpcode(spv::Op opcode) const;
// Parses a mask expression string for the given operand type.
//

View File

@@ -156,7 +156,7 @@ class Parser {
// Issues a diagnostic describing an exhaustion of input condition when
// trying to decode an instruction operand, and returns
// SPV_ERROR_INVALID_BINARY.
spv_result_t exhaustedInputDiagnostic(size_t inst_offset, SpvOp opcode,
spv_result_t exhaustedInputDiagnostic(size_t inst_offset, spv::Op opcode,
spv_operand_type_t type) {
return diagnostic() << "End of input reached while decoding Op"
<< spvOpcodeString(opcode) << " starting at word "
@@ -318,7 +318,7 @@ spv_result_t Parser::parseInstruction() {
<< inst_word_count;
}
spv_opcode_desc opcode_desc;
if (grammar_.lookupOpcode(static_cast<SpvOp>(inst.opcode), &opcode_desc))
if (grammar_.lookupOpcode(static_cast<spv::Op>(inst.opcode), &opcode_desc))
return diagnostic() << "Invalid opcode: " << inst.opcode;
// Advance past the opcode word. But remember the of the start
@@ -418,7 +418,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
std::vector<uint32_t>* words,
std::vector<spv_parsed_operand_t>* operands,
spv_operand_pattern_t* expected_operands) {
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
// We'll fill in this result as we go along.
spv_parsed_operand_t parsed_operand;
parsed_operand.offset = uint16_t(_.word_index - inst_offset);
@@ -473,7 +473,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
parsed_operand.type = SPV_OPERAND_TYPE_ID;
if (opcode == SpvOpExtInst && parsed_operand.offset == 3) {
if (opcode == spv::Op::OpExtInst && parsed_operand.offset == 3) {
// The current word is the extended instruction set Id.
// Set the extended instruction set type for the current instruction.
auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
@@ -494,7 +494,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
break;
case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
assert(SpvOpExtInst == opcode);
assert(spv::Op::OpExtInst == opcode);
assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
spv_ext_inst_desc ext_inst;
if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) ==
@@ -516,14 +516,14 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
} break;
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
assert(SpvOpSpecConstantOp == opcode);
if (word > static_cast<uint32_t>(SpvOp::SpvOpMax) ||
grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
assert(spv::Op::OpSpecConstantOp == opcode);
if (word > static_cast<uint32_t>(spv::Op::Max) ||
grammar_.lookupSpecConstantOpcode(spv::Op(word))) {
return diagnostic()
<< "Invalid " << spvOperandTypeStr(type) << ": " << word;
}
spv_opcode_desc opcode_entry = nullptr;
if (grammar_.lookupOpcode(SpvOp(word), &opcode_entry)) {
if (grammar_.lookupOpcode(spv::Op(word), &opcode_entry)) {
return diagnostic(SPV_ERROR_INTERNAL)
<< "OpSpecConstant opcode table out of sync";
}
@@ -549,7 +549,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
if (opcode == SpvOpSwitch) {
if (opcode == spv::Op::OpSwitch) {
// The literal operands have the same type as the value
// referenced by the selector Id.
const uint32_t selector_id = peekAt(inst_offset + 1);
@@ -575,7 +575,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
<< " is not a scalar integer";
}
} else {
assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant);
assert(opcode == spv::Op::OpConstant ||
opcode == spv::Op::OpSpecConstant);
// The literal number type is determined by the type Id for the
// constant.
assert(inst->type_id);
@@ -607,7 +608,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
parsed_operand.num_words = uint16_t(string_num_words);
parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
if (SpvOpExtInstImport == opcode) {
if (spv::Op::OpExtInstImport == opcode) {
// Record the extended instruction type for the ID for this import.
// There is only one string literal argument to OpExtInstImport,
// so it's sufficient to guard this just on the opcode.
@@ -789,14 +790,14 @@ spv_result_t Parser::setNumericTypeInfoForType(
void Parser::recordNumberType(size_t inst_offset,
const spv_parsed_instruction_t* inst) {
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
if (spvOpcodeGeneratesType(opcode)) {
NumberType info = {SPV_NUMBER_NONE, 0};
if (SpvOpTypeInt == opcode) {
if (spv::Op::OpTypeInt == opcode) {
const bool is_signed = peekAt(inst_offset + 3) != 0;
info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
info.bit_width = peekAt(inst_offset + 2);
} else if (SpvOpTypeFloat == opcode) {
} else if (spv::Op::OpTypeFloat == opcode) {
info.type = SPV_NUMBER_FLOATING;
info.bit_width = peekAt(inst_offset + 2);
}

View File

@@ -44,8 +44,8 @@ using IdGroup = std::vector<uint32_t>;
// different implementations produce identical results.
using IdGroupMapByName = std::map<std::string, IdGroup>;
using IdGroupMapByTypeId = std::map<uint32_t, IdGroup>;
using IdGroupMapByOp = std::map<SpvOp, IdGroup>;
using IdGroupMapByStorageClass = std::map<SpvStorageClass, IdGroup>;
using IdGroupMapByOp = std::map<spv::Op, IdGroup>;
using IdGroupMapByStorageClass = std::map<spv::StorageClass, IdGroup>;
// A set of potential id mappings that haven't been resolved yet. Any id in src
// may map in any id in dst. Note that ids are added in the same order as they
@@ -301,10 +301,10 @@ class Differ {
// Get various properties from an id. These Helper functions are passed to
// `GroupIds` and `GroupIdsAndMatch` below (as the `get_group` argument).
uint32_t GroupIdsHelperGetTypeId(const IdInstructions& id_to, uint32_t id);
SpvStorageClass GroupIdsHelperGetTypePointerStorageClass(
spv::StorageClass GroupIdsHelperGetTypePointerStorageClass(
const IdInstructions& id_to, uint32_t id);
SpvOp GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
uint32_t id);
spv::Op GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
uint32_t id);
// Given a list of ids, groups them based on some value. The `get_group`
// function extracts a piece of information corresponding to each id, and the
@@ -414,8 +414,8 @@ class Differ {
// Helper functions to retrieve information pertaining to an id
const opt::Instruction* GetInst(const IdInstructions& id_to, uint32_t id);
uint32_t GetConstantUint(const IdInstructions& id_to, uint32_t constant_id);
SpvExecutionModel GetExecutionModel(const opt::Module* module,
uint32_t entry_point_id);
spv::ExecutionModel GetExecutionModel(const opt::Module* module,
uint32_t entry_point_id);
bool HasName(const IdInstructions& id_to, uint32_t id);
// Get the OpName associated with an id
std::string GetName(const IdInstructions& id_to, uint32_t id, bool* has_name);
@@ -424,20 +424,21 @@ class Differ {
// string, and this improves diff between SPIR-V from those tools and others.
std::string GetSanitizedName(const IdInstructions& id_to, uint32_t id);
uint32_t GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
SpvStorageClass* storage_class);
spv::StorageClass* storage_class);
bool GetDecorationValue(const IdInstructions& id_to, uint32_t id,
SpvDecoration decoration, uint32_t* decoration_value);
spv::Decoration decoration,
uint32_t* decoration_value);
const opt::Instruction* GetForwardPointerInst(const IdInstructions& id_to,
uint32_t id);
bool IsIntType(const IdInstructions& id_to, uint32_t type_id);
bool IsFloatType(const IdInstructions& id_to, uint32_t type_id);
bool IsConstantUint(const IdInstructions& id_to, uint32_t id);
bool IsVariable(const IdInstructions& id_to, uint32_t pointer_id);
bool IsOp(const IdInstructions& id_to, uint32_t id, SpvOp opcode);
bool IsOp(const IdInstructions& id_to, uint32_t id, spv::Op opcode);
bool IsPerVertexType(const IdInstructions& id_to, uint32_t type_id);
bool IsPerVertexVariable(const IdInstructions& id_to, uint32_t type_id);
SpvStorageClass GetPerVertexStorageClass(const opt::Module* module,
uint32_t type_id);
spv::StorageClass GetPerVertexStorageClass(const opt::Module* module,
uint32_t type_id);
spv_ext_inst_type_t GetExtInstType(const IdInstructions& id_to,
uint32_t set_id);
spv_number_kind_t GetNumberKind(const IdInstructions& id_to,
@@ -561,19 +562,19 @@ void IdInstructions::MapIdsToInfos(
uint32_t id_operand = 0;
switch (inst.opcode()) {
case SpvOpName:
case spv::Op::OpName:
info_map = &name_map_;
break;
case SpvOpMemberName:
case spv::Op::OpMemberName:
info_map = &name_map_;
break;
case SpvOpDecorate:
case spv::Op::OpDecorate:
info_map = &decoration_map_;
break;
case SpvOpMemberDecorate:
case spv::Op::OpMemberDecorate:
info_map = &decoration_map_;
break;
case SpvOpTypeForwardPointer: {
case spv::Op::OpTypeForwardPointer: {
uint32_t id = inst.GetSingleWordOperand(0);
assert(id != 0);
@@ -731,10 +732,10 @@ int Differ::ComparePreambleInstructions(const opt::Instruction* a,
// Instead of comparing OpExecutionMode entry point ids as ids, compare them
// through their corresponding execution model. This simplifies traversing
// the sorted list of instructions between src and dst modules.
if (a->opcode() == SpvOpExecutionMode) {
const SpvExecutionModel src_model =
if (a->opcode() == spv::Op::OpExecutionMode) {
const spv::ExecutionModel src_model =
GetExecutionModel(src_inst_module, a->GetSingleWordOperand(0));
const SpvExecutionModel dst_model =
const spv::ExecutionModel dst_model =
GetExecutionModel(dst_inst_module, b->GetSingleWordOperand(0));
if (src_model < dst_model) {
@@ -818,17 +819,17 @@ uint32_t Differ::GroupIdsHelperGetTypeId(const IdInstructions& id_to,
return GetInst(id_to, id)->type_id();
}
SpvStorageClass Differ::GroupIdsHelperGetTypePointerStorageClass(
spv::StorageClass Differ::GroupIdsHelperGetTypePointerStorageClass(
const IdInstructions& id_to, uint32_t id) {
const opt::Instruction* inst = GetInst(id_to, id);
assert(inst && inst->opcode() == SpvOpTypePointer);
return SpvStorageClass(inst->GetSingleWordInOperand(0));
assert(inst && inst->opcode() == spv::Op::OpTypePointer);
return spv::StorageClass(inst->GetSingleWordInOperand(0));
}
SpvOp Differ::GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
uint32_t id) {
spv::Op Differ::GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
uint32_t id) {
const opt::Instruction* inst = GetInst(id_to, id);
assert(inst && inst->opcode() == SpvOpTypePointer);
assert(inst && inst->opcode() == spv::Op::OpTypePointer);
const uint32_t type_id = inst->GetSingleWordInOperand(1);
const opt::Instruction* type_inst = GetInst(id_to, type_id);
@@ -1020,7 +1021,7 @@ bool Differ::DoInstructionsMatchFuzzy(const opt::Instruction* src_inst,
}
// For external instructions, make sure the set and opcode of the external
// instruction matches too.
if (src_inst->opcode() == SpvOpExtInst) {
if (src_inst->opcode() == spv::Op::OpExtInst) {
if (!DoOperandsMatch(src_inst, dst_inst, 0, 2)) {
return false;
}
@@ -1064,26 +1065,26 @@ bool Differ::DoDebugAndAnnotationInstructionsMatch(
}
switch (src_inst->opcode()) {
case SpvOpString:
case SpvOpSourceExtension:
case SpvOpModuleProcessed:
case spv::Op::OpString:
case spv::Op::OpSourceExtension:
case spv::Op::OpModuleProcessed:
return DoesOperandMatch(src_inst->GetOperand(0), dst_inst->GetOperand(0));
case SpvOpSource:
case spv::Op::OpSource:
return DoOperandsMatch(src_inst, dst_inst, 0, 2);
case SpvOpSourceContinued:
case spv::Op::OpSourceContinued:
return true;
case SpvOpName:
case spv::Op::OpName:
return DoOperandsMatch(src_inst, dst_inst, 0, 1);
case SpvOpMemberName:
case spv::Op::OpMemberName:
return DoOperandsMatch(src_inst, dst_inst, 0, 2);
case SpvOpDecorate:
case spv::Op::OpDecorate:
return DoOperandsMatch(src_inst, dst_inst, 0, 2);
case SpvOpMemberDecorate:
case spv::Op::OpMemberDecorate:
return DoOperandsMatch(src_inst, dst_inst, 0, 3);
case SpvOpExtInst:
case SpvOpDecorationGroup:
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate:
case spv::Op::OpExtInst:
case spv::Op::OpDecorationGroup:
case spv::Op::OpGroupDecorate:
case spv::Op::OpGroupMemberDecorate:
return false;
default:
return false;
@@ -1095,9 +1096,9 @@ bool Differ::AreVariablesMatchable(uint32_t src_id, uint32_t dst_id,
// Variables must match by their built-in decorations.
uint32_t src_built_in_decoration = 0, dst_built_in_decoration = 0;
const bool src_is_built_in = GetDecorationValue(
src_id_to_, src_id, SpvDecorationBuiltIn, &src_built_in_decoration);
src_id_to_, src_id, spv::Decoration::BuiltIn, &src_built_in_decoration);
const bool dst_is_built_in = GetDecorationValue(
dst_id_to_, dst_id, SpvDecorationBuiltIn, &dst_built_in_decoration);
dst_id_to_, dst_id, spv::Decoration::BuiltIn, &dst_built_in_decoration);
if (src_is_built_in != dst_is_built_in) {
return false;
@@ -1107,7 +1108,7 @@ bool Differ::AreVariablesMatchable(uint32_t src_id, uint32_t dst_id,
}
// Check their types and storage classes.
SpvStorageClass src_storage_class, dst_storage_class;
spv::StorageClass src_storage_class, dst_storage_class;
const uint32_t src_type_id =
GetVarTypeId(src_id_to_, src_id, &src_storage_class);
const uint32_t dst_type_id =
@@ -1127,12 +1128,14 @@ bool Differ::AreVariablesMatchable(uint32_t src_id, uint32_t dst_id,
// Allow one of the two to be Private while the other is Input or
// Output, this allows matching in/out variables that have been turned
// global as part of linking two stages (as done in ANGLE).
const bool src_is_io = src_storage_class == SpvStorageClassInput ||
src_storage_class == SpvStorageClassOutput;
const bool dst_is_io = dst_storage_class == SpvStorageClassInput ||
dst_storage_class == SpvStorageClassOutput;
const bool src_is_private = src_storage_class == SpvStorageClassPrivate;
const bool dst_is_private = dst_storage_class == SpvStorageClassPrivate;
const bool src_is_io = src_storage_class == spv::StorageClass::Input ||
src_storage_class == spv::StorageClass::Output;
const bool dst_is_io = dst_storage_class == spv::StorageClass::Input ||
dst_storage_class == spv::StorageClass::Output;
const bool src_is_private =
src_storage_class == spv::StorageClass::Private;
const bool dst_is_private =
dst_storage_class == spv::StorageClass::Private;
if (!((src_is_io && dst_is_private) || (src_is_private && dst_is_io))) {
return false;
@@ -1277,16 +1280,16 @@ bool Differ::MatchOpSpecConstant(const opt::Instruction* src_inst,
// Otherwise, match them by SpecId.
uint32_t src_spec_id, dst_spec_id;
if (GetDecorationValue(src_id_to_, src_id, SpvDecorationSpecId,
if (GetDecorationValue(src_id_to_, src_id, spv::Decoration::SpecId,
&src_spec_id) &&
GetDecorationValue(dst_id_to_, dst_id, SpvDecorationSpecId,
GetDecorationValue(dst_id_to_, dst_id, spv::Decoration::SpecId,
&dst_spec_id)) {
return src_spec_id == dst_spec_id;
}
// There is no SpecId decoration, while not practical, still valid.
// SpecConstantOp don't have SpecId and can be matched by operands
if (src_inst->opcode() == SpvOpSpecConstantOp) {
if (src_inst->opcode() == spv::Op::OpSpecConstantOp) {
if (src_inst->NumInOperandWords() == dst_inst->NumInOperandWords()) {
return DoOperandsMatch(src_inst, dst_inst, 0,
src_inst->NumInOperandWords());
@@ -1327,13 +1330,13 @@ bool Differ::MatchOpVariable(const opt::Instruction* src_inst,
// built-in decorations.
uint32_t src_built_in_decoration;
const bool src_is_built_in = GetDecorationValue(
src_id_to_, src_id, SpvDecorationBuiltIn, &src_built_in_decoration);
src_id_to_, src_id, spv::Decoration::BuiltIn, &src_built_in_decoration);
if (src_is_built_in && AreVariablesMatchable(src_id, dst_id, flexibility)) {
return true;
}
SpvStorageClass src_storage_class, dst_storage_class;
spv::StorageClass src_storage_class, dst_storage_class;
GetVarTypeId(src_id_to_, src_id, &src_storage_class);
GetVarTypeId(dst_id_to_, dst_id, &dst_storage_class);
@@ -1348,13 +1351,13 @@ bool Differ::MatchOpVariable(const opt::Instruction* src_inst,
uint32_t src_binding = 0, dst_binding = 0;
const bool src_has_set = GetDecorationValue(
src_id_to_, src_id, SpvDecorationDescriptorSet, &src_set);
src_id_to_, src_id, spv::Decoration::DescriptorSet, &src_set);
const bool dst_has_set = GetDecorationValue(
dst_id_to_, dst_id, SpvDecorationDescriptorSet, &dst_set);
const bool src_has_binding =
GetDecorationValue(src_id_to_, src_id, SpvDecorationBinding, &src_set);
const bool dst_has_binding =
GetDecorationValue(dst_id_to_, dst_id, SpvDecorationBinding, &dst_set);
dst_id_to_, dst_id, spv::Decoration::DescriptorSet, &dst_set);
const bool src_has_binding = GetDecorationValue(
src_id_to_, src_id, spv::Decoration::Binding, &src_set);
const bool dst_has_binding = GetDecorationValue(
dst_id_to_, dst_id, spv::Decoration::Binding, &dst_set);
if (src_has_set && dst_has_set && src_has_binding && dst_has_binding) {
return src_set == dst_set && src_binding == dst_binding;
@@ -1367,9 +1370,9 @@ bool Differ::MatchOpVariable(const opt::Instruction* src_inst,
uint32_t src_location, dst_location;
const bool src_has_location = GetDecorationValue(
src_id_to_, src_id, SpvDecorationLocation, &src_location);
src_id_to_, src_id, spv::Decoration::Location, &src_location);
const bool dst_has_location = GetDecorationValue(
dst_id_to_, dst_id, SpvDecorationLocation, &dst_location);
dst_id_to_, dst_id, spv::Decoration::Location, &dst_location);
if (src_has_location && dst_has_location) {
return src_location == dst_location;
@@ -1384,25 +1387,25 @@ bool Differ::MatchPerVertexType(uint32_t src_type_id, uint32_t dst_type_id) {
// For gl_PerVertex, find the type pointer of this type (array) and make sure
// the storage classes of src and dst match; geometry and tessellation shaders
// have two instances of gl_PerVertex.
SpvStorageClass src_storage_class =
spv::StorageClass src_storage_class =
GetPerVertexStorageClass(src_, src_type_id);
SpvStorageClass dst_storage_class =
spv::StorageClass dst_storage_class =
GetPerVertexStorageClass(dst_, dst_type_id);
assert(src_storage_class == SpvStorageClassInput ||
src_storage_class == SpvStorageClassOutput);
assert(dst_storage_class == SpvStorageClassInput ||
dst_storage_class == SpvStorageClassOutput);
assert(src_storage_class == spv::StorageClass::Input ||
src_storage_class == spv::StorageClass::Output);
assert(dst_storage_class == spv::StorageClass::Input ||
dst_storage_class == spv::StorageClass::Output);
return src_storage_class == dst_storage_class;
}
bool Differ::MatchPerVertexVariable(const opt::Instruction* src_inst,
const opt::Instruction* dst_inst) {
SpvStorageClass src_storage_class =
SpvStorageClass(src_inst->GetSingleWordInOperand(0));
SpvStorageClass dst_storage_class =
SpvStorageClass(dst_inst->GetSingleWordInOperand(0));
spv::StorageClass src_storage_class =
spv::StorageClass(src_inst->GetSingleWordInOperand(0));
spv::StorageClass dst_storage_class =
spv::StorageClass(dst_inst->GetSingleWordInOperand(0));
return src_storage_class == dst_storage_class;
}
@@ -1479,7 +1482,7 @@ InstructionList Differ::GetFunctionHeader(const opt::Function& function) {
InstructionList body;
function.WhileEachInst(
[&body](const opt::Instruction* inst) {
if (inst->opcode() == SpvOpLabel) {
if (inst->opcode() == spv::Op::OpLabel) {
return false;
}
body.push_back(inst);
@@ -1694,12 +1697,12 @@ void Differ::MatchVariablesUsedByMatchedInstructions(
default:
// TODO: match functions based on OpFunctionCall?
break;
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case SpvOpLoad:
case SpvOpStore:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
case spv::Op::OpLoad:
case spv::Op::OpStore:
const uint32_t src_pointer_id = src_inst->GetSingleWordInOperand(0);
const uint32_t dst_pointer_id = dst_inst->GetSingleWordInOperand(0);
if (IsVariable(src_id_to_, src_pointer_id) &&
@@ -1727,23 +1730,24 @@ const opt::Instruction* Differ::GetInst(const IdInstructions& id_to,
uint32_t Differ::GetConstantUint(const IdInstructions& id_to,
uint32_t constant_id) {
const opt::Instruction* constant_inst = GetInst(id_to, constant_id);
assert(constant_inst->opcode() == SpvOpConstant);
assert(GetInst(id_to, constant_inst->type_id())->opcode() == SpvOpTypeInt);
assert(constant_inst->opcode() == spv::Op::OpConstant);
assert(GetInst(id_to, constant_inst->type_id())->opcode() ==
spv::Op::OpTypeInt);
return constant_inst->GetSingleWordInOperand(0);
}
SpvExecutionModel Differ::GetExecutionModel(const opt::Module* module,
uint32_t entry_point_id) {
spv::ExecutionModel Differ::GetExecutionModel(const opt::Module* module,
uint32_t entry_point_id) {
for (const opt::Instruction& inst : module->entry_points()) {
assert(inst.opcode() == SpvOpEntryPoint);
assert(inst.opcode() == spv::Op::OpEntryPoint);
if (inst.GetSingleWordOperand(1) == entry_point_id) {
return SpvExecutionModel(inst.GetSingleWordOperand(0));
return spv::ExecutionModel(inst.GetSingleWordOperand(0));
}
}
assert(false && "Unreachable");
return SpvExecutionModel(0xFFF);
return spv::ExecutionModel(0xFFF);
}
bool Differ::HasName(const IdInstructions& id_to, uint32_t id) {
@@ -1751,7 +1755,7 @@ bool Differ::HasName(const IdInstructions& id_to, uint32_t id) {
assert(id < id_to.name_map_.size());
for (const opt::Instruction* inst : id_to.name_map_[id]) {
if (inst->opcode() == SpvOpName) {
if (inst->opcode() == spv::Op::OpName) {
return true;
}
}
@@ -1765,7 +1769,7 @@ std::string Differ::GetName(const IdInstructions& id_to, uint32_t id,
assert(id < id_to.name_map_.size());
for (const opt::Instruction* inst : id_to.name_map_[id]) {
if (inst->opcode() == SpvOpName) {
if (inst->opcode() == spv::Op::OpName) {
*has_name = true;
return inst->GetOperand(1).AsString();
}
@@ -1788,11 +1792,11 @@ std::string Differ::GetSanitizedName(const IdInstructions& id_to, uint32_t id) {
}
uint32_t Differ::GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
SpvStorageClass* storage_class) {
spv::StorageClass* storage_class) {
const opt::Instruction* var_inst = GetInst(id_to, var_id);
assert(var_inst->opcode() == SpvOpVariable);
assert(var_inst->opcode() == spv::Op::OpVariable);
*storage_class = SpvStorageClass(var_inst->GetSingleWordInOperand(0));
*storage_class = spv::StorageClass(var_inst->GetSingleWordInOperand(0));
// Get the type pointer from the variable.
const uint32_t type_pointer_id = var_inst->type_id();
@@ -1803,15 +1807,15 @@ uint32_t Differ::GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
}
bool Differ::GetDecorationValue(const IdInstructions& id_to, uint32_t id,
SpvDecoration decoration,
spv::Decoration decoration,
uint32_t* decoration_value) {
assert(id != 0);
assert(id < id_to.decoration_map_.size());
for (const opt::Instruction* inst : id_to.decoration_map_[id]) {
if (inst->opcode() == SpvOpDecorate &&
if (inst->opcode() == spv::Op::OpDecorate &&
inst->GetSingleWordOperand(0) == id &&
inst->GetSingleWordOperand(1) == decoration) {
spv::Decoration(inst->GetSingleWordOperand(1)) == decoration) {
*decoration_value = inst->GetSingleWordOperand(2);
return true;
}
@@ -1828,28 +1832,28 @@ const opt::Instruction* Differ::GetForwardPointerInst(
}
bool Differ::IsIntType(const IdInstructions& id_to, uint32_t type_id) {
return IsOp(id_to, type_id, SpvOpTypeInt);
return IsOp(id_to, type_id, spv::Op::OpTypeInt);
}
bool Differ::IsFloatType(const IdInstructions& id_to, uint32_t type_id) {
return IsOp(id_to, type_id, SpvOpTypeFloat);
return IsOp(id_to, type_id, spv::Op::OpTypeFloat);
}
bool Differ::IsConstantUint(const IdInstructions& id_to, uint32_t id) {
const opt::Instruction* constant_inst = GetInst(id_to, id);
if (constant_inst->opcode() != SpvOpConstant) {
if (constant_inst->opcode() != spv::Op::OpConstant) {
return false;
}
const opt::Instruction* type_inst = GetInst(id_to, constant_inst->type_id());
return type_inst->opcode() == SpvOpTypeInt;
return type_inst->opcode() == spv::Op::OpTypeInt;
}
bool Differ::IsVariable(const IdInstructions& id_to, uint32_t pointer_id) {
return IsOp(id_to, pointer_id, SpvOpVariable);
return IsOp(id_to, pointer_id, spv::Op::OpVariable);
}
bool Differ::IsOp(const IdInstructions& id_to, uint32_t id, SpvOp op) {
bool Differ::IsOp(const IdInstructions& id_to, uint32_t id, spv::Op op) {
return GetInst(id_to, id)->opcode() == op;
}
@@ -1858,17 +1862,18 @@ bool Differ::IsPerVertexType(const IdInstructions& id_to, uint32_t type_id) {
assert(type_id < id_to.decoration_map_.size());
for (const opt::Instruction* inst : id_to.decoration_map_[type_id]) {
if (inst->opcode() == SpvOpMemberDecorate &&
if (inst->opcode() == spv::Op::OpMemberDecorate &&
inst->GetSingleWordOperand(0) == type_id &&
inst->GetSingleWordOperand(2) == SpvDecorationBuiltIn) {
SpvBuiltIn built_in = SpvBuiltIn(inst->GetSingleWordOperand(3));
spv::Decoration(inst->GetSingleWordOperand(2)) ==
spv::Decoration::BuiltIn) {
spv::BuiltIn built_in = spv::BuiltIn(inst->GetSingleWordOperand(3));
// Only gl_PerVertex can have, and it can only have, the following
// built-in decorations.
return built_in == SpvBuiltInPosition ||
built_in == SpvBuiltInPointSize ||
built_in == SpvBuiltInClipDistance ||
built_in == SpvBuiltInCullDistance;
return built_in == spv::BuiltIn::Position ||
built_in == spv::BuiltIn::PointSize ||
built_in == spv::BuiltIn::ClipDistance ||
built_in == spv::BuiltIn::CullDistance;
}
}
@@ -1877,12 +1882,12 @@ bool Differ::IsPerVertexType(const IdInstructions& id_to, uint32_t type_id) {
bool Differ::IsPerVertexVariable(const IdInstructions& id_to, uint32_t var_id) {
// Get the type from the type pointer.
SpvStorageClass storage_class;
spv::StorageClass storage_class;
uint32_t type_id = GetVarTypeId(id_to, var_id, &storage_class);
const opt::Instruction* type_inst = GetInst(id_to, type_id);
// If array, get the element type.
if (type_inst->opcode() == SpvOpTypeArray) {
if (type_inst->opcode() == spv::Op::OpTypeArray) {
type_id = type_inst->GetSingleWordInOperand(0);
}
@@ -1890,21 +1895,21 @@ bool Differ::IsPerVertexVariable(const IdInstructions& id_to, uint32_t var_id) {
return IsPerVertexType(id_to, type_id);
}
SpvStorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
uint32_t type_id) {
spv::StorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
uint32_t type_id) {
for (const opt::Instruction& inst : module->types_values()) {
switch (inst.opcode()) {
case SpvOpTypeArray:
case spv::Op::OpTypeArray:
// The gl_PerVertex instance could be an array, look for a variable of
// the array type instead.
if (inst.GetSingleWordInOperand(0) == type_id) {
type_id = inst.result_id();
}
break;
case SpvOpTypePointer:
case spv::Op::OpTypePointer:
// Find the storage class of the pointer to this type.
if (inst.GetSingleWordInOperand(1) == type_id) {
return SpvStorageClass(inst.GetSingleWordInOperand(0));
return spv::StorageClass(inst.GetSingleWordInOperand(0));
}
break;
default:
@@ -1915,7 +1920,7 @@ SpvStorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
// gl_PerVertex is declared, but is unused. Return either of Input or Output
// classes just so it matches one in the other module. This should be highly
// unlikely, perhaps except for ancient GS-used-to-emulate-CS scenarios.
return SpvStorageClassOutput;
return spv::StorageClass::Output;
}
spv_ext_inst_type_t Differ::GetExtInstType(const IdInstructions& id_to,
@@ -1941,9 +1946,9 @@ spv_number_kind_t Differ::GetNumberKind(const IdInstructions& id_to,
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
switch (inst.opcode()) {
case SpvOpSwitch:
case SpvOpConstant:
case SpvOpSpecConstant:
case spv::Op::OpSwitch:
case spv::Op::OpConstant:
case spv::Op::OpSpecConstant:
// Same kind of number as the selector (OpSwitch) or the type
// (Op*Constant).
return GetTypeNumberKind(id_to, inst.GetSingleWordOperand(0),
@@ -1969,12 +1974,12 @@ spv_number_kind_t Differ::GetTypeNumberKind(const IdInstructions& id_to,
}
switch (type_inst->opcode()) {
case SpvOpTypeInt:
case spv::Op::OpTypeInt:
*number_bit_width = type_inst->GetSingleWordOperand(1);
return type_inst->GetSingleWordOperand(2) == 0 ? SPV_NUMBER_UNSIGNED_INT
: SPV_NUMBER_SIGNED_INT;
break;
case SpvOpTypeFloat:
case spv::Op::OpTypeFloat:
*number_bit_width = type_inst->GetSingleWordOperand(1);
return SPV_NUMBER_FLOATING;
default:
@@ -2092,7 +2097,7 @@ void Differ::MatchTypeForwardPointers() {
return inst.GetSingleWordOperand(0);
};
auto accept_type_forward_pointer_ops = [](const opt::Instruction& inst) {
return inst.opcode() == SpvOpTypeForwardPointer;
return inst.opcode() == spv::Op::OpTypeForwardPointer;
};
PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
@@ -2116,17 +2121,17 @@ void Differ::MatchTypeForwardPointers() {
// - If leftover is unique, match
// Group forwarded pointers by storage class first and loop over them.
GroupIdsAndMatch<SpvStorageClass>(
potential_id_map.src_ids, potential_id_map.dst_ids, SpvStorageClassMax,
&Differ::GroupIdsHelperGetTypePointerStorageClass,
GroupIdsAndMatch<spv::StorageClass>(
potential_id_map.src_ids, potential_id_map.dst_ids,
spv::StorageClass::Max, &Differ::GroupIdsHelperGetTypePointerStorageClass,
[this](const IdGroup& src_group_by_storage_class,
const IdGroup& dst_group_by_storage_class) {
// Group them further by the type they are pointing to and loop over
// them.
GroupIdsAndMatch<SpvOp>(
src_group_by_storage_class, dst_group_by_storage_class, SpvOpMax,
&Differ::GroupIdsHelperGetTypePointerTypeOp,
GroupIdsAndMatch<spv::Op>(
src_group_by_storage_class, dst_group_by_storage_class,
spv::Op::Max, &Differ::GroupIdsHelperGetTypePointerTypeOp,
[this](const IdGroup& src_group_by_type_op,
const IdGroup& dst_group_by_type_op) {
@@ -2182,8 +2187,8 @@ void Differ::MatchTypeIds() {
MatchIds(potential_id_map, [this, flexibility](
const opt::Instruction* src_inst,
const opt::Instruction* dst_inst) {
const SpvOp src_op = src_inst->opcode();
const SpvOp dst_op = dst_inst->opcode();
const spv::Op src_op = src_inst->opcode();
const spv::Op dst_op = dst_inst->opcode();
// Don't match if the opcode is not the same.
if (src_op != dst_op) {
@@ -2191,26 +2196,26 @@ void Differ::MatchTypeIds() {
}
switch (src_op) {
case SpvOpTypeVoid:
case SpvOpTypeBool:
case SpvOpTypeSampler:
case spv::Op::OpTypeVoid:
case spv::Op::OpTypeBool:
case spv::Op::OpTypeSampler:
// void, bool and sampler are unique, match them.
return true;
case SpvOpTypeInt:
case SpvOpTypeFloat:
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case SpvOpTypeSampledImage:
case SpvOpTypeRuntimeArray:
case SpvOpTypePointer:
case spv::Op::OpTypeInt:
case spv::Op::OpTypeFloat:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeSampledImage:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypePointer:
// Match these instructions when all operands match.
assert(src_inst->NumInOperandWords() ==
dst_inst->NumInOperandWords());
return DoOperandsMatch(src_inst, dst_inst, 0,
src_inst->NumInOperandWords());
case SpvOpTypeFunction:
case SpvOpTypeImage:
case spv::Op::OpTypeFunction:
case spv::Op::OpTypeImage:
// Match function types only if they have the same number of operands,
// and they all match.
// Match image types similarly, expecting the optional final parameter
@@ -2221,7 +2226,7 @@ void Differ::MatchTypeIds() {
return DoOperandsMatch(src_inst, dst_inst, 0,
src_inst->NumInOperandWords());
case SpvOpTypeArray:
case spv::Op::OpTypeArray:
// Match arrays only if the element type and length match. The length
// is an id of a constant, so the actual constant it's defining is
// compared instead.
@@ -2238,7 +2243,7 @@ void Differ::MatchTypeIds() {
// example if a spec contant is used).
return DoOperandsMatch(src_inst, dst_inst, 1, 1);
case SpvOpTypeStruct:
case spv::Op::OpTypeStruct:
return MatchOpTypeStruct(src_inst, dst_inst, flexibility);
default:
@@ -2270,8 +2275,8 @@ void Differ::MatchConstants() {
MatchIds(potential_id_map, [this, flexibility](
const opt::Instruction* src_inst,
const opt::Instruction* dst_inst) {
const SpvOp src_op = src_inst->opcode();
const SpvOp dst_op = dst_inst->opcode();
const spv::Op src_op = src_inst->opcode();
const spv::Op dst_op = dst_inst->opcode();
// Don't match if the opcode is not the same.
if (src_op != dst_op) {
@@ -2279,14 +2284,14 @@ void Differ::MatchConstants() {
}
switch (src_op) {
case SpvOpConstantTrue:
case SpvOpConstantFalse:
case spv::Op::OpConstantTrue:
case spv::Op::OpConstantFalse:
// true and false are unique, match them.
return true;
case SpvOpConstant:
case spv::Op::OpConstant:
return MatchOpConstant(src_inst, dst_inst, flexibility);
case SpvOpConstantComposite:
case SpvOpSpecConstantComposite:
case spv::Op::OpConstantComposite:
case spv::Op::OpSpecConstantComposite:
// Composite constants must match in type and value.
//
// TODO: match OpConstantNull with OpConstantComposite with all zeros
@@ -2299,7 +2304,7 @@ void Differ::MatchConstants() {
dst_inst->GetOperand(0)) &&
DoOperandsMatch(src_inst, dst_inst, 0,
src_inst->NumInOperandWords());
case SpvOpConstantSampler:
case spv::Op::OpConstantSampler:
// Match sampler constants exactly.
// TODO: Allow flexibility in parameters to better diff shaders where
// the sampler param has changed.
@@ -2307,15 +2312,15 @@ void Differ::MatchConstants() {
dst_inst->NumInOperandWords());
return DoOperandsMatch(src_inst, dst_inst, 0,
src_inst->NumInOperandWords());
case SpvOpConstantNull:
case spv::Op::OpConstantNull:
// Match null constants as long as the type matches.
return DoesOperandMatch(src_inst->GetOperand(0),
dst_inst->GetOperand(0));
case SpvOpSpecConstantTrue:
case SpvOpSpecConstantFalse:
case SpvOpSpecConstant:
case SpvOpSpecConstantOp:
case spv::Op::OpSpecConstantTrue:
case spv::Op::OpSpecConstantFalse:
case spv::Op::OpSpecConstant:
case spv::Op::OpSpecConstantOp:
// Match spec constants by name if available, then by the SpecId
// decoration.
return MatchOpSpecConstant(src_inst, dst_inst);
@@ -2334,7 +2339,7 @@ void Differ::MatchVariableIds() {
return inst.result_id();
};
auto accept_type_ops = [](const opt::Instruction& inst) {
return inst.opcode() == SpvOpVariable;
return inst.opcode() == spv::Op::OpVariable;
};
PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
@@ -2350,8 +2355,8 @@ void Differ::MatchVariableIds() {
MatchIds(potential_id_map,
[this, flexibility](const opt::Instruction* src_inst,
const opt::Instruction* dst_inst) {
assert(src_inst->opcode() == SpvOpVariable);
assert(dst_inst->opcode() == SpvOpVariable);
assert(src_inst->opcode() == spv::Op::OpVariable);
assert(dst_inst->opcode() == spv::Op::OpVariable);
return MatchOpVariable(src_inst, dst_inst, flexibility);
});
@@ -2597,7 +2602,7 @@ void Differ::ToParsedInstruction(
parsed_inst->num_words = static_cast<uint16_t>(inst_binary.size());
parsed_inst->opcode = static_cast<uint16_t>(inst.opcode());
parsed_inst->ext_inst_type =
inst.opcode() == SpvOpExtInst
inst.opcode() == spv::Op::OpExtInst
? GetExtInstType(id_to, original_inst.GetSingleWordInOperand(0))
: SPV_EXT_INST_TYPE_NONE;
parsed_inst->type_id =

View File

@@ -244,7 +244,7 @@ void InstructionDisassembler::EmitHeaderSchema(uint32_t schema) {
void InstructionDisassembler::EmitInstruction(
const spv_parsed_instruction_t& inst, size_t inst_byte_offset) {
auto opcode = static_cast<SpvOp>(inst.opcode);
auto opcode = static_cast<spv::Op>(inst.opcode);
if (inst.result_id) {
SetBlue();
@@ -268,7 +268,7 @@ void InstructionDisassembler::EmitInstruction(
EmitOperand(inst, i);
}
if (comment_ && opcode == SpvOpName) {
if (comment_ && opcode == spv::Op::OpName) {
const spv_parsed_operand_t& operand = inst.operands[0];
const uint32_t word = inst.words[operand.offset];
stream_ << " ; id %" << word;
@@ -290,8 +290,8 @@ void InstructionDisassembler::EmitInstruction(
void InstructionDisassembler::EmitSectionComment(
const spv_parsed_instruction_t& inst, bool& inserted_decoration_space,
bool& inserted_debug_space, bool& inserted_type_space) {
auto opcode = static_cast<SpvOp>(inst.opcode);
if (comment_ && opcode == SpvOpFunction) {
auto opcode = static_cast<spv::Op>(inst.opcode);
if (comment_ && opcode == spv::Op::OpFunction) {
stream_ << std::endl;
stream_ << std::string(indent_, ' ');
stream_ << "; Function " << name_mapper_(inst.result_id) << std::endl;
@@ -351,7 +351,7 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst,
} break;
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
spv_opcode_desc opcode_desc;
if (grammar_.lookupOpcode(SpvOp(word), &opcode_desc))
if (grammar_.lookupOpcode(spv::Op(word), &opcode_desc))
assert(false && "should have caught this earlier");
SetRed();
stream_ << opcode_desc->name;

View File

@@ -200,8 +200,8 @@ class EnumSet {
std::unique_ptr<OverflowSetType> overflow_ = {};
};
// A set of SpvCapability, optimized for small capability values.
using CapabilitySet = EnumSet<SpvCapability>;
// A set of spv::Capability, optimized for small capability values.
using CapabilitySet = EnumSet<spv::Capability>;
} // namespace spvtools

View File

@@ -29,7 +29,7 @@ bool GetExtensionFromString(const char* str, Extension* extension);
const char* ExtensionToString(Extension extension);
// Returns text string corresponding to |capability|.
const char* CapabilityToString(SpvCapability capability);
const char* CapabilityToString(spv::Capability capability);
} // namespace spvtools

View File

@@ -24,7 +24,9 @@
namespace spvtools {
std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
if (inst->opcode != SpvOpExtension) return "ERROR_not_op_extension";
if (inst->opcode != static_cast<uint16_t>(spv::Op::OpExtension)) {
return "ERROR_not_op_extension";
}
assert(inst->num_operands == 1);

View File

@@ -26,7 +26,7 @@ struct spv_instruction_t {
// Normally, both opcode and extInstType contain valid data.
// However, when the assembler parses !<number> as the first word in
// an instruction and opcode and extInstType are invalid.
SpvOp opcode;
spv::Op opcode;
spv_ext_inst_type_t extInstType;
// The Id of the result type, if this instruction has one. Zero otherwise.

View File

@@ -15,6 +15,6 @@
#ifndef SOURCE_LATEST_VERSION_SPIRV_HEADER_H_
#define SOURCE_LATEST_VERSION_SPIRV_HEADER_H_
#include "spirv/unified1/spirv.h"
#include "spirv/unified1/spirv.hpp11"
#endif // SOURCE_LATEST_VERSION_SPIRV_HEADER_H_

View File

@@ -57,12 +57,12 @@ using opt::analysis::TypeManager;
// Stores various information about an imported or exported symbol.
struct LinkageSymbolInfo {
SpvId id; // ID of the symbol
SpvId type_id; // ID of the type of the symbol
spv::Id id; // ID of the symbol
spv::Id type_id; // ID of the type of the symbol
std::string name; // unique name defining the symbol and used for matching
// imports and exports together
std::vector<SpvId> parameter_ids; // ID of the parameters of the symbol, if
// it is a function
std::vector<spv::Id> parameter_ids; // ID of the parameters of the symbol, if
// it is a function
};
struct LinkageEntry {
LinkageSymbolInfo imported_symbol;
@@ -226,7 +226,7 @@ spv_result_t GenerateHeader(const MessageConsumer& consumer,
<< " (input module " << (i + 1) << ").";
}
header->magic_number = SpvMagicNumber;
header->magic_number = spv::MagicNumber;
header->version = linked_version;
header->generator = SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_LINKER, 0);
header->bound = max_id_bound;
@@ -367,7 +367,7 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
std::vector<uint32_t> processed_words =
spvtools::utils::MakeVector(processed_string);
linked_module->AddDebug3Inst(std::unique_ptr<Instruction>(
new Instruction(linked_context, SpvOpModuleProcessed, 0u, 0u,
new Instruction(linked_context, spv::Op::OpModuleProcessed, 0u, 0u,
{{SPV_OPERAND_TYPE_LITERAL_STRING, processed_words}})));
}
@@ -377,7 +377,7 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
std::unique_ptr<Instruction>(inst.Clone(linked_context)));
// TODO(pierremoreau): Since the modules have not been validate, should we
// expect SpvStorageClassFunction variables outside
// expect spv::StorageClass::Function variables outside
// functions?
for (const auto& module : input_modules) {
for (const auto& inst : module->types_values()) {
@@ -414,16 +414,18 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer,
// Figure out the imports and exports
for (const auto& decoration : linked_context.annotations()) {
if (decoration.opcode() != SpvOpDecorate ||
decoration.GetSingleWordInOperand(1u) != SpvDecorationLinkageAttributes)
if (decoration.opcode() != spv::Op::OpDecorate ||
spv::Decoration(decoration.GetSingleWordInOperand(1u)) !=
spv::Decoration::LinkageAttributes)
continue;
const SpvId id = decoration.GetSingleWordInOperand(0u);
const spv::Id id = decoration.GetSingleWordInOperand(0u);
// Ignore if the targeted symbol is a built-in
bool is_built_in = false;
for (const auto& id_decoration :
decoration_manager.GetDecorationsFor(id, false)) {
if (id_decoration->GetSingleWordInOperand(1u) == SpvDecorationBuiltIn) {
if (spv::Decoration(id_decoration->GetSingleWordInOperand(1u)) ==
spv::Decoration::BuiltIn) {
is_built_in = true;
break;
}
@@ -447,9 +449,9 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer,
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
<< "ID " << id << " is never defined:\n";
if (def_inst->opcode() == SpvOpVariable) {
if (def_inst->opcode() == spv::Op::OpVariable) {
symbol_info.type_id = def_inst->type_id();
} else if (def_inst->opcode() == SpvOpFunction) {
} else if (def_inst->opcode() == spv::Op::OpFunction) {
symbol_info.type_id = def_inst->GetSingleWordInOperand(1u);
// range-based for loop calls begin()/end(), but never cbegin()/cend(),
@@ -467,9 +469,9 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer,
<< " LinkageAttributes; " << id << " is neither of them.\n";
}
if (type == SpvLinkageTypeImport)
if (spv::LinkageType(type) == spv::LinkageType::Import)
imports.push_back(symbol_info);
else if (type == SpvLinkageTypeExport)
else if (spv::LinkageType(type) == spv::LinkageType::Export)
exports[symbol_info.name].push_back(symbol_info);
}
@@ -585,7 +587,7 @@ spv_result_t RemoveLinkageSpecificInstructions(
// TODO(pierremoreau): This will not work if the decoration is applied
// through a group, but the linker does not support that
// either.
std::unordered_set<SpvId> imports;
std::unordered_set<spv::Id> imports;
if (options.GetAllowPartialLinkage()) {
imports.reserve(linkings_to_do.size());
for (const auto& linking_entry : linkings_to_do)
@@ -601,9 +603,11 @@ spv_result_t RemoveLinkageSpecificInstructions(
// * if we do not allow partial linkage, remove all import annotations;
// * otherwise, remove the annotation only if there was a corresponding
// export.
if (inst->opcode() == SpvOpDecorate &&
inst->GetSingleWordOperand(1u) == SpvDecorationLinkageAttributes &&
inst->GetSingleWordOperand(3u) == SpvLinkageTypeImport &&
if (inst->opcode() == spv::Op::OpDecorate &&
spv::Decoration(inst->GetSingleWordOperand(1u)) ==
spv::Decoration::LinkageAttributes &&
spv::LinkageType(inst->GetSingleWordOperand(3u)) ==
spv::LinkageType::Import &&
(!options.GetAllowPartialLinkage() ||
imports.find(inst->GetSingleWordOperand(0u)) != imports.end())) {
linked_context->KillInst(&*inst);
@@ -616,9 +620,11 @@ spv_result_t RemoveLinkageSpecificInstructions(
for (auto inst = next; inst != linked_context->annotation_end();
inst = next) {
++next;
if (inst->opcode() == SpvOpDecorate &&
inst->GetSingleWordOperand(1u) == SpvDecorationLinkageAttributes &&
inst->GetSingleWordOperand(3u) == SpvLinkageTypeExport) {
if (inst->opcode() == spv::Op::OpDecorate &&
spv::Decoration(inst->GetSingleWordOperand(1u)) ==
spv::Decoration::LinkageAttributes &&
spv::LinkageType(inst->GetSingleWordOperand(3u)) ==
spv::LinkageType::Export) {
linked_context->KillInst(&*inst);
}
}
@@ -628,10 +634,11 @@ spv_result_t RemoveLinkageSpecificInstructions(
// not allowed
if (!options.GetCreateLibrary() && !options.GetAllowPartialLinkage()) {
for (auto& inst : linked_context->capabilities())
if (inst.GetSingleWordInOperand(0u) == SpvCapabilityLinkage) {
if (spv::Capability(inst.GetSingleWordInOperand(0u)) ==
spv::Capability::Linkage) {
linked_context->KillInst(&inst);
// The RemoveDuplicatesPass did remove duplicated capabilities, so we
// now there arent more SpvCapabilityLinkage further down.
// now there arent more spv::Capability::Linkage further down.
break;
}
}
@@ -671,7 +678,7 @@ spv_result_t VerifyLimits(const MessageConsumer& consumer,
size_t num_global_values = 0u;
for (const auto& inst : linked_context.module()->types_values()) {
num_global_values += inst.opcode() == SpvOpVariable;
num_global_values += inst.opcode() == spv::Op::OpVariable;
}
if (num_global_values >= SPV_LIMIT_GLOBAL_VARIABLES_MAX)
DiagnosticStream(position, consumer, "", SPV_WARNING)

View File

@@ -19,7 +19,6 @@
#include "source/opt/dataflow.h"
#include "source/opt/function.h"
#include "source/opt/instruction.h"
#include "spirv/unified1/spirv.h"
namespace spvtools {
namespace lint {
@@ -32,7 +31,7 @@ void DivergenceAnalysis::EnqueueSuccessors(opt::Instruction* inst) {
uint32_t block_id;
if (inst->IsBlockTerminator()) {
block_id = context().get_instr_block(inst)->id();
} else if (inst->opcode() == SpvOpLabel) {
} else if (inst->opcode() == spv::Op::OpLabel) {
block_id = inst->result_id();
opt::BasicBlock* bb = context().cfg()->block(block_id);
// Only enqueue phi instructions, as other uses don't affect divergence.
@@ -54,7 +53,7 @@ void DivergenceAnalysis::EnqueueSuccessors(opt::Instruction* inst) {
opt::DataFlowAnalysis::VisitResult DivergenceAnalysis::Visit(
opt::Instruction* inst) {
if (inst->opcode() == SpvOpLabel) {
if (inst->opcode() == spv::Op::OpLabel) {
return VisitBlock(inst->result_id());
} else {
return VisitInstruction(inst);
@@ -128,12 +127,12 @@ DivergenceAnalysis::ComputeInstructionDivergence(opt::Instruction* inst) {
// Device/QueueFamily could satisfy fully uniform.
uint32_t id = inst->result_id();
// Handle divergence roots.
if (inst->opcode() == SpvOpFunctionParameter) {
if (inst->opcode() == spv::Op::OpFunctionParameter) {
divergence_source_[id] = 0;
return divergence_[id] = DivergenceLevel::kDivergent;
} else if (inst->IsLoad()) {
spvtools::opt::Instruction* var = inst->GetBaseAddress();
if (var->opcode() != SpvOpVariable) {
if (var->opcode() != spv::Op::OpVariable) {
// Assume divergent.
divergence_source_[id] = 0;
return DivergenceLevel::kDivergent;
@@ -166,29 +165,30 @@ DivergenceAnalysis::ComputeVariableDivergence(opt::Instruction* var) {
uint32_t def_id = var->result_id();
DivergenceLevel ret;
switch (type->storage_class()) {
case SpvStorageClassFunction:
case SpvStorageClassGeneric:
case SpvStorageClassAtomicCounter:
case SpvStorageClassStorageBuffer:
case SpvStorageClassPhysicalStorageBuffer:
case SpvStorageClassOutput:
case SpvStorageClassWorkgroup:
case SpvStorageClassImage: // Image atomics probably aren't uniform.
case SpvStorageClassPrivate:
case spv::StorageClass::Function:
case spv::StorageClass::Generic:
case spv::StorageClass::AtomicCounter:
case spv::StorageClass::StorageBuffer:
case spv::StorageClass::PhysicalStorageBuffer:
case spv::StorageClass::Output:
case spv::StorageClass::Workgroup:
case spv::StorageClass::Image: // Image atomics probably aren't uniform.
case spv::StorageClass::Private:
ret = DivergenceLevel::kDivergent;
break;
case SpvStorageClassInput:
case spv::StorageClass::Input:
ret = DivergenceLevel::kDivergent;
// If this variable has a Flat decoration, it is partially uniform.
// TODO(kuhar): Track access chain indices and also consider Flat members
// of a structure.
context().get_decoration_mgr()->WhileEachDecoration(
def_id, SpvDecorationFlat, [&ret](const opt::Instruction&) {
def_id, static_cast<uint32_t>(spv::Decoration::Flat),
[&ret](const opt::Instruction&) {
ret = DivergenceLevel::kPartiallyUniform;
return false;
});
break;
case SpvStorageClassUniformConstant:
case spv::StorageClass::UniformConstant:
// May be a storage image which is also written to; mark those as
// divergent.
if (!var->IsVulkanStorageImage() || var->IsReadOnlyPointer()) {
@@ -197,9 +197,10 @@ DivergenceAnalysis::ComputeVariableDivergence(opt::Instruction* var) {
ret = DivergenceLevel::kDivergent;
}
break;
case SpvStorageClassUniform:
case SpvStorageClassPushConstant:
case SpvStorageClassCrossWorkgroup: // Not for shaders; default uniform.
case spv::StorageClass::Uniform:
case spv::StorageClass::PushConstant:
case spv::StorageClass::CrossWorkgroup: // Not for shaders; default
// uniform.
default:
ret = DivergenceLevel::kUniform;
break;
@@ -216,7 +217,7 @@ void DivergenceAnalysis::Setup(opt::Function* function) {
function->entry().get(), [this](const opt::BasicBlock* bb) {
uint32_t id = bb->id();
if (bb->terminator() == nullptr ||
bb->terminator()->opcode() != SpvOpBranch) {
bb->terminator()->opcode() != spv::Op::OpBranch) {
follow_unconditional_branches_[id] = id;
} else {
uint32_t target_id = bb->terminator()->GetSingleWordInOperand(0);

View File

@@ -27,7 +27,6 @@
#include "source/opt/instruction.h"
#include "source/opt/ir_context.h"
#include "spirv-tools/libspirv.h"
#include "spirv/unified1/spirv.h"
namespace spvtools {
namespace lint {
@@ -43,7 +42,7 @@ std::string GetFriendlyName(opt::IRContext* context, uint32_t id) {
ss << id;
} else {
opt::Instruction* inst_name = names.begin()->second;
if (inst_name->opcode() == SpvOpName) {
if (inst_name->opcode() == spv::Op::OpName) {
ss << names.begin()->second->GetInOperand(0).AsString();
ss << "[" << id << "]";
} else {
@@ -54,26 +53,26 @@ std::string GetFriendlyName(opt::IRContext* context, uint32_t id) {
}
bool InstructionHasDerivative(const opt::Instruction& inst) {
static const SpvOp derivative_opcodes[] = {
static const spv::Op derivative_opcodes[] = {
// Implicit derivatives.
SpvOpImageSampleImplicitLod,
SpvOpImageSampleDrefImplicitLod,
SpvOpImageSampleProjImplicitLod,
SpvOpImageSampleProjDrefImplicitLod,
SpvOpImageSparseSampleImplicitLod,
SpvOpImageSparseSampleDrefImplicitLod,
SpvOpImageSparseSampleProjImplicitLod,
SpvOpImageSparseSampleProjDrefImplicitLod,
spv::Op::OpImageSampleImplicitLod,
spv::Op::OpImageSampleDrefImplicitLod,
spv::Op::OpImageSampleProjImplicitLod,
spv::Op::OpImageSampleProjDrefImplicitLod,
spv::Op::OpImageSparseSampleImplicitLod,
spv::Op::OpImageSparseSampleDrefImplicitLod,
spv::Op::OpImageSparseSampleProjImplicitLod,
spv::Op::OpImageSparseSampleProjDrefImplicitLod,
// Explicit derivatives.
SpvOpDPdx,
SpvOpDPdy,
SpvOpFwidth,
SpvOpDPdxFine,
SpvOpDPdyFine,
SpvOpFwidthFine,
SpvOpDPdxCoarse,
SpvOpDPdyCoarse,
SpvOpFwidthCoarse,
spv::Op::OpDPdx,
spv::Op::OpDPdy,
spv::Op::OpFwidth,
spv::Op::OpDPdxFine,
spv::Op::OpDPdyFine,
spv::Op::OpFwidthFine,
spv::Op::OpDPdxCoarse,
spv::Op::OpDPdyCoarse,
spv::Op::OpFwidthCoarse,
};
return std::find(std::begin(derivative_opcodes), std::end(derivative_opcodes),
inst.opcode()) != std::end(derivative_opcodes);
@@ -97,13 +96,14 @@ void PrintDivergenceFlow(opt::IRContext* context, DivergenceAnalysis div,
opt::analysis::DefUseManager* def_use = context->get_def_use_mgr();
opt::CFG* cfg = context->cfg();
while (id != 0) {
bool is_block = def_use->GetDef(id)->opcode() == SpvOpLabel;
bool is_block = def_use->GetDef(id)->opcode() == spv::Op::OpLabel;
if (is_block) {
Warn(context, nullptr)
<< "block " << GetFriendlyName(context, id) << " is divergent";
uint32_t source = div.GetDivergenceSource(id);
// Skip intermediate blocks.
while (source != 0 && def_use->GetDef(source)->opcode() == SpvOpLabel) {
while (source != 0 &&
def_use->GetDef(source)->opcode() == spv::Op::OpLabel) {
id = source;
source = div.GetDivergenceSource(id);
}
@@ -122,7 +122,7 @@ void PrintDivergenceFlow(opt::IRContext* context, DivergenceAnalysis div,
opt::Instruction* source_def =
source == 0 ? nullptr : def_use->GetDef(source);
// First print data -> data dependencies.
while (source != 0 && source_def->opcode() != SpvOpLabel) {
while (source != 0 && source_def->opcode() != spv::Op::OpLabel) {
Warn(context, def_use->GetDef(id))
<< "because " << GetFriendlyName(context, id) << " uses value "
<< GetFriendlyName(context, source)

View File

@@ -19,7 +19,6 @@
#include "source/opt/ir_context.h"
#include "spirv-tools/libspirv.h"
#include "spirv-tools/libspirv.hpp"
#include "spirv/unified1/spirv.h"
namespace spvtools {

View File

@@ -100,18 +100,18 @@ void FriendlyNameMapper::SaveName(uint32_t id,
void FriendlyNameMapper::SaveBuiltInName(uint32_t target_id,
uint32_t built_in) {
#define GLCASE(name) \
case SpvBuiltIn##name: \
case spv::BuiltIn::name: \
SaveName(target_id, "gl_" #name); \
return;
#define GLCASE2(name, suggested) \
case SpvBuiltIn##name: \
case spv::BuiltIn::name: \
SaveName(target_id, "gl_" #suggested); \
return;
#define CASE(name) \
case SpvBuiltIn##name: \
case spv::BuiltIn::name: \
SaveName(target_id, #name); \
return;
switch (built_in) {
switch (spv::BuiltIn(built_in)) {
GLCASE(Position)
GLCASE(PointSize)
GLCASE(ClipDistance)
@@ -170,28 +170,28 @@ void FriendlyNameMapper::SaveBuiltInName(uint32_t target_id,
spv_result_t FriendlyNameMapper::ParseInstruction(
const spv_parsed_instruction_t& inst) {
const auto result_id = inst.result_id;
switch (inst.opcode) {
case SpvOpName:
switch (spv::Op(inst.opcode)) {
case spv::Op::OpName:
SaveName(inst.words[1], spvDecodeLiteralStringOperand(inst, 1));
break;
case SpvOpDecorate:
case spv::Op::OpDecorate:
// Decorations come after OpName. So OpName will take precedence over
// decorations.
//
// In theory, we should also handle OpGroupDecorate. But that's unlikely
// to occur.
if (inst.words[2] == SpvDecorationBuiltIn) {
if (spv::Decoration(inst.words[2]) == spv::Decoration::BuiltIn) {
assert(inst.num_words > 3);
SaveBuiltInName(inst.words[1], inst.words[3]);
}
break;
case SpvOpTypeVoid:
case spv::Op::OpTypeVoid:
SaveName(result_id, "void");
break;
case SpvOpTypeBool:
case spv::Op::OpTypeBool:
SaveName(result_id, "bool");
break;
case SpvOpTypeInt: {
case spv::Op::OpTypeInt: {
std::string signedness;
std::string root;
const auto bit_width = inst.words[2];
@@ -216,7 +216,7 @@ spv_result_t FriendlyNameMapper::ParseInstruction(
if (0 == inst.words[3]) signedness = "u";
SaveName(result_id, signedness + root);
} break;
case SpvOpTypeFloat: {
case spv::Op::OpTypeFloat: {
const auto bit_width = inst.words[2];
switch (bit_width) {
case 16:
@@ -233,68 +233,68 @@ spv_result_t FriendlyNameMapper::ParseInstruction(
break;
}
} break;
case SpvOpTypeVector:
case spv::Op::OpTypeVector:
SaveName(result_id, std::string("v") + to_string(inst.words[3]) +
NameForId(inst.words[2]));
break;
case SpvOpTypeMatrix:
case spv::Op::OpTypeMatrix:
SaveName(result_id, std::string("mat") + to_string(inst.words[3]) +
NameForId(inst.words[2]));
break;
case SpvOpTypeArray:
case spv::Op::OpTypeArray:
SaveName(result_id, std::string("_arr_") + NameForId(inst.words[2]) +
"_" + NameForId(inst.words[3]));
break;
case SpvOpTypeRuntimeArray:
case spv::Op::OpTypeRuntimeArray:
SaveName(result_id,
std::string("_runtimearr_") + NameForId(inst.words[2]));
break;
case SpvOpTypePointer:
case spv::Op::OpTypePointer:
SaveName(result_id, std::string("_ptr_") +
NameForEnumOperand(SPV_OPERAND_TYPE_STORAGE_CLASS,
inst.words[2]) +
"_" + NameForId(inst.words[3]));
break;
case SpvOpTypePipe:
case spv::Op::OpTypePipe:
SaveName(result_id,
std::string("Pipe") +
NameForEnumOperand(SPV_OPERAND_TYPE_ACCESS_QUALIFIER,
inst.words[2]));
break;
case SpvOpTypeEvent:
case spv::Op::OpTypeEvent:
SaveName(result_id, "Event");
break;
case SpvOpTypeDeviceEvent:
case spv::Op::OpTypeDeviceEvent:
SaveName(result_id, "DeviceEvent");
break;
case SpvOpTypeReserveId:
case spv::Op::OpTypeReserveId:
SaveName(result_id, "ReserveId");
break;
case SpvOpTypeQueue:
case spv::Op::OpTypeQueue:
SaveName(result_id, "Queue");
break;
case SpvOpTypeOpaque:
case spv::Op::OpTypeOpaque:
SaveName(result_id, std::string("Opaque_") +
Sanitize(spvDecodeLiteralStringOperand(inst, 1)));
break;
case SpvOpTypePipeStorage:
case spv::Op::OpTypePipeStorage:
SaveName(result_id, "PipeStorage");
break;
case SpvOpTypeNamedBarrier:
case spv::Op::OpTypeNamedBarrier:
SaveName(result_id, "NamedBarrier");
break;
case SpvOpTypeStruct:
case spv::Op::OpTypeStruct:
// Structs are mapped rather simplisitically. Just indicate that they
// are a struct and then give the raw Id number.
SaveName(result_id, std::string("_struct_") + to_string(result_id));
break;
case SpvOpConstantTrue:
case spv::Op::OpConstantTrue:
SaveName(result_id, "true");
break;
case SpvOpConstantFalse:
case spv::Op::OpConstantFalse:
SaveName(result_id, "false");
break;
case SpvOpConstant: {
case spv::Op::OpConstant: {
std::ostringstream value;
EmitNumericLiteral(&value, inst, inst.operands[2]);
auto value_str = value.str();

View File

@@ -64,7 +64,7 @@ const char* spvGeneratorStr(uint32_t generator) {
return "Unknown";
}
uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) {
uint32_t spvOpcodeMake(uint16_t wordCount, spv::Op opcode) {
return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
}
@@ -125,7 +125,7 @@ spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
const spv_opcode_table table,
const SpvOp opcode,
const spv::Op opcode,
spv_opcode_desc* pEntry) {
if (!table) return SPV_ERROR_INVALID_TABLE;
if (!pEntry) return SPV_ERROR_INVALID_POINTER;
@@ -166,7 +166,7 @@ spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
return SPV_ERROR_INVALID_LOOKUP;
}
void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
void spvInstructionCopy(const uint32_t* words, const spv::Op opcode,
const uint16_t wordCount, const spv_endianness_t endian,
spv_instruction_t* pInst) {
pInst->opcode = opcode;
@@ -177,7 +177,7 @@ void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
uint16_t thisWordCount;
uint16_t thisOpcode;
spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
assert(opcode == static_cast<SpvOp>(thisOpcode) &&
assert(opcode == static_cast<spv::Op>(thisOpcode) &&
wordCount == thisWordCount && "Endianness failed!");
}
}
@@ -186,7 +186,7 @@ void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
const char* spvOpcodeString(const uint32_t opcode) {
const auto beg = kOpcodeTableEntries;
const auto end = kOpcodeTableEntries + ARRAY_SIZE(kOpcodeTableEntries);
spv_opcode_desc_t needle = {"", static_cast<SpvOp>(opcode),
spv_opcode_desc_t needle = {"", static_cast<spv::Op>(opcode),
0, nullptr,
0, {},
false, false,
@@ -196,7 +196,7 @@ const char* spvOpcodeString(const uint32_t opcode) {
return lhs.opcode < rhs.opcode;
};
auto it = std::lower_bound(beg, end, needle, comp);
if (it != end && it->opcode == opcode) {
if (it != end && it->opcode == spv::Op(opcode)) {
return it->name;
}
@@ -204,140 +204,145 @@ const char* spvOpcodeString(const uint32_t opcode) {
return "unknown";
}
int32_t spvOpcodeIsScalarType(const SpvOp opcode) {
const char* spvOpcodeString(const spv::Op opcode) {
return spvOpcodeString(static_cast<uint32_t>(opcode));
}
int32_t spvOpcodeIsScalarType(const spv::Op opcode) {
switch (opcode) {
case SpvOpTypeInt:
case SpvOpTypeFloat:
case SpvOpTypeBool:
case spv::Op::OpTypeInt:
case spv::Op::OpTypeFloat:
case spv::Op::OpTypeBool:
return true;
default:
return false;
}
}
int32_t spvOpcodeIsSpecConstant(const SpvOp opcode) {
int32_t spvOpcodeIsSpecConstant(const spv::Op opcode) {
switch (opcode) {
case SpvOpSpecConstantTrue:
case SpvOpSpecConstantFalse:
case SpvOpSpecConstant:
case SpvOpSpecConstantComposite:
case SpvOpSpecConstantOp:
case spv::Op::OpSpecConstantTrue:
case spv::Op::OpSpecConstantFalse:
case spv::Op::OpSpecConstant:
case spv::Op::OpSpecConstantComposite:
case spv::Op::OpSpecConstantOp:
return true;
default:
return false;
}
}
int32_t spvOpcodeIsConstant(const SpvOp opcode) {
int32_t spvOpcodeIsConstant(const spv::Op opcode) {
switch (opcode) {
case SpvOpConstantTrue:
case SpvOpConstantFalse:
case SpvOpConstant:
case SpvOpConstantComposite:
case SpvOpConstantSampler:
case SpvOpConstantNull:
case SpvOpSpecConstantTrue:
case SpvOpSpecConstantFalse:
case SpvOpSpecConstant:
case SpvOpSpecConstantComposite:
case SpvOpSpecConstantOp:
case spv::Op::OpConstantTrue:
case spv::Op::OpConstantFalse:
case spv::Op::OpConstant:
case spv::Op::OpConstantComposite:
case spv::Op::OpConstantSampler:
case spv::Op::OpConstantNull:
case spv::Op::OpSpecConstantTrue:
case spv::Op::OpSpecConstantFalse:
case spv::Op::OpSpecConstant:
case spv::Op::OpSpecConstantComposite:
case spv::Op::OpSpecConstantOp:
return true;
default:
return false;
}
}
bool spvOpcodeIsConstantOrUndef(const SpvOp opcode) {
return opcode == SpvOpUndef || spvOpcodeIsConstant(opcode);
bool spvOpcodeIsConstantOrUndef(const spv::Op opcode) {
return opcode == spv::Op::OpUndef || spvOpcodeIsConstant(opcode);
}
bool spvOpcodeIsScalarSpecConstant(const SpvOp opcode) {
bool spvOpcodeIsScalarSpecConstant(const spv::Op opcode) {
switch (opcode) {
case SpvOpSpecConstantTrue:
case SpvOpSpecConstantFalse:
case SpvOpSpecConstant:
case spv::Op::OpSpecConstantTrue:
case spv::Op::OpSpecConstantFalse:
case spv::Op::OpSpecConstant:
return true;
default:
return false;
}
}
int32_t spvOpcodeIsComposite(const SpvOp opcode) {
int32_t spvOpcodeIsComposite(const spv::Op opcode) {
switch (opcode) {
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case SpvOpTypeArray:
case SpvOpTypeStruct:
case SpvOpTypeCooperativeMatrixNV:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeStruct:
case spv::Op::OpTypeCooperativeMatrixNV:
return true;
default:
return false;
}
}
bool spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode) {
bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) {
switch (opcode) {
case SpvOpVariable:
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpFunctionParameter:
case SpvOpImageTexelPointer:
case SpvOpCopyObject:
case SpvOpSelect:
case SpvOpPhi:
case SpvOpFunctionCall:
case SpvOpPtrAccessChain:
case SpvOpLoad:
case SpvOpConstantNull:
case spv::Op::OpVariable:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpFunctionParameter:
case spv::Op::OpImageTexelPointer:
case spv::Op::OpCopyObject:
case spv::Op::OpSelect:
case spv::Op::OpPhi:
case spv::Op::OpFunctionCall:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpLoad:
case spv::Op::OpConstantNull:
return true;
default:
return false;
}
}
int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode) {
int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) {
switch (opcode) {
case SpvOpVariable:
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpFunctionParameter:
case SpvOpImageTexelPointer:
case SpvOpCopyObject:
case spv::Op::OpVariable:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpFunctionParameter:
case spv::Op::OpImageTexelPointer:
case spv::Op::OpCopyObject:
return true;
default:
return false;
}
}
int32_t spvOpcodeGeneratesType(SpvOp op) {
int32_t spvOpcodeGeneratesType(spv::Op op) {
switch (op) {
case SpvOpTypeVoid:
case SpvOpTypeBool:
case SpvOpTypeInt:
case SpvOpTypeFloat:
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case SpvOpTypeImage:
case SpvOpTypeSampler:
case SpvOpTypeSampledImage:
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeStruct:
case SpvOpTypeOpaque:
case SpvOpTypePointer:
case SpvOpTypeFunction:
case SpvOpTypeEvent:
case SpvOpTypeDeviceEvent:
case SpvOpTypeReserveId:
case SpvOpTypeQueue:
case SpvOpTypePipe:
case SpvOpTypePipeStorage:
case SpvOpTypeNamedBarrier:
case SpvOpTypeAccelerationStructureNV:
case SpvOpTypeCooperativeMatrixNV:
// case SpvOpTypeAccelerationStructureKHR: covered by
// SpvOpTypeAccelerationStructureNV
case SpvOpTypeRayQueryKHR:
case spv::Op::OpTypeVoid:
case spv::Op::OpTypeBool:
case spv::Op::OpTypeInt:
case spv::Op::OpTypeFloat:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeImage:
case spv::Op::OpTypeSampler:
case spv::Op::OpTypeSampledImage:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeStruct:
case spv::Op::OpTypeOpaque:
case spv::Op::OpTypePointer:
case spv::Op::OpTypeFunction:
case spv::Op::OpTypeEvent:
case spv::Op::OpTypeDeviceEvent:
case spv::Op::OpTypeReserveId:
case spv::Op::OpTypeQueue:
case spv::Op::OpTypePipe:
case spv::Op::OpTypePipeStorage:
case spv::Op::OpTypeNamedBarrier:
case spv::Op::OpTypeAccelerationStructureNV:
case spv::Op::OpTypeCooperativeMatrixNV:
// case spv::Op::OpTypeAccelerationStructureKHR: covered by
// spv::Op::OpTypeAccelerationStructureNV
case spv::Op::OpTypeRayQueryKHR:
case spv::Op::OpTypeHitObjectNV:
return true;
default:
// In particular, OpTypeForwardPointer does not generate a type,
@@ -348,15 +353,15 @@ int32_t spvOpcodeGeneratesType(SpvOp op) {
return 0;
}
bool spvOpcodeIsDecoration(const SpvOp opcode) {
bool spvOpcodeIsDecoration(const spv::Op opcode) {
switch (opcode) {
case SpvOpDecorate:
case SpvOpDecorateId:
case SpvOpMemberDecorate:
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate:
case SpvOpDecorateStringGOOGLE:
case SpvOpMemberDecorateStringGOOGLE:
case spv::Op::OpDecorate:
case spv::Op::OpDecorateId:
case spv::Op::OpMemberDecorate:
case spv::Op::OpGroupDecorate:
case spv::Op::OpGroupMemberDecorate:
case spv::Op::OpDecorateStringGOOGLE:
case spv::Op::OpMemberDecorateStringGOOGLE:
return true;
default:
break;
@@ -364,402 +369,403 @@ bool spvOpcodeIsDecoration(const SpvOp opcode) {
return false;
}
bool spvOpcodeIsLoad(const SpvOp opcode) {
bool spvOpcodeIsLoad(const spv::Op opcode) {
switch (opcode) {
case SpvOpLoad:
case SpvOpImageSampleExplicitLod:
case SpvOpImageSampleImplicitLod:
case SpvOpImageSampleDrefImplicitLod:
case SpvOpImageSampleDrefExplicitLod:
case SpvOpImageSampleProjImplicitLod:
case SpvOpImageSampleProjExplicitLod:
case SpvOpImageSampleProjDrefImplicitLod:
case SpvOpImageSampleProjDrefExplicitLod:
case SpvOpImageFetch:
case SpvOpImageGather:
case SpvOpImageDrefGather:
case SpvOpImageRead:
case SpvOpImageSparseSampleImplicitLod:
case SpvOpImageSparseSampleExplicitLod:
case SpvOpImageSparseSampleDrefExplicitLod:
case SpvOpImageSparseSampleDrefImplicitLod:
case SpvOpImageSparseFetch:
case SpvOpImageSparseGather:
case SpvOpImageSparseDrefGather:
case SpvOpImageSparseRead:
case spv::Op::OpLoad:
case spv::Op::OpImageSampleExplicitLod:
case spv::Op::OpImageSampleImplicitLod:
case spv::Op::OpImageSampleDrefImplicitLod:
case spv::Op::OpImageSampleDrefExplicitLod:
case spv::Op::OpImageSampleProjImplicitLod:
case spv::Op::OpImageSampleProjExplicitLod:
case spv::Op::OpImageSampleProjDrefImplicitLod:
case spv::Op::OpImageSampleProjDrefExplicitLod:
case spv::Op::OpImageFetch:
case spv::Op::OpImageGather:
case spv::Op::OpImageDrefGather:
case spv::Op::OpImageRead:
case spv::Op::OpImageSparseSampleImplicitLod:
case spv::Op::OpImageSparseSampleExplicitLod:
case spv::Op::OpImageSparseSampleDrefExplicitLod:
case spv::Op::OpImageSparseSampleDrefImplicitLod:
case spv::Op::OpImageSparseFetch:
case spv::Op::OpImageSparseGather:
case spv::Op::OpImageSparseDrefGather:
case spv::Op::OpImageSparseRead:
return true;
default:
return false;
}
}
bool spvOpcodeIsBranch(SpvOp opcode) {
bool spvOpcodeIsBranch(spv::Op opcode) {
switch (opcode) {
case SpvOpBranch:
case SpvOpBranchConditional:
case SpvOpSwitch:
case spv::Op::OpBranch:
case spv::Op::OpBranchConditional:
case spv::Op::OpSwitch:
return true;
default:
return false;
}
}
bool spvOpcodeIsAtomicWithLoad(const SpvOp opcode) {
bool spvOpcodeIsAtomicWithLoad(const spv::Op opcode) {
switch (opcode) {
case SpvOpAtomicLoad:
case SpvOpAtomicExchange:
case SpvOpAtomicCompareExchange:
case SpvOpAtomicCompareExchangeWeak:
case SpvOpAtomicIIncrement:
case SpvOpAtomicIDecrement:
case SpvOpAtomicIAdd:
case SpvOpAtomicFAddEXT:
case SpvOpAtomicISub:
case SpvOpAtomicSMin:
case SpvOpAtomicUMin:
case SpvOpAtomicFMinEXT:
case SpvOpAtomicSMax:
case SpvOpAtomicUMax:
case SpvOpAtomicFMaxEXT:
case SpvOpAtomicAnd:
case SpvOpAtomicOr:
case SpvOpAtomicXor:
case SpvOpAtomicFlagTestAndSet:
case spv::Op::OpAtomicLoad:
case spv::Op::OpAtomicExchange:
case spv::Op::OpAtomicCompareExchange:
case spv::Op::OpAtomicCompareExchangeWeak:
case spv::Op::OpAtomicIIncrement:
case spv::Op::OpAtomicIDecrement:
case spv::Op::OpAtomicIAdd:
case spv::Op::OpAtomicFAddEXT:
case spv::Op::OpAtomicISub:
case spv::Op::OpAtomicSMin:
case spv::Op::OpAtomicUMin:
case spv::Op::OpAtomicFMinEXT:
case spv::Op::OpAtomicSMax:
case spv::Op::OpAtomicUMax:
case spv::Op::OpAtomicFMaxEXT:
case spv::Op::OpAtomicAnd:
case spv::Op::OpAtomicOr:
case spv::Op::OpAtomicXor:
case spv::Op::OpAtomicFlagTestAndSet:
return true;
default:
return false;
}
}
bool spvOpcodeIsAtomicOp(const SpvOp opcode) {
return (spvOpcodeIsAtomicWithLoad(opcode) || opcode == SpvOpAtomicStore ||
opcode == SpvOpAtomicFlagClear);
bool spvOpcodeIsAtomicOp(const spv::Op opcode) {
return (spvOpcodeIsAtomicWithLoad(opcode) ||
opcode == spv::Op::OpAtomicStore ||
opcode == spv::Op::OpAtomicFlagClear);
}
bool spvOpcodeIsReturn(SpvOp opcode) {
bool spvOpcodeIsReturn(spv::Op opcode) {
switch (opcode) {
case SpvOpReturn:
case SpvOpReturnValue:
case spv::Op::OpReturn:
case spv::Op::OpReturnValue:
return true;
default:
return false;
}
}
bool spvOpcodeIsAbort(SpvOp opcode) {
bool spvOpcodeIsAbort(spv::Op opcode) {
switch (opcode) {
case SpvOpKill:
case SpvOpUnreachable:
case SpvOpTerminateInvocation:
case SpvOpTerminateRayKHR:
case SpvOpIgnoreIntersectionKHR:
case SpvOpEmitMeshTasksEXT:
case spv::Op::OpKill:
case spv::Op::OpUnreachable:
case spv::Op::OpTerminateInvocation:
case spv::Op::OpTerminateRayKHR:
case spv::Op::OpIgnoreIntersectionKHR:
case spv::Op::OpEmitMeshTasksEXT:
return true;
default:
return false;
}
}
bool spvOpcodeIsReturnOrAbort(SpvOp opcode) {
bool spvOpcodeIsReturnOrAbort(spv::Op opcode) {
return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode);
}
bool spvOpcodeIsBlockTerminator(SpvOp opcode) {
bool spvOpcodeIsBlockTerminator(spv::Op opcode) {
return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
}
bool spvOpcodeIsBaseOpaqueType(SpvOp opcode) {
bool spvOpcodeIsBaseOpaqueType(spv::Op opcode) {
switch (opcode) {
case SpvOpTypeImage:
case SpvOpTypeSampler:
case SpvOpTypeSampledImage:
case SpvOpTypeOpaque:
case SpvOpTypeEvent:
case SpvOpTypeDeviceEvent:
case SpvOpTypeReserveId:
case SpvOpTypeQueue:
case SpvOpTypePipe:
case SpvOpTypeForwardPointer:
case SpvOpTypePipeStorage:
case SpvOpTypeNamedBarrier:
case spv::Op::OpTypeImage:
case spv::Op::OpTypeSampler:
case spv::Op::OpTypeSampledImage:
case spv::Op::OpTypeOpaque:
case spv::Op::OpTypeEvent:
case spv::Op::OpTypeDeviceEvent:
case spv::Op::OpTypeReserveId:
case spv::Op::OpTypeQueue:
case spv::Op::OpTypePipe:
case spv::Op::OpTypeForwardPointer:
case spv::Op::OpTypePipeStorage:
case spv::Op::OpTypeNamedBarrier:
return true;
default:
return false;
}
}
bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode) {
bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
switch (opcode) {
case SpvOpGroupNonUniformElect:
case SpvOpGroupNonUniformAll:
case SpvOpGroupNonUniformAny:
case SpvOpGroupNonUniformAllEqual:
case SpvOpGroupNonUniformBroadcast:
case SpvOpGroupNonUniformBroadcastFirst:
case SpvOpGroupNonUniformBallot:
case SpvOpGroupNonUniformInverseBallot:
case SpvOpGroupNonUniformBallotBitExtract:
case SpvOpGroupNonUniformBallotBitCount:
case SpvOpGroupNonUniformBallotFindLSB:
case SpvOpGroupNonUniformBallotFindMSB:
case SpvOpGroupNonUniformShuffle:
case SpvOpGroupNonUniformShuffleXor:
case SpvOpGroupNonUniformShuffleUp:
case SpvOpGroupNonUniformShuffleDown:
case SpvOpGroupNonUniformIAdd:
case SpvOpGroupNonUniformFAdd:
case SpvOpGroupNonUniformIMul:
case SpvOpGroupNonUniformFMul:
case SpvOpGroupNonUniformSMin:
case SpvOpGroupNonUniformUMin:
case SpvOpGroupNonUniformFMin:
case SpvOpGroupNonUniformSMax:
case SpvOpGroupNonUniformUMax:
case SpvOpGroupNonUniformFMax:
case SpvOpGroupNonUniformBitwiseAnd:
case SpvOpGroupNonUniformBitwiseOr:
case SpvOpGroupNonUniformBitwiseXor:
case SpvOpGroupNonUniformLogicalAnd:
case SpvOpGroupNonUniformLogicalOr:
case SpvOpGroupNonUniformLogicalXor:
case SpvOpGroupNonUniformQuadBroadcast:
case SpvOpGroupNonUniformQuadSwap:
case SpvOpGroupNonUniformRotateKHR:
case spv::Op::OpGroupNonUniformElect:
case spv::Op::OpGroupNonUniformAll:
case spv::Op::OpGroupNonUniformAny:
case spv::Op::OpGroupNonUniformAllEqual:
case spv::Op::OpGroupNonUniformBroadcast:
case spv::Op::OpGroupNonUniformBroadcastFirst:
case spv::Op::OpGroupNonUniformBallot:
case spv::Op::OpGroupNonUniformInverseBallot:
case spv::Op::OpGroupNonUniformBallotBitExtract:
case spv::Op::OpGroupNonUniformBallotBitCount:
case spv::Op::OpGroupNonUniformBallotFindLSB:
case spv::Op::OpGroupNonUniformBallotFindMSB:
case spv::Op::OpGroupNonUniformShuffle:
case spv::Op::OpGroupNonUniformShuffleXor:
case spv::Op::OpGroupNonUniformShuffleUp:
case spv::Op::OpGroupNonUniformShuffleDown:
case spv::Op::OpGroupNonUniformIAdd:
case spv::Op::OpGroupNonUniformFAdd:
case spv::Op::OpGroupNonUniformIMul:
case spv::Op::OpGroupNonUniformFMul:
case spv::Op::OpGroupNonUniformSMin:
case spv::Op::OpGroupNonUniformUMin:
case spv::Op::OpGroupNonUniformFMin:
case spv::Op::OpGroupNonUniformSMax:
case spv::Op::OpGroupNonUniformUMax:
case spv::Op::OpGroupNonUniformFMax:
case spv::Op::OpGroupNonUniformBitwiseAnd:
case spv::Op::OpGroupNonUniformBitwiseOr:
case spv::Op::OpGroupNonUniformBitwiseXor:
case spv::Op::OpGroupNonUniformLogicalAnd:
case spv::Op::OpGroupNonUniformLogicalOr:
case spv::Op::OpGroupNonUniformLogicalXor:
case spv::Op::OpGroupNonUniformQuadBroadcast:
case spv::Op::OpGroupNonUniformQuadSwap:
case spv::Op::OpGroupNonUniformRotateKHR:
return true;
default:
return false;
}
}
bool spvOpcodeIsScalarizable(SpvOp opcode) {
bool spvOpcodeIsScalarizable(spv::Op opcode) {
switch (opcode) {
case SpvOpPhi:
case SpvOpCopyObject:
case SpvOpConvertFToU:
case SpvOpConvertFToS:
case SpvOpConvertSToF:
case SpvOpConvertUToF:
case SpvOpUConvert:
case SpvOpSConvert:
case SpvOpFConvert:
case SpvOpQuantizeToF16:
case SpvOpVectorInsertDynamic:
case SpvOpSNegate:
case SpvOpFNegate:
case SpvOpIAdd:
case SpvOpFAdd:
case SpvOpISub:
case SpvOpFSub:
case SpvOpIMul:
case SpvOpFMul:
case SpvOpUDiv:
case SpvOpSDiv:
case SpvOpFDiv:
case SpvOpUMod:
case SpvOpSRem:
case SpvOpSMod:
case SpvOpFRem:
case SpvOpFMod:
case SpvOpVectorTimesScalar:
case SpvOpIAddCarry:
case SpvOpISubBorrow:
case SpvOpUMulExtended:
case SpvOpSMulExtended:
case SpvOpShiftRightLogical:
case SpvOpShiftRightArithmetic:
case SpvOpShiftLeftLogical:
case SpvOpBitwiseOr:
case SpvOpBitwiseAnd:
case SpvOpNot:
case SpvOpBitFieldInsert:
case SpvOpBitFieldSExtract:
case SpvOpBitFieldUExtract:
case SpvOpBitReverse:
case SpvOpBitCount:
case SpvOpIsNan:
case SpvOpIsInf:
case SpvOpIsFinite:
case SpvOpIsNormal:
case SpvOpSignBitSet:
case SpvOpLessOrGreater:
case SpvOpOrdered:
case SpvOpUnordered:
case SpvOpLogicalEqual:
case SpvOpLogicalNotEqual:
case SpvOpLogicalOr:
case SpvOpLogicalAnd:
case SpvOpLogicalNot:
case SpvOpSelect:
case SpvOpIEqual:
case SpvOpINotEqual:
case SpvOpUGreaterThan:
case SpvOpSGreaterThan:
case SpvOpUGreaterThanEqual:
case SpvOpSGreaterThanEqual:
case SpvOpULessThan:
case SpvOpSLessThan:
case SpvOpULessThanEqual:
case SpvOpSLessThanEqual:
case SpvOpFOrdEqual:
case SpvOpFUnordEqual:
case SpvOpFOrdNotEqual:
case SpvOpFUnordNotEqual:
case SpvOpFOrdLessThan:
case SpvOpFUnordLessThan:
case SpvOpFOrdGreaterThan:
case SpvOpFUnordGreaterThan:
case SpvOpFOrdLessThanEqual:
case SpvOpFUnordLessThanEqual:
case SpvOpFOrdGreaterThanEqual:
case SpvOpFUnordGreaterThanEqual:
case spv::Op::OpPhi:
case spv::Op::OpCopyObject:
case spv::Op::OpConvertFToU:
case spv::Op::OpConvertFToS:
case spv::Op::OpConvertSToF:
case spv::Op::OpConvertUToF:
case spv::Op::OpUConvert:
case spv::Op::OpSConvert:
case spv::Op::OpFConvert:
case spv::Op::OpQuantizeToF16:
case spv::Op::OpVectorInsertDynamic:
case spv::Op::OpSNegate:
case spv::Op::OpFNegate:
case spv::Op::OpIAdd:
case spv::Op::OpFAdd:
case spv::Op::OpISub:
case spv::Op::OpFSub:
case spv::Op::OpIMul:
case spv::Op::OpFMul:
case spv::Op::OpUDiv:
case spv::Op::OpSDiv:
case spv::Op::OpFDiv:
case spv::Op::OpUMod:
case spv::Op::OpSRem:
case spv::Op::OpSMod:
case spv::Op::OpFRem:
case spv::Op::OpFMod:
case spv::Op::OpVectorTimesScalar:
case spv::Op::OpIAddCarry:
case spv::Op::OpISubBorrow:
case spv::Op::OpUMulExtended:
case spv::Op::OpSMulExtended:
case spv::Op::OpShiftRightLogical:
case spv::Op::OpShiftRightArithmetic:
case spv::Op::OpShiftLeftLogical:
case spv::Op::OpBitwiseOr:
case spv::Op::OpBitwiseAnd:
case spv::Op::OpNot:
case spv::Op::OpBitFieldInsert:
case spv::Op::OpBitFieldSExtract:
case spv::Op::OpBitFieldUExtract:
case spv::Op::OpBitReverse:
case spv::Op::OpBitCount:
case spv::Op::OpIsNan:
case spv::Op::OpIsInf:
case spv::Op::OpIsFinite:
case spv::Op::OpIsNormal:
case spv::Op::OpSignBitSet:
case spv::Op::OpLessOrGreater:
case spv::Op::OpOrdered:
case spv::Op::OpUnordered:
case spv::Op::OpLogicalEqual:
case spv::Op::OpLogicalNotEqual:
case spv::Op::OpLogicalOr:
case spv::Op::OpLogicalAnd:
case spv::Op::OpLogicalNot:
case spv::Op::OpSelect:
case spv::Op::OpIEqual:
case spv::Op::OpINotEqual:
case spv::Op::OpUGreaterThan:
case spv::Op::OpSGreaterThan:
case spv::Op::OpUGreaterThanEqual:
case spv::Op::OpSGreaterThanEqual:
case spv::Op::OpULessThan:
case spv::Op::OpSLessThan:
case spv::Op::OpULessThanEqual:
case spv::Op::OpSLessThanEqual:
case spv::Op::OpFOrdEqual:
case spv::Op::OpFUnordEqual:
case spv::Op::OpFOrdNotEqual:
case spv::Op::OpFUnordNotEqual:
case spv::Op::OpFOrdLessThan:
case spv::Op::OpFUnordLessThan:
case spv::Op::OpFOrdGreaterThan:
case spv::Op::OpFUnordGreaterThan:
case spv::Op::OpFOrdLessThanEqual:
case spv::Op::OpFUnordLessThanEqual:
case spv::Op::OpFOrdGreaterThanEqual:
case spv::Op::OpFUnordGreaterThanEqual:
return true;
default:
return false;
}
}
bool spvOpcodeIsDebug(SpvOp opcode) {
bool spvOpcodeIsDebug(spv::Op opcode) {
switch (opcode) {
case SpvOpName:
case SpvOpMemberName:
case SpvOpSource:
case SpvOpSourceContinued:
case SpvOpSourceExtension:
case SpvOpString:
case SpvOpLine:
case SpvOpNoLine:
case SpvOpModuleProcessed:
case spv::Op::OpName:
case spv::Op::OpMemberName:
case spv::Op::OpSource:
case spv::Op::OpSourceContinued:
case spv::Op::OpSourceExtension:
case spv::Op::OpString:
case spv::Op::OpLine:
case spv::Op::OpNoLine:
case spv::Op::OpModuleProcessed:
return true;
default:
return false;
}
}
bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode) {
bool spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode) {
switch (opcode) {
case SpvOpPtrEqual:
case SpvOpPtrNotEqual:
case SpvOpIAdd:
case SpvOpFAdd:
case SpvOpIMul:
case SpvOpFMul:
case SpvOpDot:
case SpvOpIAddCarry:
case SpvOpUMulExtended:
case SpvOpSMulExtended:
case SpvOpBitwiseOr:
case SpvOpBitwiseXor:
case SpvOpBitwiseAnd:
case SpvOpOrdered:
case SpvOpUnordered:
case SpvOpLogicalEqual:
case SpvOpLogicalNotEqual:
case SpvOpLogicalOr:
case SpvOpLogicalAnd:
case SpvOpIEqual:
case SpvOpINotEqual:
case SpvOpFOrdEqual:
case SpvOpFUnordEqual:
case SpvOpFOrdNotEqual:
case SpvOpFUnordNotEqual:
case spv::Op::OpPtrEqual:
case spv::Op::OpPtrNotEqual:
case spv::Op::OpIAdd:
case spv::Op::OpFAdd:
case spv::Op::OpIMul:
case spv::Op::OpFMul:
case spv::Op::OpDot:
case spv::Op::OpIAddCarry:
case spv::Op::OpUMulExtended:
case spv::Op::OpSMulExtended:
case spv::Op::OpBitwiseOr:
case spv::Op::OpBitwiseXor:
case spv::Op::OpBitwiseAnd:
case spv::Op::OpOrdered:
case spv::Op::OpUnordered:
case spv::Op::OpLogicalEqual:
case spv::Op::OpLogicalNotEqual:
case spv::Op::OpLogicalOr:
case spv::Op::OpLogicalAnd:
case spv::Op::OpIEqual:
case spv::Op::OpINotEqual:
case spv::Op::OpFOrdEqual:
case spv::Op::OpFUnordEqual:
case spv::Op::OpFOrdNotEqual:
case spv::Op::OpFUnordNotEqual:
return true;
default:
return false;
}
}
bool spvOpcodeIsLinearAlgebra(SpvOp opcode) {
bool spvOpcodeIsLinearAlgebra(spv::Op opcode) {
switch (opcode) {
case SpvOpTranspose:
case SpvOpVectorTimesScalar:
case SpvOpMatrixTimesScalar:
case SpvOpVectorTimesMatrix:
case SpvOpMatrixTimesVector:
case SpvOpMatrixTimesMatrix:
case SpvOpOuterProduct:
case SpvOpDot:
case spv::Op::OpTranspose:
case spv::Op::OpVectorTimesScalar:
case spv::Op::OpMatrixTimesScalar:
case spv::Op::OpVectorTimesMatrix:
case spv::Op::OpMatrixTimesVector:
case spv::Op::OpMatrixTimesMatrix:
case spv::Op::OpOuterProduct:
case spv::Op::OpDot:
return true;
default:
return false;
}
}
bool spvOpcodeIsImageSample(const SpvOp opcode) {
bool spvOpcodeIsImageSample(const spv::Op opcode) {
switch (opcode) {
case SpvOpImageSampleImplicitLod:
case SpvOpImageSampleExplicitLod:
case SpvOpImageSampleDrefImplicitLod:
case SpvOpImageSampleDrefExplicitLod:
case SpvOpImageSampleProjImplicitLod:
case SpvOpImageSampleProjExplicitLod:
case SpvOpImageSampleProjDrefImplicitLod:
case SpvOpImageSampleProjDrefExplicitLod:
case SpvOpImageSparseSampleImplicitLod:
case SpvOpImageSparseSampleExplicitLod:
case SpvOpImageSparseSampleDrefImplicitLod:
case SpvOpImageSparseSampleDrefExplicitLod:
case spv::Op::OpImageSampleImplicitLod:
case spv::Op::OpImageSampleExplicitLod:
case spv::Op::OpImageSampleDrefImplicitLod:
case spv::Op::OpImageSampleDrefExplicitLod:
case spv::Op::OpImageSampleProjImplicitLod:
case spv::Op::OpImageSampleProjExplicitLod:
case spv::Op::OpImageSampleProjDrefImplicitLod:
case spv::Op::OpImageSampleProjDrefExplicitLod:
case spv::Op::OpImageSparseSampleImplicitLod:
case spv::Op::OpImageSparseSampleExplicitLod:
case spv::Op::OpImageSparseSampleDrefImplicitLod:
case spv::Op::OpImageSparseSampleDrefExplicitLod:
return true;
default:
return false;
}
}
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode) {
switch (opcode) {
case SpvOpMemoryBarrier:
case spv::Op::OpMemoryBarrier:
return {1};
case SpvOpAtomicStore:
case SpvOpControlBarrier:
case SpvOpAtomicFlagClear:
case SpvOpMemoryNamedBarrier:
case spv::Op::OpAtomicStore:
case spv::Op::OpControlBarrier:
case spv::Op::OpAtomicFlagClear:
case spv::Op::OpMemoryNamedBarrier:
return {2};
case SpvOpAtomicLoad:
case SpvOpAtomicExchange:
case SpvOpAtomicIIncrement:
case SpvOpAtomicIDecrement:
case SpvOpAtomicIAdd:
case SpvOpAtomicFAddEXT:
case SpvOpAtomicISub:
case SpvOpAtomicSMin:
case SpvOpAtomicUMin:
case SpvOpAtomicSMax:
case SpvOpAtomicUMax:
case SpvOpAtomicAnd:
case SpvOpAtomicOr:
case SpvOpAtomicXor:
case SpvOpAtomicFlagTestAndSet:
case spv::Op::OpAtomicLoad:
case spv::Op::OpAtomicExchange:
case spv::Op::OpAtomicIIncrement:
case spv::Op::OpAtomicIDecrement:
case spv::Op::OpAtomicIAdd:
case spv::Op::OpAtomicFAddEXT:
case spv::Op::OpAtomicISub:
case spv::Op::OpAtomicSMin:
case spv::Op::OpAtomicUMin:
case spv::Op::OpAtomicSMax:
case spv::Op::OpAtomicUMax:
case spv::Op::OpAtomicAnd:
case spv::Op::OpAtomicOr:
case spv::Op::OpAtomicXor:
case spv::Op::OpAtomicFlagTestAndSet:
return {4};
case SpvOpAtomicCompareExchange:
case SpvOpAtomicCompareExchangeWeak:
case spv::Op::OpAtomicCompareExchange:
case spv::Op::OpAtomicCompareExchangeWeak:
return {4, 5};
default:
return {};
}
}
bool spvOpcodeIsAccessChain(SpvOp opcode) {
bool spvOpcodeIsAccessChain(spv::Op opcode) {
switch (opcode) {
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
return true;
default:
return false;
}
}
bool spvOpcodeIsBit(SpvOp opcode) {
bool spvOpcodeIsBit(spv::Op opcode) {
switch (opcode) {
case SpvOpShiftRightLogical:
case SpvOpShiftRightArithmetic:
case SpvOpShiftLeftLogical:
case SpvOpBitwiseOr:
case SpvOpBitwiseXor:
case SpvOpBitwiseAnd:
case SpvOpNot:
case SpvOpBitReverse:
case SpvOpBitCount:
case spv::Op::OpShiftRightLogical:
case spv::Op::OpShiftRightArithmetic:
case spv::Op::OpShiftLeftLogical:
case spv::Op::OpBitwiseOr:
case spv::Op::OpBitwiseXor:
case spv::Op::OpBitwiseAnd:
case spv::Op::OpNot:
case spv::Op::OpBitReverse:
case spv::Op::OpBitCount:
return true;
default:
return false;

View File

@@ -29,7 +29,7 @@
const char* spvGeneratorStr(uint32_t generator);
// Combines word_count and opcode enumerant in single word.
uint32_t spvOpcodeMake(uint16_t word_count, SpvOp opcode);
uint32_t spvOpcodeMake(uint16_t word_count, spv::Op opcode);
// Splits word into into two constituent parts: word_count and opcode.
void spvOpcodeSplit(const uint32_t word, uint16_t* word_count,
@@ -45,115 +45,118 @@ spv_result_t spvOpcodeTableNameLookup(spv_target_env,
// SPV_SUCCESS and writes a handle of the table entry into *entry.
spv_result_t spvOpcodeTableValueLookup(spv_target_env,
const spv_opcode_table table,
const SpvOp opcode,
const spv::Op opcode,
spv_opcode_desc* entry);
// Copies an instruction's word and fixes the endianness to host native. The
// source instruction's stream/opcode/endianness is in the words/opcode/endian
// parameter. The word_count parameter specifies the number of words to copy.
// Writes copied instruction into *inst.
void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
void spvInstructionCopy(const uint32_t* words, const spv::Op opcode,
const uint16_t word_count,
const spv_endianness_t endian, spv_instruction_t* inst);
// Determine if the given opcode is a scalar type. Returns zero if false,
// non-zero otherwise.
int32_t spvOpcodeIsScalarType(const SpvOp opcode);
int32_t spvOpcodeIsScalarType(const spv::Op opcode);
// Determines if the given opcode is a specialization constant. Returns zero if
// false, non-zero otherwise.
int32_t spvOpcodeIsSpecConstant(const SpvOp opcode);
int32_t spvOpcodeIsSpecConstant(const spv::Op opcode);
// Determines if the given opcode is a constant. Returns zero if false, non-zero
// otherwise.
int32_t spvOpcodeIsConstant(const SpvOp opcode);
int32_t spvOpcodeIsConstant(const spv::Op opcode);
// Returns true if the given opcode is a constant or undef.
bool spvOpcodeIsConstantOrUndef(const SpvOp opcode);
bool spvOpcodeIsConstantOrUndef(const spv::Op opcode);
// Returns true if the given opcode is a scalar specialization constant.
bool spvOpcodeIsScalarSpecConstant(const SpvOp opcode);
bool spvOpcodeIsScalarSpecConstant(const spv::Op opcode);
// Determines if the given opcode is a composite type. Returns zero if false,
// non-zero otherwise.
int32_t spvOpcodeIsComposite(const SpvOp opcode);
int32_t spvOpcodeIsComposite(const spv::Op opcode);
// Determines if the given opcode results in a pointer when using the logical
// addressing model. Returns zero if false, non-zero otherwise.
int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode);
int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode);
// Returns whether the given opcode could result in a pointer or a variable
// pointer when using the logical addressing model.
bool spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode);
bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode);
// Determines if the given opcode generates a type. Returns zero if false,
// non-zero otherwise.
int32_t spvOpcodeGeneratesType(SpvOp opcode);
int32_t spvOpcodeGeneratesType(spv::Op opcode);
// Returns true if the opcode adds a decoration to an id.
bool spvOpcodeIsDecoration(const SpvOp opcode);
bool spvOpcodeIsDecoration(const spv::Op opcode);
// Returns true if the opcode is a load from memory into a result id. This
// function only considers core instructions.
bool spvOpcodeIsLoad(const SpvOp opcode);
bool spvOpcodeIsLoad(const spv::Op opcode);
// Returns true if the opcode is an atomic operation that uses the original
// value.
bool spvOpcodeIsAtomicWithLoad(const SpvOp opcode);
bool spvOpcodeIsAtomicWithLoad(const spv::Op opcode);
// Returns true if the opcode is an atomic operation.
bool spvOpcodeIsAtomicOp(const SpvOp opcode);
bool spvOpcodeIsAtomicOp(const spv::Op opcode);
// Returns true if the given opcode is a branch instruction.
bool spvOpcodeIsBranch(SpvOp opcode);
bool spvOpcodeIsBranch(spv::Op opcode);
// Returns true if the given opcode is a return instruction.
bool spvOpcodeIsReturn(SpvOp opcode);
bool spvOpcodeIsReturn(spv::Op opcode);
// Returns true if the given opcode aborts execution. To abort means that after
// executing that instruction, no other instructions will be executed regardless
// of the context in which the instruction appears. Note that `OpUnreachable`
// is considered an abort even if its behaviour is undefined.
bool spvOpcodeIsAbort(SpvOp opcode);
bool spvOpcodeIsAbort(spv::Op opcode);
// Returns true if the given opcode is a return instruction or it aborts
// execution.
bool spvOpcodeIsReturnOrAbort(SpvOp opcode);
bool spvOpcodeIsReturnOrAbort(spv::Op opcode);
// Returns true if the given opcode is a basic block terminator.
bool spvOpcodeIsBlockTerminator(SpvOp opcode);
bool spvOpcodeIsBlockTerminator(spv::Op opcode);
// Returns true if the given opcode always defines an opaque type.
bool spvOpcodeIsBaseOpaqueType(SpvOp opcode);
bool spvOpcodeIsBaseOpaqueType(spv::Op opcode);
// Returns true if the given opcode is a non-uniform group operation.
bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode);
bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode);
// Returns true if the opcode with vector inputs could be divided into a series
// of independent scalar operations that would give the same result.
bool spvOpcodeIsScalarizable(SpvOp opcode);
bool spvOpcodeIsScalarizable(spv::Op opcode);
// Returns true if the given opcode is a debug instruction.
bool spvOpcodeIsDebug(SpvOp opcode);
bool spvOpcodeIsDebug(spv::Op opcode);
// Returns true for opcodes that are binary operators,
// where the order of the operands is irrelevant.
bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode);
bool spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode);
// Returns true for opcodes that represent linear algebra instructions.
bool spvOpcodeIsLinearAlgebra(SpvOp opcode);
bool spvOpcodeIsLinearAlgebra(spv::Op opcode);
// Returns true for opcodes that represent image sample instructions.
bool spvOpcodeIsImageSample(SpvOp opcode);
bool spvOpcodeIsImageSample(spv::Op opcode);
// Returns a vector containing the indices of the memory semantics <id>
// operands for |opcode|.
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode);
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode);
// Returns true for opcodes that represent access chain instructions.
bool spvOpcodeIsAccessChain(SpvOp opcode);
bool spvOpcodeIsAccessChain(spv::Op opcode);
// Returns true for opcodes that represent bit instructions.
bool spvOpcodeIsBit(SpvOp opcode);
bool spvOpcodeIsBit(spv::Op opcode);
// Gets the name of an instruction, without the "Op" prefix.
const char* spvOpcodeString(const spv::Op opcode);
#endif // SOURCE_OPCODE_H_

View File

@@ -512,7 +512,7 @@ bool spvIsInIdType(spv_operand_type_t type) {
}
std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
SpvOp opcode) {
spv::Op opcode) {
std::function<bool(unsigned index)> out;
if (spvOpcodeGeneratesType(opcode)) {
// All types can use forward pointers.
@@ -520,57 +520,57 @@ std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
return out;
}
switch (opcode) {
case SpvOpExecutionMode:
case SpvOpExecutionModeId:
case SpvOpEntryPoint:
case SpvOpName:
case SpvOpMemberName:
case SpvOpSelectionMerge:
case SpvOpDecorate:
case SpvOpMemberDecorate:
case SpvOpDecorateId:
case SpvOpDecorateStringGOOGLE:
case SpvOpMemberDecorateStringGOOGLE:
case SpvOpBranch:
case SpvOpLoopMerge:
case spv::Op::OpExecutionMode:
case spv::Op::OpExecutionModeId:
case spv::Op::OpEntryPoint:
case spv::Op::OpName:
case spv::Op::OpMemberName:
case spv::Op::OpSelectionMerge:
case spv::Op::OpDecorate:
case spv::Op::OpMemberDecorate:
case spv::Op::OpDecorateId:
case spv::Op::OpDecorateStringGOOGLE:
case spv::Op::OpMemberDecorateStringGOOGLE:
case spv::Op::OpBranch:
case spv::Op::OpLoopMerge:
out = [](unsigned) { return true; };
break;
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate:
case SpvOpBranchConditional:
case SpvOpSwitch:
case spv::Op::OpGroupDecorate:
case spv::Op::OpGroupMemberDecorate:
case spv::Op::OpBranchConditional:
case spv::Op::OpSwitch:
out = [](unsigned index) { return index != 0; };
break;
case SpvOpFunctionCall:
case spv::Op::OpFunctionCall:
// The Function parameter.
out = [](unsigned index) { return index == 2; };
break;
case SpvOpPhi:
case spv::Op::OpPhi:
out = [](unsigned index) { return index > 1; };
break;
case SpvOpEnqueueKernel:
case spv::Op::OpEnqueueKernel:
// The Invoke parameter.
out = [](unsigned index) { return index == 8; };
break;
case SpvOpGetKernelNDrangeSubGroupCount:
case SpvOpGetKernelNDrangeMaxSubGroupSize:
case spv::Op::OpGetKernelNDrangeSubGroupCount:
case spv::Op::OpGetKernelNDrangeMaxSubGroupSize:
// The Invoke parameter.
out = [](unsigned index) { return index == 3; };
break;
case SpvOpGetKernelWorkGroupSize:
case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
case spv::Op::OpGetKernelWorkGroupSize:
case spv::Op::OpGetKernelPreferredWorkGroupSizeMultiple:
// The Invoke parameter.
out = [](unsigned index) { return index == 2; };
break;
case SpvOpTypeForwardPointer:
case spv::Op::OpTypeForwardPointer:
out = [](unsigned index) { return index == 0; };
break;
case SpvOpTypeArray:
case spv::Op::OpTypeArray:
out = [](unsigned index) { return index == 1; };
break;
default:

View File

@@ -139,7 +139,7 @@ bool spvIsInIdType(spv_operand_type_t type);
// of the operand can be forward declared. This function will
// used in the SSA validation stage of the pipeline
std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
SpvOp opcode);
spv::Op opcode);
// Takes the instruction key of a debug info extension instruction
// and returns a function object that will return true if the index

View File

@@ -31,51 +31,50 @@
namespace spvtools {
namespace opt {
namespace {
const uint32_t kTypePointerStorageClassInIdx = 0;
const uint32_t kEntryPointFunctionIdInIdx = 1;
const uint32_t kSelectionMergeMergeBlockIdInIdx = 0;
const uint32_t kLoopMergeContinueBlockIdInIdx = 1;
const uint32_t kCopyMemoryTargetAddrInIdx = 0;
const uint32_t kCopyMemorySourceAddrInIdx = 1;
const uint32_t kLoadSourceAddrInIdx = 0;
const uint32_t kDebugDeclareOperandVariableIndex = 5;
const uint32_t kGlobalVariableVariableIndex = 12;
constexpr uint32_t kTypePointerStorageClassInIdx = 0;
constexpr uint32_t kEntryPointFunctionIdInIdx = 1;
constexpr uint32_t kSelectionMergeMergeBlockIdInIdx = 0;
constexpr uint32_t kLoopMergeContinueBlockIdInIdx = 1;
constexpr uint32_t kCopyMemoryTargetAddrInIdx = 0;
constexpr uint32_t kCopyMemorySourceAddrInIdx = 1;
constexpr uint32_t kLoadSourceAddrInIdx = 0;
constexpr uint32_t kDebugDeclareOperandVariableIndex = 5;
constexpr uint32_t kGlobalVariableVariableIndex = 12;
// Sorting functor to present annotation instructions in an easy-to-process
// order. The functor orders by opcode first and falls back on unique id
// ordering if both instructions have the same opcode.
//
// Desired priority:
// SpvOpGroupDecorate
// SpvOpGroupMemberDecorate
// SpvOpDecorate
// SpvOpMemberDecorate
// SpvOpDecorateId
// SpvOpDecorateStringGOOGLE
// SpvOpDecorationGroup
// spv::Op::OpGroupDecorate
// spv::Op::OpGroupMemberDecorate
// spv::Op::OpDecorate
// spv::Op::OpMemberDecorate
// spv::Op::OpDecorateId
// spv::Op::OpDecorateStringGOOGLE
// spv::Op::OpDecorationGroup
struct DecorationLess {
bool operator()(const Instruction* lhs, const Instruction* rhs) const {
assert(lhs && rhs);
SpvOp lhsOp = lhs->opcode();
SpvOp rhsOp = rhs->opcode();
spv::Op lhsOp = lhs->opcode();
spv::Op rhsOp = rhs->opcode();
if (lhsOp != rhsOp) {
#define PRIORITY_CASE(opcode) \
if (lhsOp == opcode && rhsOp != opcode) return true; \
if (rhsOp == opcode && lhsOp != opcode) return false;
// OpGroupDecorate and OpGroupMember decorate are highest priority to
// eliminate dead targets early and simplify subsequent checks.
PRIORITY_CASE(SpvOpGroupDecorate)
PRIORITY_CASE(SpvOpGroupMemberDecorate)
PRIORITY_CASE(SpvOpDecorate)
PRIORITY_CASE(SpvOpMemberDecorate)
PRIORITY_CASE(SpvOpDecorateId)
PRIORITY_CASE(SpvOpDecorateStringGOOGLE)
PRIORITY_CASE(spv::Op::OpGroupDecorate)
PRIORITY_CASE(spv::Op::OpGroupMemberDecorate)
PRIORITY_CASE(spv::Op::OpDecorate)
PRIORITY_CASE(spv::Op::OpMemberDecorate)
PRIORITY_CASE(spv::Op::OpDecorateId)
PRIORITY_CASE(spv::Op::OpDecorateStringGOOGLE)
// OpDecorationGroup is lowest priority to ensure use/def chains remain
// usable for instructions that target this group.
PRIORITY_CASE(SpvOpDecorationGroup)
PRIORITY_CASE(spv::Op::OpDecorationGroup)
#undef PRIORITY_CASE
}
@@ -86,25 +85,26 @@ struct DecorationLess {
} // namespace
bool AggressiveDCEPass::IsVarOfStorage(uint32_t varId, uint32_t storageClass) {
bool AggressiveDCEPass::IsVarOfStorage(uint32_t varId,
spv::StorageClass storageClass) {
if (varId == 0) return false;
const Instruction* varInst = get_def_use_mgr()->GetDef(varId);
const SpvOp op = varInst->opcode();
if (op != SpvOpVariable) return false;
const spv::Op op = varInst->opcode();
if (op != spv::Op::OpVariable) return false;
const uint32_t varTypeId = varInst->type_id();
const Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId);
if (varTypeInst->opcode() != SpvOpTypePointer) return false;
return varTypeInst->GetSingleWordInOperand(kTypePointerStorageClassInIdx) ==
storageClass;
if (varTypeInst->opcode() != spv::Op::OpTypePointer) return false;
return spv::StorageClass(varTypeInst->GetSingleWordInOperand(
kTypePointerStorageClassInIdx)) == storageClass;
}
bool AggressiveDCEPass::IsLocalVar(uint32_t varId, Function* func) {
if (IsVarOfStorage(varId, SpvStorageClassFunction)) {
if (IsVarOfStorage(varId, spv::StorageClass::Function)) {
return true;
}
if (!IsVarOfStorage(varId, SpvStorageClassPrivate) &&
!IsVarOfStorage(varId, SpvStorageClassWorkgroup)) {
if (!IsVarOfStorage(varId, spv::StorageClass::Private) &&
!IsVarOfStorage(varId, spv::StorageClass::Workgroup)) {
return false;
}
@@ -122,21 +122,21 @@ void AggressiveDCEPass::AddStores(Function* func, uint32_t ptrId) {
if (blk && blk->GetParent() != func) return;
switch (user->opcode()) {
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpCopyObject:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpCopyObject:
this->AddStores(func, user->result_id());
break;
case SpvOpLoad:
case spv::Op::OpLoad:
break;
case SpvOpCopyMemory:
case SpvOpCopyMemorySized:
case spv::Op::OpCopyMemory:
case spv::Op::OpCopyMemorySized:
if (user->GetSingleWordInOperand(kCopyMemoryTargetAddrInIdx) == ptrId) {
AddToWorklist(user);
}
break;
// If default, assume it stores e.g. frexp, modf, function call
case SpvOpStore:
case spv::Op::OpStore:
default:
AddToWorklist(user);
break;
@@ -154,7 +154,7 @@ bool AggressiveDCEPass::AllExtensionsSupported() const {
// Only allow NonSemantic.Shader.DebugInfo.100, we cannot safely optimise
// around unknown extended instruction sets even if they are non-semantic
for (auto& inst : context()->module()->ext_inst_imports()) {
assert(inst.opcode() == SpvOpExtInstImport &&
assert(inst.opcode() == spv::Op::OpExtInstImport &&
"Expecting an import of an extension's instruction set.");
const std::string extension_name = inst.GetInOperand(0).AsString();
if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
@@ -172,11 +172,11 @@ bool AggressiveDCEPass::IsTargetDead(Instruction* inst) {
// This must be a decoration group. We go through annotations in a specific
// order. So if this is not used by any group or group member decorates, it
// is dead.
assert(tInst->opcode() == SpvOpDecorationGroup);
assert(tInst->opcode() == spv::Op::OpDecorationGroup);
bool dead = true;
get_def_use_mgr()->ForEachUser(tInst, [&dead](Instruction* user) {
if (user->opcode() == SpvOpGroupDecorate ||
user->opcode() == SpvOpGroupMemberDecorate)
if (user->opcode() == spv::Op::OpGroupDecorate ||
user->opcode() == spv::Op::OpGroupMemberDecorate)
dead = false;
});
return dead;
@@ -197,7 +197,7 @@ void AggressiveDCEPass::ProcessLoad(Function* func, uint32_t varId) {
void AggressiveDCEPass::AddBranch(uint32_t labelId, BasicBlock* bp) {
std::unique_ptr<Instruction> newBranch(
new Instruction(context(), SpvOpBranch, 0, 0,
new Instruction(context(), spv::Op::OpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
context()->AnalyzeDefUse(&*newBranch);
context()->set_instr_block(&*newBranch, bp);
@@ -206,8 +206,8 @@ void AggressiveDCEPass::AddBranch(uint32_t labelId, BasicBlock* bp) {
void AggressiveDCEPass::AddBreaksAndContinuesToWorklist(
Instruction* mergeInst) {
assert(mergeInst->opcode() == SpvOpSelectionMerge ||
mergeInst->opcode() == SpvOpLoopMerge);
assert(mergeInst->opcode() == spv::Op::OpSelectionMerge ||
mergeInst->opcode() == spv::Op::OpLoopMerge);
BasicBlock* header = context()->get_instr_block(mergeInst);
const uint32_t mergeId = mergeInst->GetSingleWordInOperand(0);
@@ -223,7 +223,7 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist(
}
});
if (mergeInst->opcode() != SpvOpLoopMerge) {
if (mergeInst->opcode() != spv::Op::OpLoopMerge) {
return;
}
@@ -231,26 +231,27 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist(
const uint32_t contId =
mergeInst->GetSingleWordInOperand(kLoopMergeContinueBlockIdInIdx);
get_def_use_mgr()->ForEachUser(contId, [&contId, this](Instruction* user) {
SpvOp op = user->opcode();
if (op == SpvOpBranchConditional || op == SpvOpSwitch) {
spv::Op op = user->opcode();
if (op == spv::Op::OpBranchConditional || op == spv::Op::OpSwitch) {
// A conditional branch or switch can only be a continue if it does not
// have a merge instruction or its merge block is not the continue block.
Instruction* hdrMerge = GetMergeInstruction(user);
if (hdrMerge != nullptr && hdrMerge->opcode() == SpvOpSelectionMerge) {
if (hdrMerge != nullptr &&
hdrMerge->opcode() == spv::Op::OpSelectionMerge) {
uint32_t hdrMergeId =
hdrMerge->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx);
if (hdrMergeId == contId) return;
// Need to mark merge instruction too
AddToWorklist(hdrMerge);
}
} else if (op == SpvOpBranch) {
} else if (op == spv::Op::OpBranch) {
// An unconditional branch can only be a continue if it is not
// branching to its own merge block.
BasicBlock* blk = context()->get_instr_block(user);
Instruction* hdrBranch = GetHeaderBranch(blk);
if (hdrBranch == nullptr) return;
Instruction* hdrMerge = GetMergeInstruction(hdrBranch);
if (hdrMerge->opcode() == SpvOpLoopMerge) return;
if (hdrMerge->opcode() == spv::Op::OpLoopMerge) return;
uint32_t hdrMergeId =
hdrMerge->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx);
if (contId == hdrMergeId) return;
@@ -277,11 +278,11 @@ bool AggressiveDCEPass::KillDeadInstructions(
uint32_t merge_block_id = 0;
(*bi)->ForEachInst([this, &modified, &merge_block_id](Instruction* inst) {
if (IsLive(inst)) return;
if (inst->opcode() == SpvOpLabel) return;
if (inst->opcode() == spv::Op::OpLabel) return;
// If dead instruction is selection merge, remember merge block
// for new branch at end of block
if (inst->opcode() == SpvOpSelectionMerge ||
inst->opcode() == SpvOpLoopMerge)
if (inst->opcode() == spv::Op::OpSelectionMerge ||
inst->opcode() == spv::Op::OpLoopMerge)
merge_block_id = inst->GetSingleWordInOperand(0);
to_kill_.push_back(inst);
modified = true;
@@ -295,19 +296,19 @@ bool AggressiveDCEPass::KillDeadInstructions(
}
auto merge_terminator = (*bi)->terminator();
if (merge_terminator->opcode() == SpvOpUnreachable) {
if (merge_terminator->opcode() == spv::Op::OpUnreachable) {
// The merge was unreachable. This is undefined behaviour so just
// return (or return an undef). Then mark the new return as live.
auto func_ret_type_inst = get_def_use_mgr()->GetDef(func->type_id());
if (func_ret_type_inst->opcode() == SpvOpTypeVoid) {
merge_terminator->SetOpcode(SpvOpReturn);
if (func_ret_type_inst->opcode() == spv::Op::OpTypeVoid) {
merge_terminator->SetOpcode(spv::Op::OpReturn);
} else {
// Find an undef for the return value and make sure it gets kept by
// the pass.
auto undef_id = Type2Undef(func->type_id());
auto undef = get_def_use_mgr()->GetDef(undef_id);
live_insts_.Set(undef->unique_id());
merge_terminator->SetOpcode(SpvOpReturnValue);
merge_terminator->SetOpcode(spv::Op::OpReturnValue);
merge_terminator->SetInOperands({{SPV_OPERAND_TYPE_ID, {undef_id}}});
get_def_use_mgr()->AnalyzeInstUse(merge_terminator);
}
@@ -369,11 +370,11 @@ void AggressiveDCEPass::AddDecorationsToWorkList(const Instruction* inst) {
// We only care about OpDecorateId instructions because the are the only
// decorations that will reference an id that will have to be kept live
// because of that use.
if (dec->opcode() != SpvOpDecorateId) {
if (dec->opcode() != spv::Op::OpDecorateId) {
continue;
}
if (dec->GetSingleWordInOperand(1) ==
SpvDecorationHlslCounterBufferGOOGLE) {
if (spv::Decoration(dec->GetSingleWordInOperand(1)) ==
spv::Decoration::HlslCounterBufferGOOGLE) {
// These decorations should not force the use id to be live. It will be
// removed if either the target or the in operand are dead.
continue;
@@ -391,7 +392,7 @@ void AggressiveDCEPass::MarkLoadedVariablesAsLive(Function* func,
}
std::vector<uint32_t> AggressiveDCEPass::GetLoadedVariables(Instruction* inst) {
if (inst->opcode() == SpvOpFunctionCall) {
if (inst->opcode() == spv::Op::OpFunctionCall) {
return GetLoadedVariablesFromFunctionCall(inst);
}
uint32_t var_id = GetLoadedVariableFromNonFunctionCalls(inst);
@@ -409,11 +410,11 @@ uint32_t AggressiveDCEPass::GetLoadedVariableFromNonFunctionCalls(
}
switch (inst->opcode()) {
case SpvOpLoad:
case SpvOpImageTexelPointer:
case spv::Op::OpLoad:
case spv::Op::OpImageTexelPointer:
return GetVariableId(inst->GetSingleWordInOperand(kLoadSourceAddrInIdx));
case SpvOpCopyMemory:
case SpvOpCopyMemorySized:
case spv::Op::OpCopyMemory:
case spv::Op::OpCopyMemorySized:
return GetVariableId(
inst->GetSingleWordInOperand(kCopyMemorySourceAddrInIdx));
default:
@@ -436,7 +437,7 @@ uint32_t AggressiveDCEPass::GetLoadedVariableFromNonFunctionCalls(
std::vector<uint32_t> AggressiveDCEPass::GetLoadedVariablesFromFunctionCall(
const Instruction* inst) {
assert(inst->opcode() == SpvOpFunctionCall);
assert(inst->opcode() == spv::Op::OpFunctionCall);
std::vector<uint32_t> live_variables;
inst->ForEachInId([this, &live_variables](const uint32_t* operand_id) {
if (!IsPtr(*operand_id)) return;
@@ -481,7 +482,7 @@ void AggressiveDCEPass::MarkBlockAsLive(Instruction* inst) {
// the loop, so the loop construct must be live. We exclude the label because
// it does not matter how many times it is executed. This could be extended
// to more instructions, but we will need it for now.
if (inst->opcode() != SpvOpLabel)
if (inst->opcode() != spv::Op::OpLabel)
MarkLoopConstructAsLiveIfLoopHeader(basic_block);
Instruction* next_branch_inst = GetBranchForNextHeader(basic_block);
@@ -491,8 +492,8 @@ void AggressiveDCEPass::MarkBlockAsLive(Instruction* inst) {
AddToWorklist(mergeInst);
}
if (inst->opcode() == SpvOpLoopMerge ||
inst->opcode() == SpvOpSelectionMerge) {
if (inst->opcode() == spv::Op::OpLoopMerge ||
inst->opcode() == spv::Op::OpSelectionMerge) {
AddBreaksAndContinuesToWorklist(inst);
}
}
@@ -529,27 +530,27 @@ void AggressiveDCEPass::InitializeWorkList(
// cleaned up.
for (auto& bi : structured_order) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
SpvOp op = ii->opcode();
spv::Op op = ii->opcode();
if (ii->IsBranch()) {
continue;
}
switch (op) {
case SpvOpStore: {
case spv::Op::OpStore: {
uint32_t var_id = 0;
(void)GetPtr(&*ii, &var_id);
if (!IsLocalVar(var_id, func)) AddToWorklist(&*ii);
} break;
case SpvOpCopyMemory:
case SpvOpCopyMemorySized: {
case spv::Op::OpCopyMemory:
case spv::Op::OpCopyMemorySized: {
uint32_t var_id = 0;
uint32_t target_addr_id =
ii->GetSingleWordInOperand(kCopyMemoryTargetAddrInIdx);
(void)GetPtr(target_addr_id, &var_id);
if (!IsLocalVar(var_id, func)) AddToWorklist(&*ii);
} break;
case SpvOpLoopMerge:
case SpvOpSelectionMerge:
case SpvOpUnreachable:
case spv::Op::OpLoopMerge:
case spv::Op::OpSelectionMerge:
case spv::Op::OpUnreachable:
break;
default: {
// Function calls, atomics, function params, function returns, etc.
@@ -578,8 +579,10 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() {
auto* var = get_def_use_mgr()->GetDef(entry.GetSingleWordInOperand(i));
auto storage_class = var->GetSingleWordInOperand(0u);
// Vulkan support outputs without an associated input, but not inputs
// without an associated output.
if (storage_class == SpvStorageClassOutput) {
// without an associated output. Don't remove outputs unless explicitly
// allowed.
if (!remove_outputs_ &&
spv::StorageClass(storage_class) == spv::StorageClass::Output) {
AddToWorklist(var);
}
}
@@ -588,24 +591,29 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() {
}
}
for (auto& anno : get_module()->annotations()) {
if (anno.opcode() == SpvOpDecorate) {
if (anno.opcode() == spv::Op::OpDecorate) {
// Keep workgroup size.
if (anno.GetSingleWordInOperand(1u) == SpvDecorationBuiltIn &&
anno.GetSingleWordInOperand(2u) == SpvBuiltInWorkgroupSize) {
if (spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
spv::Decoration::BuiltIn &&
spv::BuiltIn(anno.GetSingleWordInOperand(2u)) ==
spv::BuiltIn::WorkgroupSize) {
AddToWorklist(&anno);
}
if (context()->preserve_bindings()) {
// Keep all bindings.
if ((anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet) ||
(anno.GetSingleWordInOperand(1u) == SpvDecorationBinding)) {
if ((spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
spv::Decoration::DescriptorSet) ||
(spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
spv::Decoration::Binding)) {
AddToWorklist(&anno);
}
}
if (context()->preserve_spec_constants()) {
// Keep all specialization constant instructions
if (anno.GetSingleWordInOperand(1u) == SpvDecorationSpecId) {
if (spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
spv::Decoration::SpecId) {
AddToWorklist(&anno);
}
}
@@ -624,7 +632,7 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() {
debug_global_seen = true;
dbg.ForEachInId([this](const uint32_t* iid) {
Instruction* in_inst = get_def_use_mgr()->GetDef(*iid);
if (in_inst->opcode() == SpvOpVariable) return;
if (in_inst->opcode() == spv::Op::OpVariable) return;
AddToWorklist(in_inst);
});
}
@@ -647,19 +655,19 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() {
Pass::Status AggressiveDCEPass::ProcessImpl() {
// Current functionality assumes shader capability
// TODO(greg-lunarg): Handle additional capabilities
if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
return Status::SuccessWithoutChange;
// Current functionality assumes relaxed logical addressing (see
// instruction.h)
// TODO(greg-lunarg): Handle non-logical addressing
if (context()->get_feature_mgr()->HasCapability(SpvCapabilityAddresses))
if (context()->get_feature_mgr()->HasCapability(spv::Capability::Addresses))
return Status::SuccessWithoutChange;
// The variable pointer extension is no longer needed to use the capability,
// so we have to look for the capability.
if (context()->get_feature_mgr()->HasCapability(
SpvCapabilityVariablePointersStorageBuffer))
spv::Capability::VariablePointersStorageBuffer))
return Status::SuccessWithoutChange;
// If any extensions in the module are not explicitly supported,
@@ -743,7 +751,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
bool modified = false;
Instruction* instruction = &*get_module()->debug2_begin();
while (instruction) {
if (instruction->opcode() != SpvOpName) {
if (instruction->opcode() != spv::Op::OpName) {
instruction = instruction->NextNode();
continue;
}
@@ -764,22 +772,22 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
std::sort(annotations.begin(), annotations.end(), DecorationLess());
for (auto annotation : annotations) {
switch (annotation->opcode()) {
case SpvOpDecorate:
case SpvOpMemberDecorate:
case SpvOpDecorateStringGOOGLE:
case SpvOpMemberDecorateStringGOOGLE:
case spv::Op::OpDecorate:
case spv::Op::OpMemberDecorate:
case spv::Op::OpDecorateStringGOOGLE:
case spv::Op::OpMemberDecorateStringGOOGLE:
if (IsTargetDead(annotation)) {
context()->KillInst(annotation);
modified = true;
}
break;
case SpvOpDecorateId:
case spv::Op::OpDecorateId:
if (IsTargetDead(annotation)) {
context()->KillInst(annotation);
modified = true;
} else {
if (annotation->GetSingleWordInOperand(1) ==
SpvDecorationHlslCounterBufferGOOGLE) {
if (spv::Decoration(annotation->GetSingleWordInOperand(1)) ==
spv::Decoration::HlslCounterBufferGOOGLE) {
// HlslCounterBuffer will reference an id other than the target.
// If that id is dead, then the decoration can be removed as well.
uint32_t counter_buffer_id = annotation->GetSingleWordInOperand(2);
@@ -792,7 +800,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
}
}
break;
case SpvOpGroupDecorate: {
case spv::Op::OpGroupDecorate: {
// Go through the targets of this group decorate. Remove each dead
// target. If all targets are dead, remove this decoration.
bool dead = true;
@@ -818,7 +826,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
}
break;
}
case SpvOpGroupMemberDecorate: {
case spv::Op::OpGroupMemberDecorate: {
// Go through the targets of this group member decorate. Remove each
// dead target (and member index). If all targets are dead, remove this
// decoration.
@@ -846,7 +854,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
}
break;
}
case SpvOpDecorationGroup:
case spv::Op::OpDecorationGroup:
// By the time we hit decoration groups we've checked everything that
// can target them. So if they have no uses they must be dead.
if (get_def_use_mgr()->NumUsers(annotation) == 0) {
@@ -887,7 +895,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
// this live as it does not have a result id. This is a little too
// conservative since it is not known if the structure type that needed
// it is still live. TODO(greg-lunarg): Only save if needed.
if (val.opcode() == SpvOpTypeForwardPointer) {
if (val.opcode() == spv::Op::OpTypeForwardPointer) {
uint32_t ptr_ty_id = val.GetSingleWordInOperand(0);
Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id);
if (IsLive(ptr_ty_inst)) continue;
@@ -1083,8 +1091,9 @@ bool AggressiveDCEPass::IsEntryPoint(Function* func) {
}
bool AggressiveDCEPass::HasCall(Function* func) {
return !func->WhileEachInst(
[](Instruction* inst) { return inst->opcode() != SpvOpFunctionCall; });
return !func->WhileEachInst([](Instruction* inst) {
return inst->opcode() != spv::Op::OpFunctionCall;
});
}
void AggressiveDCEPass::MarkFirstBlockAsLive(Function* func) {

View File

@@ -44,8 +44,10 @@ class AggressiveDCEPass : public MemPass {
using GetBlocksFunction =
std::function<std::vector<BasicBlock*>*(const BasicBlock*)>;
AggressiveDCEPass(bool preserve_interface = false)
: preserve_interface_(preserve_interface) {}
AggressiveDCEPass(bool preserve_interface = false,
bool remove_outputs = false)
: preserve_interface_(preserve_interface),
remove_outputs_(remove_outputs) {}
const char* name() const override { return "eliminate-dead-code-aggressive"; }
Status Process() override;
@@ -63,9 +65,14 @@ class AggressiveDCEPass : public MemPass {
// is not allowed.
bool preserve_interface_;
// Output variables can be removed from the interface if this is true.
// This is safe if the caller knows that the corresponding input variable
// in the following shader has been removed. It is false by default.
bool remove_outputs_;
// Return true if |varId| is a variable of |storageClass|. |varId| must either
// be 0 or the result of an instruction.
bool IsVarOfStorage(uint32_t varId, uint32_t storageClass);
bool IsVarOfStorage(uint32_t varId, spv::StorageClass storageClass);
// Return true if the instance of the variable |varId| can only be access in
// |func|. For example, a function scope variable, or a private variable

View File

@@ -24,7 +24,6 @@
namespace spvtools {
namespace opt {
namespace {
enum AmdShaderBallotExtOpcodes {
@@ -136,19 +135,19 @@ bool ReplaceTrinaryMid(IRContext* ctx, Instruction* inst,
// Returns a folding rule that will replace the opcode with |opcode| and add
// the capabilities required. The folding rule assumes it is folding an
// OpGroup*NonUniformAMD instruction from the SPV_AMD_shader_ballot extension.
template <SpvOp new_opcode>
template <spv::Op new_opcode>
bool ReplaceGroupNonuniformOperationOpCode(
IRContext* ctx, Instruction* inst,
const std::vector<const analysis::Constant*>&) {
switch (new_opcode) {
case SpvOpGroupNonUniformIAdd:
case SpvOpGroupNonUniformFAdd:
case SpvOpGroupNonUniformUMin:
case SpvOpGroupNonUniformSMin:
case SpvOpGroupNonUniformFMin:
case SpvOpGroupNonUniformUMax:
case SpvOpGroupNonUniformSMax:
case SpvOpGroupNonUniformFMax:
case spv::Op::OpGroupNonUniformIAdd:
case spv::Op::OpGroupNonUniformFAdd:
case spv::Op::OpGroupNonUniformUMin:
case spv::Op::OpGroupNonUniformSMin:
case spv::Op::OpGroupNonUniformFMin:
case spv::Op::OpGroupNonUniformUMax:
case spv::Op::OpGroupNonUniformSMax:
case spv::Op::OpGroupNonUniformFMax:
break;
default:
assert(
@@ -157,21 +156,21 @@ bool ReplaceGroupNonuniformOperationOpCode(
}
switch (inst->opcode()) {
case SpvOpGroupIAddNonUniformAMD:
case SpvOpGroupFAddNonUniformAMD:
case SpvOpGroupUMinNonUniformAMD:
case SpvOpGroupSMinNonUniformAMD:
case SpvOpGroupFMinNonUniformAMD:
case SpvOpGroupUMaxNonUniformAMD:
case SpvOpGroupSMaxNonUniformAMD:
case SpvOpGroupFMaxNonUniformAMD:
case spv::Op::OpGroupIAddNonUniformAMD:
case spv::Op::OpGroupFAddNonUniformAMD:
case spv::Op::OpGroupUMinNonUniformAMD:
case spv::Op::OpGroupSMinNonUniformAMD:
case spv::Op::OpGroupFMinNonUniformAMD:
case spv::Op::OpGroupUMaxNonUniformAMD:
case spv::Op::OpGroupSMaxNonUniformAMD:
case spv::Op::OpGroupFMaxNonUniformAMD:
break;
default:
assert(false &&
"Should be replacing a group non uniform arithmetic operation.");
}
ctx->AddCapability(SpvCapabilityGroupNonUniformArithmetic);
ctx->AddCapability(spv::Capability::GroupNonUniformArithmetic);
inst->SetOpcode(new_opcode);
return true;
}
@@ -215,8 +214,8 @@ bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst,
analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
ctx->AddExtension("SPV_KHR_shader_ballot");
ctx->AddCapability(SpvCapabilityGroupNonUniformBallot);
ctx->AddCapability(SpvCapabilityGroupNonUniformShuffle);
ctx->AddCapability(spv::Capability::GroupNonUniformBallot);
ctx->AddCapability(spv::Capability::GroupNonUniformShuffle);
InstructionBuilder ir_builder(
ctx, inst,
@@ -226,8 +225,8 @@ bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst,
uint32_t offset_id = inst->GetSingleWordInOperand(3);
// Get the subgroup invocation id.
uint32_t var_id =
ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
uint32_t var_id = ctx->GetBuiltinInputVarId(
uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
Instruction* var_ptr_type =
@@ -239,35 +238,38 @@ bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst,
uint32_t quad_mask = ir_builder.GetUintConstantId(3);
// This gives the offset in the group of 4 of this invocation.
Instruction* quad_idx = ir_builder.AddBinaryOp(uint_type_id, SpvOpBitwiseAnd,
id->result_id(), quad_mask);
Instruction* quad_idx = ir_builder.AddBinaryOp(
uint_type_id, spv::Op::OpBitwiseAnd, id->result_id(), quad_mask);
// Get the invocation id of the first invocation in the group of 4.
Instruction* quad_ldr = ir_builder.AddBinaryOp(
uint_type_id, SpvOpBitwiseXor, id->result_id(), quad_idx->result_id());
Instruction* quad_ldr =
ir_builder.AddBinaryOp(uint_type_id, spv::Op::OpBitwiseXor,
id->result_id(), quad_idx->result_id());
// Get the offset of the target invocation from the offset vector.
Instruction* my_offset =
ir_builder.AddBinaryOp(uint_type_id, SpvOpVectorExtractDynamic, offset_id,
quad_idx->result_id());
ir_builder.AddBinaryOp(uint_type_id, spv::Op::OpVectorExtractDynamic,
offset_id, quad_idx->result_id());
// Determine the index of the invocation to read from.
Instruction* target_inv = ir_builder.AddBinaryOp(
uint_type_id, SpvOpIAdd, quad_ldr->result_id(), my_offset->result_id());
Instruction* target_inv =
ir_builder.AddBinaryOp(uint_type_id, spv::Op::OpIAdd,
quad_ldr->result_id(), my_offset->result_id());
// Do the group operations
uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
uint32_t subgroup_scope = ir_builder.GetUintConstantId(SpvScopeSubgroup);
uint32_t subgroup_scope =
ir_builder.GetUintConstantId(uint32_t(spv::Scope::Subgroup));
const auto* ballot_value_const = const_mgr->GetConstant(
type_mgr->GetUIntVectorType(4),
{uint_max_id, uint_max_id, uint_max_id, uint_max_id});
Instruction* ballot_value =
const_mgr->GetDefiningInstruction(ballot_value_const);
Instruction* is_active = ir_builder.AddNaryOp(
type_mgr->GetBoolTypeId(), SpvOpGroupNonUniformBallotBitExtract,
type_mgr->GetBoolTypeId(), spv::Op::OpGroupNonUniformBallotBitExtract,
{subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
Instruction* shuffle =
ir_builder.AddNaryOp(inst->type_id(), SpvOpGroupNonUniformShuffle,
ir_builder.AddNaryOp(inst->type_id(), spv::Op::OpGroupNonUniformShuffle,
{subgroup_scope, data_id, target_inv->result_id()});
// Create the null constant to use in the select.
@@ -276,7 +278,7 @@ bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst,
Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
// Build the select.
inst->SetOpcode(SpvOpSelect);
inst->SetOpcode(spv::Op::OpSelect);
Instruction::OperandList new_operands;
new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}});
new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}});
@@ -327,8 +329,8 @@ bool ReplaceSwizzleInvocationsMasked(
analysis::DefUseManager* def_use_mgr = ctx->get_def_use_mgr();
analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
ctx->AddCapability(SpvCapabilityGroupNonUniformBallot);
ctx->AddCapability(SpvCapabilityGroupNonUniformShuffle);
ctx->AddCapability(spv::Capability::GroupNonUniformBallot);
ctx->AddCapability(spv::Capability::GroupNonUniformShuffle);
InstructionBuilder ir_builder(
ctx, inst,
@@ -338,7 +340,7 @@ bool ReplaceSwizzleInvocationsMasked(
uint32_t data_id = inst->GetSingleWordInOperand(2);
Instruction* mask_inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(3));
assert(mask_inst->opcode() == SpvOpConstantComposite &&
assert(mask_inst->opcode() == spv::Op::OpConstantComposite &&
"The mask is suppose to be a vector constant.");
assert(mask_inst->NumInOperands() == 3 &&
"The mask is suppose to have 3 components.");
@@ -348,8 +350,8 @@ bool ReplaceSwizzleInvocationsMasked(
uint32_t uint_z = mask_inst->GetSingleWordInOperand(2);
// Get the subgroup invocation id.
uint32_t var_id =
ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
uint32_t var_id = ctx->GetBuiltinInputVarId(
uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
ctx->AddExtension("SPV_KHR_shader_ballot");
assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
@@ -361,28 +363,30 @@ bool ReplaceSwizzleInvocationsMasked(
// Do the bitwise operations.
uint32_t mask_extended = ir_builder.GetUintConstantId(0xFFFFFFE0);
Instruction* and_mask = ir_builder.AddBinaryOp(uint_type_id, SpvOpBitwiseOr,
uint_x, mask_extended);
Instruction* and_result = ir_builder.AddBinaryOp(
uint_type_id, SpvOpBitwiseAnd, id->result_id(), and_mask->result_id());
Instruction* and_mask = ir_builder.AddBinaryOp(
uint_type_id, spv::Op::OpBitwiseOr, uint_x, mask_extended);
Instruction* and_result =
ir_builder.AddBinaryOp(uint_type_id, spv::Op::OpBitwiseAnd,
id->result_id(), and_mask->result_id());
Instruction* or_result = ir_builder.AddBinaryOp(
uint_type_id, SpvOpBitwiseOr, and_result->result_id(), uint_y);
uint_type_id, spv::Op::OpBitwiseOr, and_result->result_id(), uint_y);
Instruction* target_inv = ir_builder.AddBinaryOp(
uint_type_id, SpvOpBitwiseXor, or_result->result_id(), uint_z);
uint_type_id, spv::Op::OpBitwiseXor, or_result->result_id(), uint_z);
// Do the group operations
uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
uint32_t subgroup_scope = ir_builder.GetUintConstantId(SpvScopeSubgroup);
uint32_t subgroup_scope =
ir_builder.GetUintConstantId(uint32_t(spv::Scope::Subgroup));
const auto* ballot_value_const = const_mgr->GetConstant(
type_mgr->GetUIntVectorType(4),
{uint_max_id, uint_max_id, uint_max_id, uint_max_id});
Instruction* ballot_value =
const_mgr->GetDefiningInstruction(ballot_value_const);
Instruction* is_active = ir_builder.AddNaryOp(
type_mgr->GetBoolTypeId(), SpvOpGroupNonUniformBallotBitExtract,
type_mgr->GetBoolTypeId(), spv::Op::OpGroupNonUniformBallotBitExtract,
{subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
Instruction* shuffle =
ir_builder.AddNaryOp(inst->type_id(), SpvOpGroupNonUniformShuffle,
ir_builder.AddNaryOp(inst->type_id(), spv::Op::OpGroupNonUniformShuffle,
{subgroup_scope, data_id, target_inv->result_id()});
// Create the null constant to use in the select.
@@ -391,7 +395,7 @@ bool ReplaceSwizzleInvocationsMasked(
Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
// Build the select.
inst->SetOpcode(SpvOpSelect);
inst->SetOpcode(spv::Op::OpSelect);
Instruction::OperandList new_operands;
new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}});
new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}});
@@ -420,9 +424,9 @@ bool ReplaceSwizzleInvocationsMasked(
// Also adding the capabilities and builtins that are needed.
bool ReplaceWriteInvocation(IRContext* ctx, Instruction* inst,
const std::vector<const analysis::Constant*>&) {
uint32_t var_id =
ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId);
ctx->AddCapability(SpvCapabilitySubgroupBallotKHR);
uint32_t var_id = ctx->GetBuiltinInputVarId(
uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
ctx->AddCapability(spv::Capability::SubgroupBallotKHR);
ctx->AddExtension("SPV_KHR_shader_ballot");
assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
@@ -437,11 +441,11 @@ bool ReplaceWriteInvocation(IRContext* ctx, Instruction* inst,
analysis::Bool bool_type;
uint32_t bool_type_id = ctx->get_type_mgr()->GetTypeInstruction(&bool_type);
Instruction* cmp =
ir_builder.AddBinaryOp(bool_type_id, SpvOpIEqual, t->result_id(),
ir_builder.AddBinaryOp(bool_type_id, spv::Op::OpIEqual, t->result_id(),
inst->GetSingleWordInOperand(4));
// Build a select.
inst->SetOpcode(SpvOpSelect);
inst->SetOpcode(spv::Op::OpSelect);
Instruction::OperandList new_operands;
new_operands.push_back({SPV_OPERAND_TYPE_ID, {cmp->result_id()}});
new_operands.push_back(inst->GetInOperand(3));
@@ -479,14 +483,15 @@ bool ReplaceMbcnt(IRContext* context, Instruction* inst,
analysis::TypeManager* type_mgr = context->get_type_mgr();
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
uint32_t var_id = context->GetBuiltinInputVarId(SpvBuiltInSubgroupLtMask);
uint32_t var_id =
context->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::SubgroupLtMask));
assert(var_id != 0 && "Could not get SubgroupLtMask variable.");
context->AddCapability(SpvCapabilityGroupNonUniformBallot);
context->AddCapability(spv::Capability::GroupNonUniformBallot);
Instruction* var_inst = def_use_mgr->GetDef(var_id);
Instruction* var_ptr_type = def_use_mgr->GetDef(var_inst->type_id());
Instruction* var_type =
def_use_mgr->GetDef(var_ptr_type->GetSingleWordInOperand(1));
assert(var_type->opcode() == SpvOpTypeVector &&
assert(var_type->opcode() == spv::Op::OpTypeVector &&
"Variable is suppose to be a vector of 4 ints");
// Get the type for the shuffle.
@@ -509,11 +514,12 @@ bool ReplaceMbcnt(IRContext* context, Instruction* inst,
Instruction* shuffle = ir_builder.AddVectorShuffle(
shuffle_type_id, load->result_id(), load->result_id(), {0, 1});
Instruction* bitcast = ir_builder.AddUnaryOp(
mask_inst->type_id(), SpvOpBitcast, shuffle->result_id());
Instruction* t = ir_builder.AddBinaryOp(mask_inst->type_id(), SpvOpBitwiseAnd,
bitcast->result_id(), mask_id);
mask_inst->type_id(), spv::Op::OpBitcast, shuffle->result_id());
Instruction* t =
ir_builder.AddBinaryOp(mask_inst->type_id(), spv::Op::OpBitwiseAnd,
bitcast->result_id(), mask_id);
inst->SetOpcode(SpvOpBitCount);
inst->SetOpcode(spv::Op::OpBitCount);
inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {t->result_id()}}});
context->UpdateDefUse(inst);
return true;
@@ -599,11 +605,11 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
// Negate the input values.
Instruction* nx =
ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, x->result_id());
ir_builder.AddUnaryOp(float_type_id, spv::Op::OpFNegate, x->result_id());
Instruction* ny =
ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, y->result_id());
ir_builder.AddUnaryOp(float_type_id, spv::Op::OpFNegate, y->result_id());
Instruction* nz =
ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, z->result_id());
ir_builder.AddUnaryOp(float_type_id, spv::Op::OpFNegate, z->result_id());
// Get the abolsute values of the inputs.
Instruction* ax = ir_builder.AddNaryExtendedInstruction(
@@ -614,12 +620,12 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()});
// Find which values are negative. Used in later computations.
Instruction* is_z_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
z->result_id(), f0_const_id);
Instruction* is_y_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
y->result_id(), f0_const_id);
Instruction* is_x_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
x->result_id(), f0_const_id);
Instruction* is_z_neg = ir_builder.AddBinaryOp(
bool_id, spv::Op::OpFOrdLessThan, z->result_id(), f0_const_id);
Instruction* is_y_neg = ir_builder.AddBinaryOp(
bool_id, spv::Op::OpFOrdLessThan, y->result_id(), f0_const_id);
Instruction* is_x_neg = ir_builder.AddBinaryOp(
bool_id, spv::Op::OpFOrdLessThan, x->result_id(), f0_const_id);
// Compute cubema
Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction(
@@ -628,19 +634,21 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
Instruction* amax = ir_builder.AddNaryExtendedInstruction(
float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
{az->result_id(), amax_x_y->result_id()});
Instruction* cubema = ir_builder.AddBinaryOp(float_type_id, SpvOpFMul,
Instruction* cubema = ir_builder.AddBinaryOp(float_type_id, spv::Op::OpFMul,
f2_const_id, amax->result_id());
// Do the comparisons needed for computing cubesc and cubetc.
Instruction* is_z_max =
ir_builder.AddBinaryOp(bool_id, SpvOpFOrdGreaterThanEqual,
ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
az->result_id(), amax_x_y->result_id());
Instruction* not_is_z_max =
ir_builder.AddUnaryOp(bool_id, SpvOpLogicalNot, is_z_max->result_id());
Instruction* y_gr_x = ir_builder.AddBinaryOp(
bool_id, SpvOpFOrdGreaterThanEqual, ay->result_id(), ax->result_id());
Instruction* is_y_max = ir_builder.AddBinaryOp(
bool_id, SpvOpLogicalAnd, not_is_z_max->result_id(), y_gr_x->result_id());
Instruction* not_is_z_max = ir_builder.AddUnaryOp(
bool_id, spv::Op::OpLogicalNot, is_z_max->result_id());
Instruction* y_gr_x =
ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
ay->result_id(), ax->result_id());
Instruction* is_y_max =
ir_builder.AddBinaryOp(bool_id, spv::Op::OpLogicalAnd,
not_is_z_max->result_id(), y_gr_x->result_id());
// Select the correct value for cubesc.
Instruction* cubesc_case_1 = ir_builder.AddSelect(
@@ -667,10 +675,10 @@ bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
Instruction* denom = ir_builder.AddCompositeConstruct(
v2_float_type_id, {cubema->result_id(), cubema->result_id()});
Instruction* div = ir_builder.AddBinaryOp(
v2_float_type_id, SpvOpFDiv, cube->result_id(), denom->result_id());
v2_float_type_id, spv::Op::OpFDiv, cube->result_id(), denom->result_id());
// Get the final result by adding 0.5 to |div|.
inst->SetOpcode(SpvOpFAdd);
inst->SetOpcode(spv::Op::OpFAdd);
Instruction::OperandList new_operands;
new_operands.push_back({SPV_OPERAND_TYPE_ID, {div->result_id()}});
new_operands.push_back({SPV_OPERAND_TYPE_ID, {vec_const_id}});
@@ -752,22 +760,23 @@ bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst,
float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()});
// Find which values are negative. Used in later computations.
Instruction* is_z_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
z->result_id(), f0_const_id);
Instruction* is_y_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
y->result_id(), f0_const_id);
Instruction* is_x_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan,
x->result_id(), f0_const_id);
Instruction* is_z_neg = ir_builder.AddBinaryOp(
bool_id, spv::Op::OpFOrdLessThan, z->result_id(), f0_const_id);
Instruction* is_y_neg = ir_builder.AddBinaryOp(
bool_id, spv::Op::OpFOrdLessThan, y->result_id(), f0_const_id);
Instruction* is_x_neg = ir_builder.AddBinaryOp(
bool_id, spv::Op::OpFOrdLessThan, x->result_id(), f0_const_id);
// Find the max value.
Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction(
float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
{ax->result_id(), ay->result_id()});
Instruction* is_z_max =
ir_builder.AddBinaryOp(bool_id, SpvOpFOrdGreaterThanEqual,
ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
az->result_id(), amax_x_y->result_id());
Instruction* y_gr_x = ir_builder.AddBinaryOp(
bool_id, SpvOpFOrdGreaterThanEqual, ay->result_id(), ax->result_id());
Instruction* y_gr_x =
ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
ay->result_id(), ax->result_id());
// Get the value for each case.
Instruction* case_z = ir_builder.AddSelect(
@@ -783,7 +792,7 @@ bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst,
case_y->result_id(), case_x->result_id());
// Get the final result by adding 0.5 to |div|.
inst->SetOpcode(SpvOpSelect);
inst->SetOpcode(spv::Op::OpSelect);
Instruction::OperandList new_operands;
new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_z_max->result_id()}});
new_operands.push_back({SPV_OPERAND_TYPE_ID, {case_z->result_id()}});
@@ -813,11 +822,12 @@ bool ReplaceTimeAMD(IRContext* ctx, Instruction* inst,
ctx, inst,
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
ctx->AddExtension("SPV_KHR_shader_clock");
ctx->AddCapability(SpvCapabilityShaderClockKHR);
ctx->AddCapability(spv::Capability::ShaderClockKHR);
inst->SetOpcode(SpvOpReadClockKHR);
inst->SetOpcode(spv::Op::OpReadClockKHR);
Instruction::OperandList args;
uint32_t subgroup_scope_id = ir_builder.GetUintConstantId(SpvScopeSubgroup);
uint32_t subgroup_scope_id =
ir_builder.GetUintConstantId(uint32_t(spv::Scope::Subgroup));
args.push_back({SPV_OPERAND_TYPE_ID, {subgroup_scope_id}});
inst->SetInOperands(std::move(args));
ctx->UpdateDefUse(inst);
@@ -831,22 +841,22 @@ class AmdExtFoldingRules : public FoldingRules {
protected:
virtual void AddFoldingRules() override {
rules_[SpvOpGroupIAddNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformIAdd>);
rules_[SpvOpGroupFAddNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformFAdd>);
rules_[SpvOpGroupUMinNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformUMin>);
rules_[SpvOpGroupSMinNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformSMin>);
rules_[SpvOpGroupFMinNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformFMin>);
rules_[SpvOpGroupUMaxNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformUMax>);
rules_[SpvOpGroupSMaxNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformSMax>);
rules_[SpvOpGroupFMaxNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<SpvOpGroupNonUniformFMax>);
rules_[spv::Op::OpGroupIAddNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformIAdd>);
rules_[spv::Op::OpGroupFAddNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformFAdd>);
rules_[spv::Op::OpGroupUMinNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformUMin>);
rules_[spv::Op::OpGroupSMinNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformSMin>);
rules_[spv::Op::OpGroupFMinNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformFMin>);
rules_[spv::Op::OpGroupUMaxNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformUMax>);
rules_[spv::Op::OpGroupSMaxNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformSMax>);
rules_[spv::Op::OpGroupFMaxNonUniformAMD].push_back(
ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformFMax>);
uint32_t extension_id =
context()->module()->GetExtInstImportId("SPV_AMD_shader_ballot");
@@ -934,7 +944,7 @@ Pass::Status AmdExtensionToKhrPass::Process() {
std::vector<Instruction*> to_be_killed;
for (Instruction& inst : context()->module()->extensions()) {
if (inst.opcode() == SpvOpExtension) {
if (inst.opcode() == spv::Op::OpExtension) {
if (ext_to_remove.count(inst.GetInOperand(0).AsString()) != 0) {
to_be_killed.push_back(&inst);
}
@@ -942,7 +952,7 @@ Pass::Status AmdExtensionToKhrPass::Process() {
}
for (Instruction& inst : context()->ext_inst_imports()) {
if (inst.opcode() == SpvOpExtInstImport) {
if (inst.opcode() == spv::Op::OpExtInstImport) {
if (ext_to_remove.count(inst.GetInOperand(0).AsString()) != 0) {
to_be_killed.push_back(&inst);
}

View File

@@ -0,0 +1,45 @@
// Copyright (c) 2022 The Khronos Group Inc.
// Copyright (c) 2022 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/opt/analyze_live_input_pass.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace opt {
Pass::Status AnalyzeLiveInputPass::Process() {
// Current functionality assumes shader capability
if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
return Status::SuccessWithoutChange;
Pass::Status status = DoLiveInputAnalysis();
return status;
}
Pass::Status AnalyzeLiveInputPass::DoLiveInputAnalysis() {
// Current functionality only supports frag, tesc, tese or geom shaders.
// Report failure for any other stage.
auto stage = context()->GetStage();
if (stage != spv::ExecutionModel::Fragment &&
stage != spv::ExecutionModel::TessellationControl &&
stage != spv::ExecutionModel::TessellationEvaluation &&
stage != spv::ExecutionModel::Geometry)
return Status::Failure;
context()->get_liveness_mgr()->GetLiveness(live_locs_, live_builtins_);
return Status::SuccessWithoutChange;
}
} // namespace opt
} // namespace spvtools

View File

@@ -0,0 +1,57 @@
// Copyright (c) 2022 The Khronos Group Inc.
// Copyright (c) 2022 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_OPT_ANALYZE_LIVE_INPUT_H_
#define SOURCE_OPT_ANALYZE_LIVE_INPUT_H_
#include <unordered_set>
#include "source/opt/pass.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class AnalyzeLiveInputPass : public Pass {
public:
explicit AnalyzeLiveInputPass(std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins)
: live_locs_(live_locs), live_builtins_(live_builtins) {}
const char* name() const override { return "analyze-live-input"; }
Status Process() override;
// Return the mask of preserved Analyses.
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse |
IRContext::kAnalysisInstrToBlockMapping |
IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG |
IRContext::kAnalysisDominatorAnalysis |
IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
}
private:
// Do live input analysis
Status DoLiveInputAnalysis();
std::unordered_set<uint32_t>* live_locs_;
std::unordered_set<uint32_t>* live_builtins_;
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_ANALYZE_LIVE_INPUT_H_

View File

@@ -25,11 +25,9 @@
namespace spvtools {
namespace opt {
namespace {
const uint32_t kLoopMergeContinueBlockIdInIdx = 1;
const uint32_t kLoopMergeMergeBlockIdInIdx = 0;
const uint32_t kSelectionMergeMergeBlockIdInIdx = 0;
constexpr uint32_t kLoopMergeContinueBlockIdInIdx = 1;
constexpr uint32_t kLoopMergeMergeBlockIdInIdx = 0;
constexpr uint32_t kSelectionMergeMergeBlockIdInIdx = 0;
} // namespace
BasicBlock* BasicBlock::Clone(IRContext* context) const {
@@ -58,7 +56,7 @@ const Instruction* BasicBlock::GetMergeInst() const {
if (iter != cbegin()) {
--iter;
const auto opcode = iter->opcode();
if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) {
if (opcode == spv::Op::OpLoopMerge || opcode == spv::Op::OpSelectionMerge) {
result = &*iter;
}
}
@@ -73,7 +71,7 @@ Instruction* BasicBlock::GetMergeInst() {
if (iter != begin()) {
--iter;
const auto opcode = iter->opcode();
if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) {
if (opcode == spv::Op::OpLoopMerge || opcode == spv::Op::OpSelectionMerge) {
result = &*iter;
}
}
@@ -82,7 +80,7 @@ Instruction* BasicBlock::GetMergeInst() {
const Instruction* BasicBlock::GetLoopMergeInst() const {
if (auto* merge = GetMergeInst()) {
if (merge->opcode() == SpvOpLoopMerge) {
if (merge->opcode() == spv::Op::OpLoopMerge) {
return merge;
}
}
@@ -91,7 +89,7 @@ const Instruction* BasicBlock::GetLoopMergeInst() const {
Instruction* BasicBlock::GetLoopMergeInst() {
if (auto* merge = GetMergeInst()) {
if (merge->opcode() == SpvOpLoopMerge) {
if (merge->opcode() == spv::Op::OpLoopMerge) {
return merge;
}
}
@@ -100,7 +98,7 @@ Instruction* BasicBlock::GetLoopMergeInst() {
void BasicBlock::KillAllInsts(bool killLabel) {
ForEachInst([killLabel](Instruction* ip) {
if (killLabel || ip->opcode() != SpvOpLabel) {
if (killLabel || ip->opcode() != spv::Op::OpLabel) {
ip->context()->KillInst(ip);
}
});
@@ -118,10 +116,10 @@ bool BasicBlock::WhileEachSuccessorLabel(
const std::function<bool(const uint32_t)>& f) const {
const auto br = &insts_.back();
switch (br->opcode()) {
case SpvOpBranch:
case spv::Op::OpBranch:
return f(br->GetOperand(0).words[0]);
case SpvOpBranchConditional:
case SpvOpSwitch: {
case spv::Op::OpBranchConditional:
case spv::Op::OpSwitch: {
bool is_first = true;
return br->WhileEachInId([&is_first, &f](const uint32_t* idp) {
if (!is_first) return f(*idp);
@@ -138,13 +136,13 @@ void BasicBlock::ForEachSuccessorLabel(
const std::function<void(uint32_t*)>& f) {
auto br = &insts_.back();
switch (br->opcode()) {
case SpvOpBranch: {
case spv::Op::OpBranch: {
uint32_t tmp_id = br->GetOperand(0).words[0];
f(&tmp_id);
if (tmp_id != br->GetOperand(0).words[0]) br->SetOperand(0, {tmp_id});
} break;
case SpvOpBranchConditional:
case SpvOpSwitch: {
case spv::Op::OpBranchConditional:
case spv::Op::OpSwitch: {
bool is_first = true;
br->ForEachInId([&is_first, &f](uint32_t* idp) {
if (!is_first) f(idp);
@@ -171,7 +169,8 @@ void BasicBlock::ForMergeAndContinueLabel(
--ii;
if (ii == insts_.begin()) return;
--ii;
if (ii->opcode() == SpvOpSelectionMerge || ii->opcode() == SpvOpLoopMerge) {
if (ii->opcode() == spv::Op::OpSelectionMerge ||
ii->opcode() == spv::Op::OpLoopMerge) {
ii->ForEachInId([&f](const uint32_t* idp) { f(*idp); });
}
}
@@ -182,9 +181,9 @@ uint32_t BasicBlock::MergeBlockIdIfAny() const {
uint32_t mbid = 0;
if (merge_ii != cbegin()) {
--merge_ii;
if (merge_ii->opcode() == SpvOpLoopMerge) {
if (merge_ii->opcode() == spv::Op::OpLoopMerge) {
mbid = merge_ii->GetSingleWordInOperand(kLoopMergeMergeBlockIdInIdx);
} else if (merge_ii->opcode() == SpvOpSelectionMerge) {
} else if (merge_ii->opcode() == spv::Op::OpSelectionMerge) {
mbid = merge_ii->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx);
}
}
@@ -204,7 +203,7 @@ uint32_t BasicBlock::ContinueBlockIdIfAny() const {
uint32_t cbid = 0;
if (merge_ii != cbegin()) {
--merge_ii;
if (merge_ii->opcode() == SpvOpLoopMerge) {
if (merge_ii->opcode() == spv::Op::OpLoopMerge) {
cbid = merge_ii->GetSingleWordInOperand(kLoopMergeContinueBlockIdInIdx);
}
}
@@ -241,9 +240,9 @@ BasicBlock* BasicBlock::SplitBasicBlock(IRContext* context, uint32_t label_id,
iterator iter) {
assert(!insts_.empty());
std::unique_ptr<BasicBlock> new_block_temp =
MakeUnique<BasicBlock>(MakeUnique<Instruction>(
context, SpvOpLabel, 0, label_id, std::initializer_list<Operand>{}));
std::unique_ptr<BasicBlock> new_block_temp = MakeUnique<BasicBlock>(
MakeUnique<Instruction>(context, spv::Op::OpLabel, 0, label_id,
std::initializer_list<Operand>{}));
BasicBlock* new_block = new_block_temp.get();
function_->InsertBasicBlockAfter(std::move(new_block_temp), this);

View File

@@ -319,7 +319,7 @@ inline bool BasicBlock::WhileEachPhiInst(
Instruction* inst = &insts_.front();
while (inst != nullptr) {
Instruction* next_instruction = inst->NextNode();
if (inst->opcode() != SpvOpPhi) break;
if (inst->opcode() != spv::Op::OpPhi) break;
if (!inst->WhileEachInst(f, run_on_debug_line_insts)) return false;
inst = next_instruction;
}

View File

@@ -20,7 +20,6 @@
namespace spvtools {
namespace opt {
namespace blockmergeutil {
namespace {
// Returns true if |block| contains a merge instruction.
@@ -34,14 +33,15 @@ bool IsHeader(IRContext* context, uint32_t id) {
// Returns true if |id| is the merge target of a merge instruction.
bool IsMerge(IRContext* context, uint32_t id) {
return !context->get_def_use_mgr()->WhileEachUse(id, [](Instruction* user,
uint32_t index) {
SpvOp op = user->opcode();
if ((op == SpvOpLoopMerge || op == SpvOpSelectionMerge) && index == 0u) {
return false;
}
return true;
});
return !context->get_def_use_mgr()->WhileEachUse(
id, [](Instruction* user, uint32_t index) {
spv::Op op = user->opcode();
if ((op == spv::Op::OpLoopMerge || op == spv::Op::OpSelectionMerge) &&
index == 0u) {
return false;
}
return true;
});
}
// Returns true if |block| is the merge target of a merge instruction.
@@ -53,8 +53,8 @@ bool IsMerge(IRContext* context, BasicBlock* block) {
bool IsContinue(IRContext* context, uint32_t id) {
return !context->get_def_use_mgr()->WhileEachUse(
id, [](Instruction* user, uint32_t index) {
SpvOp op = user->opcode();
if (op == SpvOpLoopMerge && index == 1u) {
spv::Op op = user->opcode();
if (op == spv::Op::OpLoopMerge && index == 1u) {
return false;
}
return true;
@@ -82,7 +82,7 @@ bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) {
auto ii = block->end();
--ii;
Instruction* br = &*ii;
if (br->opcode() != SpvOpBranch) {
if (br->opcode() != spv::Op::OpBranch) {
return false;
}
@@ -119,9 +119,10 @@ bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) {
// The merge must be a loop merge because a selection merge cannot be
// followed by an unconditional branch.
BasicBlock* succ_block = context->get_instr_block(lab_id);
SpvOp succ_term_op = succ_block->terminator()->opcode();
assert(merge_inst->opcode() == SpvOpLoopMerge);
if (succ_term_op != SpvOpBranch && succ_term_op != SpvOpBranchConditional) {
spv::Op succ_term_op = succ_block->terminator()->opcode();
assert(merge_inst->opcode() == spv::Op::OpLoopMerge);
if (succ_term_op != spv::Op::OpBranch &&
succ_term_op != spv::Op::OpBranchConditional) {
return false;
}
}
@@ -170,6 +171,11 @@ void MergeWithSuccessor(IRContext* context, Function* func,
// sbi must follow bi in func's ordering.
assert(sbi != func->end());
if (sbi->tail()->opcode() == spv::Op::OpSwitch &&
sbi->MergeBlockIdIfAny() != 0) {
context->InvalidateAnalyses(IRContext::Analysis::kAnalysisStructuredCFG);
}
// Update the inst-to-block mapping for the instructions in sbi.
for (auto& inst : *sbi) {
context->set_instr_block(&inst, &*bi);

View File

@@ -29,14 +29,11 @@
namespace spvtools {
namespace opt {
namespace {
// This SSA id is never defined nor referenced in the IR. It is a special ID
// which represents varying values. When an ID is found to have a varying
// value, its entry in the |values_| table maps to kVaryingSSAId.
const uint32_t kVaryingSSAId = std::numeric_limits<uint32_t>::max();
constexpr uint32_t kVaryingSSAId = std::numeric_limits<uint32_t>::max();
} // namespace
bool CCPPass::IsVaryingValue(uint32_t id) const { return id == kVaryingSSAId; }
@@ -136,7 +133,7 @@ SSAPropagator::PropStatus CCPPass::VisitAssignment(Instruction* instr) {
// If this is a copy operation, and the RHS is a known constant, assign its
// value to the LHS.
if (instr->opcode() == SpvOpCopyObject) {
if (instr->opcode() == spv::Op::OpCopyObject) {
uint32_t rhs_id = instr->GetSingleWordInOperand(0);
auto it = values_.find(rhs_id);
if (it != values_.end()) {
@@ -211,10 +208,10 @@ SSAPropagator::PropStatus CCPPass::VisitBranch(Instruction* instr,
*dest_bb = nullptr;
uint32_t dest_label = 0;
if (instr->opcode() == SpvOpBranch) {
if (instr->opcode() == spv::Op::OpBranch) {
// An unconditional jump always goes to its unique destination.
dest_label = instr->GetSingleWordInOperand(0);
} else if (instr->opcode() == SpvOpBranchConditional) {
} else if (instr->opcode() == spv::Op::OpBranchConditional) {
// For a conditional branch, determine whether the predicate selector has a
// known value in |values_|. If it does, set the destination block
// according to the selector's boolean value.
@@ -243,7 +240,7 @@ SSAPropagator::PropStatus CCPPass::VisitBranch(Instruction* instr,
// For an OpSwitch, extract the value taken by the switch selector and check
// which of the target literals it matches. The branch associated with that
// literal is the taken branch.
assert(instr->opcode() == SpvOpSwitch);
assert(instr->opcode() == spv::Op::OpSwitch);
if (instr->GetOperand(0).words.size() != 1) {
// If the selector is wider than 32-bits, return varying. TODO(dnovillo):
// Add support for wider constants.
@@ -290,7 +287,7 @@ SSAPropagator::PropStatus CCPPass::VisitBranch(Instruction* instr,
SSAPropagator::PropStatus CCPPass::VisitInstruction(Instruction* instr,
BasicBlock** dest_bb) {
*dest_bb = nullptr;
if (instr->opcode() == SpvOpPhi) {
if (instr->opcode() == spv::Op::OpPhi) {
return VisitPhi(instr);
} else if (instr->IsBranch()) {
return VisitBranch(instr, dest_bb);

View File

@@ -29,16 +29,16 @@ namespace {
using cbb_ptr = const opt::BasicBlock*;
// Universal Limit of ResultID + 1
const int kMaxResultId = 0x400000;
constexpr int kMaxResultId = 0x400000;
} // namespace
CFG::CFG(Module* module)
: module_(module),
pseudo_entry_block_(std::unique_ptr<Instruction>(
new Instruction(module->context(), SpvOpLabel, 0, 0, {}))),
new Instruction(module->context(), spv::Op::OpLabel, 0, 0, {}))),
pseudo_exit_block_(std::unique_ptr<Instruction>(new Instruction(
module->context(), SpvOpLabel, 0, kMaxResultId, {}))) {
module->context(), spv::Op::OpLabel, 0, kMaxResultId, {}))) {
for (auto& fn : *module) {
for (auto& blk : fn) {
RegisterBlock(&blk);
@@ -81,7 +81,7 @@ void CFG::ComputeStructuredOrder(Function* func, BasicBlock* root,
BasicBlock* end,
std::list<BasicBlock*>* order) {
assert(module_->context()->get_feature_mgr()->HasCapability(
SpvCapabilityShader) &&
spv::Capability::Shader) &&
"This only works on structured control flow");
// Compute structured successors and do DFS.
@@ -228,7 +228,7 @@ BasicBlock* CFG::SplitLoopHeader(BasicBlock* bb) {
// Create the new header bb basic bb.
// Leave the phi instructions behind.
auto iter = bb->begin();
while (iter->opcode() == SpvOpPhi) {
while (iter->opcode() == spv::Op::OpPhi) {
++iter;
}
@@ -304,7 +304,7 @@ BasicBlock* CFG::SplitLoopHeader(BasicBlock* bb) {
context, bb,
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
bb->AddInstruction(
MakeUnique<Instruction>(context, SpvOpBranch, 0, 0,
MakeUnique<Instruction>(context, spv::Op::OpBranch, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {new_header->id()}}}));
context->AnalyzeUses(bb->terminator());

View File

@@ -50,7 +50,8 @@ bool CodeSinkingPass::SinkInstructionsInBB(BasicBlock* bb) {
}
bool CodeSinkingPass::SinkInstruction(Instruction* inst) {
if (inst->opcode() != SpvOpLoad && inst->opcode() != SpvOpAccessChain) {
if (inst->opcode() != spv::Op::OpLoad &&
inst->opcode() != spv::Op::OpAccessChain) {
return false;
}
@@ -60,7 +61,7 @@ bool CodeSinkingPass::SinkInstruction(Instruction* inst) {
if (BasicBlock* target_bb = FindNewBasicBlockFor(inst)) {
Instruction* pos = &*target_bb->begin();
while (pos->opcode() == SpvOpPhi) {
while (pos->opcode() == spv::Op::OpPhi) {
pos = pos->NextNode();
}
@@ -79,7 +80,7 @@ BasicBlock* CodeSinkingPass::FindNewBasicBlockFor(Instruction* inst) {
std::unordered_set<uint32_t> bbs_with_uses;
get_def_use_mgr()->ForEachUse(
inst, [&bbs_with_uses, this](Instruction* use, uint32_t idx) {
if (use->opcode() != SpvOpPhi) {
if (use->opcode() != spv::Op::OpPhi) {
BasicBlock* use_bb = context()->get_instr_block(use);
if (use_bb) {
bbs_with_uses.insert(use_bb->id());
@@ -99,7 +100,7 @@ BasicBlock* CodeSinkingPass::FindNewBasicBlockFor(Instruction* inst) {
// of succ_bb, then |inst| can be moved to succ_bb. If succ_bb, has move
// then one predecessor, then moving |inst| into succ_bb could cause it to
// be executed more often, so the search has to stop.
if (bb->terminator()->opcode() == SpvOpBranch) {
if (bb->terminator()->opcode() == spv::Op::OpBranch) {
uint32_t succ_bb_id = bb->terminator()->GetSingleWordInOperand(0);
if (cfg()->preds(succ_bb_id).size() == 1) {
bb = context()->get_instr_block(succ_bb_id);
@@ -113,7 +114,8 @@ BasicBlock* CodeSinkingPass::FindNewBasicBlockFor(Instruction* inst) {
// instruction or an OpLoopMerge, then it is a break or continue. We could
// figure it out, but not worth doing it now.
Instruction* merge_inst = bb->GetMergeInst();
if (merge_inst == nullptr || merge_inst->opcode() != SpvOpSelectionMerge) {
if (merge_inst == nullptr ||
merge_inst->opcode() != spv::Op::OpSelectionMerge) {
break;
}
@@ -173,7 +175,7 @@ bool CodeSinkingPass::ReferencesMutableMemory(Instruction* inst) {
}
Instruction* base_ptr = inst->GetBaseAddress();
if (base_ptr->opcode() != SpvOpVariable) {
if (base_ptr->opcode() != spv::Op::OpVariable) {
return true;
}
@@ -185,7 +187,8 @@ bool CodeSinkingPass::ReferencesMutableMemory(Instruction* inst) {
return true;
}
if (base_ptr->GetSingleWordInOperand(0) != SpvStorageClassUniform) {
if (spv::StorageClass(base_ptr->GetSingleWordInOperand(0)) !=
spv::StorageClass::Uniform) {
return true;
}
@@ -200,41 +203,41 @@ bool CodeSinkingPass::HasUniformMemorySync() {
bool has_sync = false;
get_module()->ForEachInst([this, &has_sync](Instruction* inst) {
switch (inst->opcode()) {
case SpvOpMemoryBarrier: {
case spv::Op::OpMemoryBarrier: {
uint32_t mem_semantics_id = inst->GetSingleWordInOperand(1);
if (IsSyncOnUniform(mem_semantics_id)) {
has_sync = true;
}
break;
}
case SpvOpControlBarrier:
case SpvOpAtomicLoad:
case SpvOpAtomicStore:
case SpvOpAtomicExchange:
case SpvOpAtomicIIncrement:
case SpvOpAtomicIDecrement:
case SpvOpAtomicIAdd:
case SpvOpAtomicFAddEXT:
case SpvOpAtomicISub:
case SpvOpAtomicSMin:
case SpvOpAtomicUMin:
case SpvOpAtomicFMinEXT:
case SpvOpAtomicSMax:
case SpvOpAtomicUMax:
case SpvOpAtomicFMaxEXT:
case SpvOpAtomicAnd:
case SpvOpAtomicOr:
case SpvOpAtomicXor:
case SpvOpAtomicFlagTestAndSet:
case SpvOpAtomicFlagClear: {
case spv::Op::OpControlBarrier:
case spv::Op::OpAtomicLoad:
case spv::Op::OpAtomicStore:
case spv::Op::OpAtomicExchange:
case spv::Op::OpAtomicIIncrement:
case spv::Op::OpAtomicIDecrement:
case spv::Op::OpAtomicIAdd:
case spv::Op::OpAtomicFAddEXT:
case spv::Op::OpAtomicISub:
case spv::Op::OpAtomicSMin:
case spv::Op::OpAtomicUMin:
case spv::Op::OpAtomicFMinEXT:
case spv::Op::OpAtomicSMax:
case spv::Op::OpAtomicUMax:
case spv::Op::OpAtomicFMaxEXT:
case spv::Op::OpAtomicAnd:
case spv::Op::OpAtomicOr:
case spv::Op::OpAtomicXor:
case spv::Op::OpAtomicFlagTestAndSet:
case spv::Op::OpAtomicFlagClear: {
uint32_t mem_semantics_id = inst->GetSingleWordInOperand(2);
if (IsSyncOnUniform(mem_semantics_id)) {
has_sync = true;
}
break;
}
case SpvOpAtomicCompareExchange:
case SpvOpAtomicCompareExchangeWeak:
case spv::Op::OpAtomicCompareExchange:
case spv::Op::OpAtomicCompareExchangeWeak:
if (IsSyncOnUniform(inst->GetSingleWordInOperand(2)) ||
IsSyncOnUniform(inst->GetSingleWordInOperand(3))) {
has_sync = true;
@@ -259,28 +262,30 @@ bool CodeSinkingPass::IsSyncOnUniform(uint32_t mem_semantics_id) const {
// If it does not affect uniform memory, then it is does not apply to uniform
// memory.
if ((mem_semantics_int & SpvMemorySemanticsUniformMemoryMask) == 0) {
if ((mem_semantics_int & uint32_t(spv::MemorySemanticsMask::UniformMemory)) ==
0) {
return false;
}
// Check if there is an acquire or release. If so not, this it does not add
// any memory constraints.
return (mem_semantics_int & (SpvMemorySemanticsAcquireMask |
SpvMemorySemanticsAcquireReleaseMask |
SpvMemorySemanticsReleaseMask)) != 0;
return (mem_semantics_int &
uint32_t(spv::MemorySemanticsMask::Acquire |
spv::MemorySemanticsMask::AcquireRelease |
spv::MemorySemanticsMask::Release)) != 0;
}
bool CodeSinkingPass::HasPossibleStore(Instruction* var_inst) {
assert(var_inst->opcode() == SpvOpVariable ||
var_inst->opcode() == SpvOpAccessChain ||
var_inst->opcode() == SpvOpPtrAccessChain);
assert(var_inst->opcode() == spv::Op::OpVariable ||
var_inst->opcode() == spv::Op::OpAccessChain ||
var_inst->opcode() == spv::Op::OpPtrAccessChain);
return get_def_use_mgr()->WhileEachUser(var_inst, [this](Instruction* use) {
switch (use->opcode()) {
case SpvOpStore:
case spv::Op::OpStore:
return true;
case SpvOpAccessChain:
case SpvOpPtrAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpPtrAccessChain:
return HasPossibleStore(use);
default:
return false;

View File

@@ -44,10 +44,10 @@ bool CombineAccessChains::ProcessFunction(Function& function) {
function.entry().get(), [&modified, this](BasicBlock* block) {
block->ForEachInst([&modified, this](Instruction* inst) {
switch (inst->opcode()) {
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
modified |= CombineAccessChain(inst);
break;
default:
@@ -76,10 +76,10 @@ uint32_t CombineAccessChains::GetConstantValue(
uint32_t CombineAccessChains::GetArrayStride(const Instruction* inst) {
uint32_t array_stride = 0;
context()->get_decoration_mgr()->WhileEachDecoration(
inst->type_id(), SpvDecorationArrayStride,
inst->type_id(), uint32_t(spv::Decoration::ArrayStride),
[&array_stride](const Instruction& decoration) {
assert(decoration.opcode() != SpvOpDecorateId);
if (decoration.opcode() == SpvOpDecorate) {
assert(decoration.opcode() != spv::Op::OpDecorateId);
if (decoration.opcode() == spv::Op::OpDecorate) {
array_stride = decoration.GetSingleWordInOperand(1);
} else {
array_stride = decoration.GetSingleWordInOperand(2);
@@ -200,18 +200,18 @@ bool CombineAccessChains::CreateNewInputOperands(
}
bool CombineAccessChains::CombineAccessChain(Instruction* inst) {
assert((inst->opcode() == SpvOpPtrAccessChain ||
inst->opcode() == SpvOpAccessChain ||
inst->opcode() == SpvOpInBoundsAccessChain ||
inst->opcode() == SpvOpInBoundsPtrAccessChain) &&
assert((inst->opcode() == spv::Op::OpPtrAccessChain ||
inst->opcode() == spv::Op::OpAccessChain ||
inst->opcode() == spv::Op::OpInBoundsAccessChain ||
inst->opcode() == spv::Op::OpInBoundsPtrAccessChain) &&
"Wrong opcode. Expected an access chain.");
Instruction* ptr_input =
context()->get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0));
if (ptr_input->opcode() != SpvOpAccessChain &&
ptr_input->opcode() != SpvOpInBoundsAccessChain &&
ptr_input->opcode() != SpvOpPtrAccessChain &&
ptr_input->opcode() != SpvOpInBoundsPtrAccessChain) {
if (ptr_input->opcode() != spv::Op::OpAccessChain &&
ptr_input->opcode() != spv::Op::OpInBoundsAccessChain &&
ptr_input->opcode() != spv::Op::OpPtrAccessChain &&
ptr_input->opcode() != spv::Op::OpInBoundsPtrAccessChain) {
return false;
}
@@ -246,7 +246,7 @@ bool CombineAccessChains::CombineAccessChain(Instruction* inst) {
} else if (inst->NumInOperands() == 1) {
// |inst| is a no-op, change it to a copy. Instruction simplification will
// clean it up.
inst->SetOpcode(SpvOpCopyObject);
inst->SetOpcode(spv::Op::OpCopyObject);
} else {
std::vector<Operand> new_operands;
if (!CreateNewInputOperands(ptr_input, inst, &new_operands)) return false;
@@ -259,23 +259,25 @@ bool CombineAccessChains::CombineAccessChain(Instruction* inst) {
return true;
}
SpvOp CombineAccessChains::UpdateOpcode(SpvOp base_opcode, SpvOp input_opcode) {
auto IsInBounds = [](SpvOp opcode) {
return opcode == SpvOpInBoundsPtrAccessChain ||
opcode == SpvOpInBoundsAccessChain;
spv::Op CombineAccessChains::UpdateOpcode(spv::Op base_opcode,
spv::Op input_opcode) {
auto IsInBounds = [](spv::Op opcode) {
return opcode == spv::Op::OpInBoundsPtrAccessChain ||
opcode == spv::Op::OpInBoundsAccessChain;
};
if (input_opcode == SpvOpInBoundsPtrAccessChain) {
if (!IsInBounds(base_opcode)) return SpvOpPtrAccessChain;
} else if (input_opcode == SpvOpInBoundsAccessChain) {
if (!IsInBounds(base_opcode)) return SpvOpAccessChain;
if (input_opcode == spv::Op::OpInBoundsPtrAccessChain) {
if (!IsInBounds(base_opcode)) return spv::Op::OpPtrAccessChain;
} else if (input_opcode == spv::Op::OpInBoundsAccessChain) {
if (!IsInBounds(base_opcode)) return spv::Op::OpAccessChain;
}
return input_opcode;
}
bool CombineAccessChains::IsPtrAccessChain(SpvOp opcode) {
return opcode == SpvOpPtrAccessChain || opcode == SpvOpInBoundsPtrAccessChain;
bool CombineAccessChains::IsPtrAccessChain(spv::Op opcode) {
return opcode == spv::Op::OpPtrAccessChain ||
opcode == spv::Op::OpInBoundsPtrAccessChain;
}
bool CombineAccessChains::Has64BitIndices(Instruction* inst) {

View File

@@ -68,10 +68,10 @@ class CombineAccessChains : public Pass {
std::vector<Operand>* new_operands);
// Returns the opcode to use for the combined access chain.
SpvOp UpdateOpcode(SpvOp base_opcode, SpvOp input_opcode);
spv::Op UpdateOpcode(spv::Op base_opcode, spv::Op input_opcode);
// Returns true if |opcode| is a pointer access chain.
bool IsPtrAccessChain(SpvOp opcode);
bool IsPtrAccessChain(spv::Op opcode);
// Returns true if |inst| (an access chain) has 64-bit indices.
bool Has64BitIndices(Instruction* inst);

View File

@@ -19,8 +19,7 @@
namespace spvtools {
namespace opt {
namespace {
const uint32_t kExtractCompositeIdInIdx = 0;
constexpr uint32_t kExtractCompositeIdInIdx = 0;
// Returns a constants with the value NaN of the given type. Only works for
// 32-bit and 64-bit float point types. Returns |nullptr| if an error occurs.
@@ -120,11 +119,97 @@ ConstantFoldingRule FoldExtractWithConstants() {
};
}
// Folds an OpcompositeInsert where input is a composite constant.
ConstantFoldingRule FoldInsertWithConstants() {
return [](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Constant* object = constants[0];
const analysis::Constant* composite = constants[1];
if (object == nullptr || composite == nullptr) {
return nullptr;
}
// If there is more than 1 index, then each additional constant used by the
// index will need to be recreated to use the inserted object.
std::vector<const analysis::Constant*> chain;
std::vector<const analysis::Constant*> components;
const analysis::Type* type = nullptr;
const uint32_t final_index = (inst->NumInOperands() - 1);
// Work down hierarchy of all indexes
for (uint32_t i = 2; i < inst->NumInOperands(); ++i) {
type = composite->type();
if (composite->AsNullConstant()) {
// Make new composite so it can be inserted in the index with the
// non-null value
const auto new_composite = const_mgr->GetNullCompositeConstant(type);
// Keep track of any indexes along the way to last index
if (i != final_index) {
chain.push_back(new_composite);
}
components = new_composite->AsCompositeConstant()->GetComponents();
} else {
// Keep track of any indexes along the way to last index
if (i != final_index) {
chain.push_back(composite);
}
components = composite->AsCompositeConstant()->GetComponents();
}
const uint32_t index = inst->GetSingleWordInOperand(i);
composite = components[index];
}
// Final index in hierarchy is inserted with new object.
const uint32_t final_operand = inst->GetSingleWordInOperand(final_index);
std::vector<uint32_t> ids;
for (size_t i = 0; i < components.size(); i++) {
const analysis::Constant* constant =
(i == final_operand) ? object : components[i];
Instruction* member_inst = const_mgr->GetDefiningInstruction(constant);
ids.push_back(member_inst->result_id());
}
const analysis::Constant* new_constant = const_mgr->GetConstant(type, ids);
// Work backwards up the chain and replace each index with new constant.
for (size_t i = chain.size(); i > 0; i--) {
// Need to insert any previous instruction into the module first.
// Can't just insert in types_values_begin() because it will move above
// where the types are declared.
// Can't compare with location of inst because not all new added
// instructions are added to types_values_
auto iter = context->types_values_end();
Module::inst_iterator* pos = &iter;
const_mgr->BuildInstructionAndAddToModule(new_constant, pos);
composite = chain[i - 1];
components = composite->AsCompositeConstant()->GetComponents();
type = composite->type();
ids.clear();
for (size_t k = 0; k < components.size(); k++) {
const uint32_t index =
inst->GetSingleWordInOperand(1 + static_cast<uint32_t>(i));
const analysis::Constant* constant =
(k == index) ? new_constant : components[k];
const uint32_t constant_id =
const_mgr->FindDeclaredConstant(constant, 0);
ids.push_back(constant_id);
}
new_constant = const_mgr->GetConstant(type, ids);
}
// If multiple constants were created, only need to return the top index.
return new_constant;
};
}
ConstantFoldingRule FoldVectorShuffleWithConstants() {
return [](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
assert(inst->opcode() == SpvOpVectorShuffle);
assert(inst->opcode() == spv::Op::OpVectorShuffle);
const analysis::Constant* c1 = constants[0];
const analysis::Constant* c2 = constants[1];
if (c1 == nullptr || c2 == nullptr) {
@@ -180,7 +265,7 @@ ConstantFoldingRule FoldVectorTimesScalar() {
return [](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
assert(inst->opcode() == SpvOpVectorTimesScalar);
assert(inst->opcode() == spv::Op::OpVectorTimesScalar);
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
@@ -255,7 +340,7 @@ ConstantFoldingRule FoldVectorTimesMatrix() {
return [](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
assert(inst->opcode() == SpvOpVectorTimesMatrix);
assert(inst->opcode() == spv::Op::OpVectorTimesMatrix);
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
@@ -348,7 +433,7 @@ ConstantFoldingRule FoldMatrixTimesVector() {
return [](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
assert(inst->opcode() == SpvOpMatrixTimesVector);
assert(inst->opcode() == spv::Op::OpMatrixTimesVector);
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
@@ -458,9 +543,9 @@ ConstantFoldingRule FoldCompositeWithConstants() {
}
uint32_t component_type_id = 0;
if (type_inst->opcode() == SpvOpTypeStruct) {
if (type_inst->opcode() == spv::Op::OpTypeStruct) {
component_type_id = type_inst->GetSingleWordInOperand(i);
} else if (type_inst->opcode() == SpvOpTypeArray) {
} else if (type_inst->opcode() == spv::Op::OpTypeArray) {
component_type_id = type_inst->GetSingleWordInOperand(0);
}
@@ -509,7 +594,7 @@ ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) {
}
const analysis::Constant* arg =
(inst->opcode() == SpvOpExtInst) ? constants[1] : constants[0];
(inst->opcode() == spv::Op::OpExtInst) ? constants[1] : constants[0];
if (arg == nullptr) {
return nullptr;
@@ -599,7 +684,7 @@ ConstantFoldingRule FoldFPBinaryOp(BinaryScalarFoldingRule scalar_rule) {
if (!inst->IsFloatingPointFoldingAllowed()) {
return nullptr;
}
if (inst->opcode() == SpvOpExtInst) {
if (inst->opcode() == spv::Op::OpExtInst) {
return FoldFPBinaryOp(scalar_rule, inst->type_id(),
{constants[1], constants[2]}, context);
}
@@ -957,7 +1042,7 @@ UnaryScalarFoldingRule FoldFNegateOp() {
ConstantFoldingRule FoldFNegate() { return FoldFPUnaryOp(FoldFNegateOp()); }
ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
ConstantFoldingRule FoldFClampFeedingCompare(spv::Op cmp_opcode) {
return [cmp_opcode](IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
@@ -985,7 +1070,7 @@ ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
return nullptr;
}
if (operand_inst->opcode() != SpvOpExtInst) {
if (operand_inst->opcode() != spv::Op::OpExtInst) {
return nullptr;
}
@@ -1009,25 +1094,25 @@ ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
bool result = false;
switch (cmp_opcode) {
case SpvOpFOrdLessThan:
case SpvOpFUnordLessThan:
case SpvOpFOrdGreaterThanEqual:
case SpvOpFUnordGreaterThanEqual:
case spv::Op::OpFOrdLessThan:
case spv::Op::OpFUnordLessThan:
case spv::Op::OpFOrdGreaterThanEqual:
case spv::Op::OpFUnordGreaterThanEqual:
if (constants[0]) {
if (min_const) {
if (constants[0]->GetValueAsDouble() <
min_const->GetValueAsDouble()) {
found_result = true;
result = (cmp_opcode == SpvOpFOrdLessThan ||
cmp_opcode == SpvOpFUnordLessThan);
result = (cmp_opcode == spv::Op::OpFOrdLessThan ||
cmp_opcode == spv::Op::OpFUnordLessThan);
}
}
if (max_const) {
if (constants[0]->GetValueAsDouble() >=
max_const->GetValueAsDouble()) {
found_result = true;
result = !(cmp_opcode == SpvOpFOrdLessThan ||
cmp_opcode == SpvOpFUnordLessThan);
result = !(cmp_opcode == spv::Op::OpFOrdLessThan ||
cmp_opcode == spv::Op::OpFUnordLessThan);
}
}
}
@@ -1037,8 +1122,8 @@ ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
if (max_const->GetValueAsDouble() <
constants[1]->GetValueAsDouble()) {
found_result = true;
result = (cmp_opcode == SpvOpFOrdLessThan ||
cmp_opcode == SpvOpFUnordLessThan);
result = (cmp_opcode == spv::Op::OpFOrdLessThan ||
cmp_opcode == spv::Op::OpFUnordLessThan);
}
}
@@ -1046,31 +1131,31 @@ ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
if (min_const->GetValueAsDouble() >=
constants[1]->GetValueAsDouble()) {
found_result = true;
result = !(cmp_opcode == SpvOpFOrdLessThan ||
cmp_opcode == SpvOpFUnordLessThan);
result = !(cmp_opcode == spv::Op::OpFOrdLessThan ||
cmp_opcode == spv::Op::OpFUnordLessThan);
}
}
}
break;
case SpvOpFOrdGreaterThan:
case SpvOpFUnordGreaterThan:
case SpvOpFOrdLessThanEqual:
case SpvOpFUnordLessThanEqual:
case spv::Op::OpFOrdGreaterThan:
case spv::Op::OpFUnordGreaterThan:
case spv::Op::OpFOrdLessThanEqual:
case spv::Op::OpFUnordLessThanEqual:
if (constants[0]) {
if (min_const) {
if (constants[0]->GetValueAsDouble() <=
min_const->GetValueAsDouble()) {
found_result = true;
result = (cmp_opcode == SpvOpFOrdLessThanEqual ||
cmp_opcode == SpvOpFUnordLessThanEqual);
result = (cmp_opcode == spv::Op::OpFOrdLessThanEqual ||
cmp_opcode == spv::Op::OpFUnordLessThanEqual);
}
}
if (max_const) {
if (constants[0]->GetValueAsDouble() >
max_const->GetValueAsDouble()) {
found_result = true;
result = !(cmp_opcode == SpvOpFOrdLessThanEqual ||
cmp_opcode == SpvOpFUnordLessThanEqual);
result = !(cmp_opcode == spv::Op::OpFOrdLessThanEqual ||
cmp_opcode == spv::Op::OpFUnordLessThanEqual);
}
}
}
@@ -1080,8 +1165,8 @@ ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
if (max_const->GetValueAsDouble() <=
constants[1]->GetValueAsDouble()) {
found_result = true;
result = (cmp_opcode == SpvOpFOrdLessThanEqual ||
cmp_opcode == SpvOpFUnordLessThanEqual);
result = (cmp_opcode == spv::Op::OpFOrdLessThanEqual ||
cmp_opcode == spv::Op::OpFUnordLessThanEqual);
}
}
@@ -1089,8 +1174,8 @@ ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
if (min_const->GetValueAsDouble() >
constants[1]->GetValueAsDouble()) {
found_result = true;
result = !(cmp_opcode == SpvOpFOrdLessThanEqual ||
cmp_opcode == SpvOpFUnordLessThanEqual);
result = !(cmp_opcode == spv::Op::OpFOrdLessThanEqual ||
cmp_opcode == spv::Op::OpFUnordLessThanEqual);
}
}
}
@@ -1117,7 +1202,7 @@ ConstantFoldingRule FoldFMix() {
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
assert(inst->opcode() == SpvOpExtInst &&
assert(inst->opcode() == spv::Op::OpExtInst &&
"Expecting an extended instruction.");
assert(inst->GetSingleWordInOperand(0) ==
context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
@@ -1267,7 +1352,7 @@ const analysis::Constant* FoldMax(const analysis::Type* result_type,
const analysis::Constant* FoldClamp1(
IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpExtInst &&
assert(inst->opcode() == spv::Op::OpExtInst &&
"Expecting an extended instruction.");
assert(inst->GetSingleWordInOperand(0) ==
context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
@@ -1293,7 +1378,7 @@ const analysis::Constant* FoldClamp1(
const analysis::Constant* FoldClamp2(
IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpExtInst &&
assert(inst->opcode() == spv::Op::OpExtInst &&
"Expecting an extended instruction.");
assert(inst->GetSingleWordInOperand(0) ==
context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
@@ -1321,7 +1406,7 @@ const analysis::Constant* FoldClamp2(
const analysis::Constant* FoldClamp3(
IRContext* context, Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpExtInst &&
assert(inst->opcode() == spv::Op::OpExtInst &&
"Expecting an extended instruction.");
assert(inst->GetSingleWordInOperand(0) ==
context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
@@ -1407,68 +1492,70 @@ void ConstantFoldingRules::AddFoldingRules() {
// applies to the instruction, the rest of the rules will not be attempted.
// Take that into consideration.
rules_[SpvOpCompositeConstruct].push_back(FoldCompositeWithConstants());
rules_[spv::Op::OpCompositeConstruct].push_back(FoldCompositeWithConstants());
rules_[SpvOpCompositeExtract].push_back(FoldExtractWithConstants());
rules_[spv::Op::OpCompositeExtract].push_back(FoldExtractWithConstants());
rules_[spv::Op::OpCompositeInsert].push_back(FoldInsertWithConstants());
rules_[SpvOpConvertFToS].push_back(FoldFToI());
rules_[SpvOpConvertFToU].push_back(FoldFToI());
rules_[SpvOpConvertSToF].push_back(FoldIToF());
rules_[SpvOpConvertUToF].push_back(FoldIToF());
rules_[spv::Op::OpConvertFToS].push_back(FoldFToI());
rules_[spv::Op::OpConvertFToU].push_back(FoldFToI());
rules_[spv::Op::OpConvertSToF].push_back(FoldIToF());
rules_[spv::Op::OpConvertUToF].push_back(FoldIToF());
rules_[SpvOpDot].push_back(FoldOpDotWithConstants());
rules_[SpvOpFAdd].push_back(FoldFAdd());
rules_[SpvOpFDiv].push_back(FoldFDiv());
rules_[SpvOpFMul].push_back(FoldFMul());
rules_[SpvOpFSub].push_back(FoldFSub());
rules_[spv::Op::OpDot].push_back(FoldOpDotWithConstants());
rules_[spv::Op::OpFAdd].push_back(FoldFAdd());
rules_[spv::Op::OpFDiv].push_back(FoldFDiv());
rules_[spv::Op::OpFMul].push_back(FoldFMul());
rules_[spv::Op::OpFSub].push_back(FoldFSub());
rules_[SpvOpFOrdEqual].push_back(FoldFOrdEqual());
rules_[spv::Op::OpFOrdEqual].push_back(FoldFOrdEqual());
rules_[SpvOpFUnordEqual].push_back(FoldFUnordEqual());
rules_[spv::Op::OpFUnordEqual].push_back(FoldFUnordEqual());
rules_[SpvOpFOrdNotEqual].push_back(FoldFOrdNotEqual());
rules_[spv::Op::OpFOrdNotEqual].push_back(FoldFOrdNotEqual());
rules_[SpvOpFUnordNotEqual].push_back(FoldFUnordNotEqual());
rules_[spv::Op::OpFUnordNotEqual].push_back(FoldFUnordNotEqual());
rules_[SpvOpFOrdLessThan].push_back(FoldFOrdLessThan());
rules_[SpvOpFOrdLessThan].push_back(
FoldFClampFeedingCompare(SpvOpFOrdLessThan));
rules_[spv::Op::OpFOrdLessThan].push_back(FoldFOrdLessThan());
rules_[spv::Op::OpFOrdLessThan].push_back(
FoldFClampFeedingCompare(spv::Op::OpFOrdLessThan));
rules_[SpvOpFUnordLessThan].push_back(FoldFUnordLessThan());
rules_[SpvOpFUnordLessThan].push_back(
FoldFClampFeedingCompare(SpvOpFUnordLessThan));
rules_[spv::Op::OpFUnordLessThan].push_back(FoldFUnordLessThan());
rules_[spv::Op::OpFUnordLessThan].push_back(
FoldFClampFeedingCompare(spv::Op::OpFUnordLessThan));
rules_[SpvOpFOrdGreaterThan].push_back(FoldFOrdGreaterThan());
rules_[SpvOpFOrdGreaterThan].push_back(
FoldFClampFeedingCompare(SpvOpFOrdGreaterThan));
rules_[spv::Op::OpFOrdGreaterThan].push_back(FoldFOrdGreaterThan());
rules_[spv::Op::OpFOrdGreaterThan].push_back(
FoldFClampFeedingCompare(spv::Op::OpFOrdGreaterThan));
rules_[SpvOpFUnordGreaterThan].push_back(FoldFUnordGreaterThan());
rules_[SpvOpFUnordGreaterThan].push_back(
FoldFClampFeedingCompare(SpvOpFUnordGreaterThan));
rules_[spv::Op::OpFUnordGreaterThan].push_back(FoldFUnordGreaterThan());
rules_[spv::Op::OpFUnordGreaterThan].push_back(
FoldFClampFeedingCompare(spv::Op::OpFUnordGreaterThan));
rules_[SpvOpFOrdLessThanEqual].push_back(FoldFOrdLessThanEqual());
rules_[SpvOpFOrdLessThanEqual].push_back(
FoldFClampFeedingCompare(SpvOpFOrdLessThanEqual));
rules_[spv::Op::OpFOrdLessThanEqual].push_back(FoldFOrdLessThanEqual());
rules_[spv::Op::OpFOrdLessThanEqual].push_back(
FoldFClampFeedingCompare(spv::Op::OpFOrdLessThanEqual));
rules_[SpvOpFUnordLessThanEqual].push_back(FoldFUnordLessThanEqual());
rules_[SpvOpFUnordLessThanEqual].push_back(
FoldFClampFeedingCompare(SpvOpFUnordLessThanEqual));
rules_[spv::Op::OpFUnordLessThanEqual].push_back(FoldFUnordLessThanEqual());
rules_[spv::Op::OpFUnordLessThanEqual].push_back(
FoldFClampFeedingCompare(spv::Op::OpFUnordLessThanEqual));
rules_[SpvOpFOrdGreaterThanEqual].push_back(FoldFOrdGreaterThanEqual());
rules_[SpvOpFOrdGreaterThanEqual].push_back(
FoldFClampFeedingCompare(SpvOpFOrdGreaterThanEqual));
rules_[spv::Op::OpFOrdGreaterThanEqual].push_back(FoldFOrdGreaterThanEqual());
rules_[spv::Op::OpFOrdGreaterThanEqual].push_back(
FoldFClampFeedingCompare(spv::Op::OpFOrdGreaterThanEqual));
rules_[SpvOpFUnordGreaterThanEqual].push_back(FoldFUnordGreaterThanEqual());
rules_[SpvOpFUnordGreaterThanEqual].push_back(
FoldFClampFeedingCompare(SpvOpFUnordGreaterThanEqual));
rules_[spv::Op::OpFUnordGreaterThanEqual].push_back(
FoldFUnordGreaterThanEqual());
rules_[spv::Op::OpFUnordGreaterThanEqual].push_back(
FoldFClampFeedingCompare(spv::Op::OpFUnordGreaterThanEqual));
rules_[SpvOpVectorShuffle].push_back(FoldVectorShuffleWithConstants());
rules_[SpvOpVectorTimesScalar].push_back(FoldVectorTimesScalar());
rules_[SpvOpVectorTimesMatrix].push_back(FoldVectorTimesMatrix());
rules_[SpvOpMatrixTimesVector].push_back(FoldMatrixTimesVector());
rules_[spv::Op::OpVectorShuffle].push_back(FoldVectorShuffleWithConstants());
rules_[spv::Op::OpVectorTimesScalar].push_back(FoldVectorTimesScalar());
rules_[spv::Op::OpVectorTimesMatrix].push_back(FoldVectorTimesMatrix());
rules_[spv::Op::OpMatrixTimesVector].push_back(FoldMatrixTimesVector());
rules_[SpvOpFNegate].push_back(FoldFNegate());
rules_[SpvOpQuantizeToF16].push_back(FoldQuantizeToF16());
rules_[spv::Op::OpFNegate].push_back(FoldFNegate());
rules_[spv::Op::OpQuantizeToF16].push_back(FoldQuantizeToF16());
// Add rules for GLSLstd450
FeatureManager* feature_manager = context_->get_feature_mgr();

View File

@@ -88,7 +88,7 @@ class ConstantFoldingRules {
// Returns true if there is at least 1 folding rule for |inst|.
const std::vector<ConstantFoldingRule>& GetRulesForInstruction(
const Instruction* inst) const {
if (inst->opcode() != SpvOpExtInst) {
if (inst->opcode() != spv::Op::OpExtInst) {
auto it = rules_.find(inst->opcode());
if (it != rules_.end()) {
return it->second.value;
@@ -108,9 +108,15 @@ class ConstantFoldingRules {
virtual void AddFoldingRules();
protected:
struct hasher {
size_t operator()(const spv::Op& op) const noexcept {
return std::hash<uint32_t>()(uint32_t(op));
}
};
// |rules[opcode]| is the set of rules that can be applied to instructions
// with |opcode| as the opcode.
std::unordered_map<uint32_t, Value> rules_;
std::unordered_map<spv::Op, Value, hasher> rules_;
// The folding rules for extended instructions.
std::map<Key, Value> ext_rules_;

View File

@@ -306,16 +306,16 @@ const Constant* ConstantManager::GetConstantFromInst(const Instruction* inst) {
switch (inst->opcode()) {
// OpConstant{True|False} have the value embedded in the opcode. So they
// are not handled by the for-loop above. Here we add the value explicitly.
case SpvOp::SpvOpConstantTrue:
case spv::Op::OpConstantTrue:
literal_words_or_ids.push_back(true);
break;
case SpvOp::SpvOpConstantFalse:
case spv::Op::OpConstantFalse:
literal_words_or_ids.push_back(false);
break;
case SpvOp::SpvOpConstantNull:
case SpvOp::SpvOpConstant:
case SpvOp::SpvOpConstantComposite:
case SpvOp::SpvOpSpecConstantComposite:
case spv::Op::OpConstantNull:
case spv::Op::OpConstant:
case spv::Op::OpConstantComposite:
case spv::Op::OpSpecConstantComposite:
break;
default:
return nullptr;
@@ -329,22 +329,22 @@ std::unique_ptr<Instruction> ConstantManager::CreateInstruction(
uint32_t type =
(type_id == 0) ? context()->get_type_mgr()->GetId(c->type()) : type_id;
if (c->AsNullConstant()) {
return MakeUnique<Instruction>(context(), SpvOp::SpvOpConstantNull, type,
id, std::initializer_list<Operand>{});
return MakeUnique<Instruction>(context(), spv::Op::OpConstantNull, type, id,
std::initializer_list<Operand>{});
} else if (const BoolConstant* bc = c->AsBoolConstant()) {
return MakeUnique<Instruction>(
context(),
bc->value() ? SpvOp::SpvOpConstantTrue : SpvOp::SpvOpConstantFalse,
type, id, std::initializer_list<Operand>{});
bc->value() ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse, type,
id, std::initializer_list<Operand>{});
} else if (const IntConstant* ic = c->AsIntConstant()) {
return MakeUnique<Instruction>(
context(), SpvOp::SpvOpConstant, type, id,
context(), spv::Op::OpConstant, type, id,
std::initializer_list<Operand>{
Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
ic->words())});
} else if (const FloatConstant* fc = c->AsFloatConstant()) {
return MakeUnique<Instruction>(
context(), SpvOp::SpvOpConstant, type, id,
context(), spv::Op::OpConstant, type, id,
std::initializer_list<Operand>{
Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
fc->words())});
@@ -362,9 +362,9 @@ std::unique_ptr<Instruction> ConstantManager::CreateCompositeInstruction(
uint32_t component_index = 0;
for (const Constant* component_const : cc->GetComponents()) {
uint32_t component_type_id = 0;
if (type_inst && type_inst->opcode() == SpvOpTypeStruct) {
if (type_inst && type_inst->opcode() == spv::Op::OpTypeStruct) {
component_type_id = type_inst->GetSingleWordInOperand(component_index);
} else if (type_inst && type_inst->opcode() == SpvOpTypeArray) {
} else if (type_inst && type_inst->opcode() == spv::Op::OpTypeArray) {
component_type_id = type_inst->GetSingleWordInOperand(0);
}
uint32_t id = FindDeclaredConstant(component_const, component_type_id);
@@ -381,7 +381,7 @@ std::unique_ptr<Instruction> ConstantManager::CreateCompositeInstruction(
}
uint32_t type =
(type_id == 0) ? context()->get_type_mgr()->GetId(cc->type()) : type_id;
return MakeUnique<Instruction>(context(), SpvOp::SpvOpConstantComposite, type,
return MakeUnique<Instruction>(context(), spv::Op::OpConstantComposite, type,
result_id, std::move(operands));
}
@@ -391,6 +391,43 @@ const Constant* ConstantManager::GetConstant(
return cst ? RegisterConstant(std::move(cst)) : nullptr;
}
const Constant* ConstantManager::GetNullCompositeConstant(const Type* type) {
std::vector<uint32_t> literal_words_or_id;
if (type->AsVector()) {
const Type* element_type = type->AsVector()->element_type();
const uint32_t null_id = GetNullConstId(element_type);
const uint32_t element_count = type->AsVector()->element_count();
for (uint32_t i = 0; i < element_count; i++) {
literal_words_or_id.push_back(null_id);
}
} else if (type->AsMatrix()) {
const Type* element_type = type->AsMatrix()->element_type();
const uint32_t null_id = GetNullConstId(element_type);
const uint32_t element_count = type->AsMatrix()->element_count();
for (uint32_t i = 0; i < element_count; i++) {
literal_words_or_id.push_back(null_id);
}
} else if (type->AsStruct()) {
// TODO (sfricke-lunarg) add proper struct support
return nullptr;
} else if (type->AsArray()) {
const Type* element_type = type->AsArray()->element_type();
const uint32_t null_id = GetNullConstId(element_type);
assert(type->AsArray()->length_info().words[0] ==
analysis::Array::LengthInfo::kConstant &&
"unexpected array length");
const uint32_t element_count = type->AsArray()->length_info().words[0];
for (uint32_t i = 0; i < element_count; i++) {
literal_words_or_id.push_back(null_id);
}
} else {
return nullptr;
}
return GetConstant(type, literal_words_or_id);
}
const Constant* ConstantManager::GetNumericVectorConstantWithWords(
const Vector* type, const std::vector<uint32_t>& literal_words) {
const auto* element_type = type->element_type();
@@ -445,18 +482,23 @@ const Constant* ConstantManager::GetDoubleConst(double val) {
return c;
}
uint32_t ConstantManager::GetSIntConst(int32_t val) {
uint32_t ConstantManager::GetSIntConstId(int32_t val) {
Type* sint_type = context()->get_type_mgr()->GetSIntType();
const Constant* c = GetConstant(sint_type, {static_cast<uint32_t>(val)});
return GetDefiningInstruction(c)->result_id();
}
uint32_t ConstantManager::GetUIntConst(uint32_t val) {
uint32_t ConstantManager::GetUIntConstId(uint32_t val) {
Type* uint_type = context()->get_type_mgr()->GetUIntType();
const Constant* c = GetConstant(uint_type, {val});
return GetDefiningInstruction(c)->result_id();
}
uint32_t ConstantManager::GetNullConstId(const Type* type) {
const Constant* c = GetConstant(type, {});
return GetDefiningInstruction(c)->result_id();
}
std::vector<const analysis::Constant*> Constant::GetVectorComponents(
analysis::ConstantManager* const_mgr) const {
std::vector<const analysis::Constant*> components;

View File

@@ -520,6 +520,14 @@ class ConstantManager {
literal_words_or_ids.end()));
}
// Takes a type and creates a OpConstantComposite
// This allows a
// OpConstantNull %composite_type
// to become a
// OpConstantComposite %composite_type %null %null ... etc
// Assumes type is a Composite already, otherwise returns null
const Constant* GetNullCompositeConstant(const Type* type);
// Gets or creates a unique Constant instance of Vector type |type| with
// numeric elements and a vector of constant defining words |literal_words|.
// If a Constant instance existed already in the constant pool, it returns a
@@ -649,10 +657,13 @@ class ConstantManager {
const Constant* GetDoubleConst(double val);
// Returns the id of a 32-bit signed integer constant with value |val|.
uint32_t GetSIntConst(int32_t val);
uint32_t GetSIntConstId(int32_t val);
// Returns the id of a 32-bit unsigned integer constant with value |val|.
uint32_t GetUIntConst(uint32_t val);
uint32_t GetUIntConstId(uint32_t val);
// Returns the id of a OpConstantNull with type of |type|.
uint32_t GetNullConstId(const Type* type);
private:
// Creates a Constant instance with the given type and a vector of constant

View File

@@ -24,7 +24,6 @@
#include "source/opt/dominator_analysis.h"
#include "source/opt/function.h"
#include "source/opt/instruction.h"
#include "spirv/unified1/spirv.h"
// Computes the control dependence graph (CDG) using the algorithm in Cytron
// 1991, "Efficiently Computing Static Single Assignment Form and the Control
@@ -49,8 +48,8 @@ uint32_t ControlDependence::GetConditionID(const CFG& cfg) const {
}
const BasicBlock* source_bb = cfg.block(source_bb_id());
const Instruction* branch = source_bb->terminator();
assert((branch->opcode() == SpvOpBranchConditional ||
branch->opcode() == SpvOpSwitch) &&
assert((branch->opcode() == spv::Op::OpBranchConditional ||
branch->opcode() == spv::Op::OpSwitch) &&
"invalid control dependence; last instruction must be conditional "
"branch or switch");
return branch->GetSingleWordInOperand(0);

View File

@@ -18,19 +18,16 @@
#include "source/opt/ir_builder.h"
namespace {
// Indices of operands in SPIR-V instructions
static const int kImageSampleDrefIdInIdx = 2;
} // anonymous namespace
namespace spvtools {
namespace opt {
namespace {
// Indices of operands in SPIR-V instructions
constexpr int kImageSampleDrefIdInIdx = 2;
} // namespace
bool ConvertToHalfPass::IsArithmetic(Instruction* inst) {
return target_ops_core_.count(inst->opcode()) != 0 ||
(inst->opcode() == SpvOpExtInst &&
(inst->opcode() == spv::Op::OpExtInst &&
inst->GetSingleWordInOperand(0) ==
context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450() &&
target_ops_450_.count(inst->GetSingleWordInOperand(1)) != 0);
@@ -45,9 +42,11 @@ bool ConvertToHalfPass::IsFloat(Instruction* inst, uint32_t width) {
bool ConvertToHalfPass::IsDecoratedRelaxed(Instruction* inst) {
uint32_t r_id = inst->result_id();
for (auto r_inst : get_decoration_mgr()->GetDecorationsFor(r_id, false))
if (r_inst->opcode() == SpvOpDecorate &&
r_inst->GetSingleWordInOperand(1) == SpvDecorationRelaxedPrecision)
if (r_inst->opcode() == spv::Op::OpDecorate &&
spv::Decoration(r_inst->GetSingleWordInOperand(1)) ==
spv::Decoration::RelaxedPrecision) {
return true;
}
return false;
}
@@ -82,12 +81,12 @@ analysis::Type* ConvertToHalfPass::FloatMatrixType(uint32_t v_cnt,
uint32_t ConvertToHalfPass::EquivFloatTypeId(uint32_t ty_id, uint32_t width) {
analysis::Type* reg_equiv_ty;
Instruction* ty_inst = get_def_use_mgr()->GetDef(ty_id);
if (ty_inst->opcode() == SpvOpTypeMatrix)
if (ty_inst->opcode() == spv::Op::OpTypeMatrix)
reg_equiv_ty = FloatMatrixType(ty_inst->GetSingleWordInOperand(1),
ty_inst->GetSingleWordInOperand(0), width);
else if (ty_inst->opcode() == SpvOpTypeVector)
else if (ty_inst->opcode() == spv::Op::OpTypeVector)
reg_equiv_ty = FloatVectorType(ty_inst->GetSingleWordInOperand(1), width);
else // SpvOpTypeFloat
else // spv::Op::OpTypeFloat
reg_equiv_ty = FloatScalarType(width);
return context()->get_type_mgr()->GetTypeInstruction(reg_equiv_ty);
}
@@ -102,18 +101,18 @@ void ConvertToHalfPass::GenConvert(uint32_t* val_idp, uint32_t width,
InstructionBuilder builder(
context(), inst,
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
if (val_inst->opcode() == SpvOpUndef)
cvt_inst = builder.AddNullaryOp(nty_id, SpvOpUndef);
if (val_inst->opcode() == spv::Op::OpUndef)
cvt_inst = builder.AddNullaryOp(nty_id, spv::Op::OpUndef);
else
cvt_inst = builder.AddUnaryOp(nty_id, SpvOpFConvert, *val_idp);
cvt_inst = builder.AddUnaryOp(nty_id, spv::Op::OpFConvert, *val_idp);
*val_idp = cvt_inst->result_id();
}
bool ConvertToHalfPass::MatConvertCleanup(Instruction* inst) {
if (inst->opcode() != SpvOpFConvert) return false;
if (inst->opcode() != spv::Op::OpFConvert) return false;
uint32_t mty_id = inst->type_id();
Instruction* mty_inst = get_def_use_mgr()->GetDef(mty_id);
if (mty_inst->opcode() != SpvOpTypeMatrix) return false;
if (mty_inst->opcode() != spv::Op::OpTypeMatrix) return false;
uint32_t vty_id = mty_inst->GetSingleWordInOperand(0);
uint32_t v_cnt = mty_inst->GetSingleWordInOperand(1);
Instruction* vty_inst = get_def_use_mgr()->GetDef(vty_id);
@@ -130,18 +129,18 @@ bool ConvertToHalfPass::MatConvertCleanup(Instruction* inst) {
std::vector<Operand> opnds = {};
for (uint32_t vidx = 0; vidx < v_cnt; ++vidx) {
Instruction* ext_inst = builder.AddIdLiteralOp(
orig_vty_id, SpvOpCompositeExtract, orig_mat_id, vidx);
orig_vty_id, spv::Op::OpCompositeExtract, orig_mat_id, vidx);
Instruction* cvt_inst =
builder.AddUnaryOp(vty_id, SpvOpFConvert, ext_inst->result_id());
builder.AddUnaryOp(vty_id, spv::Op::OpFConvert, ext_inst->result_id());
opnds.push_back({SPV_OPERAND_TYPE_ID, {cvt_inst->result_id()}});
}
uint32_t mat_id = TakeNextId();
std::unique_ptr<Instruction> mat_inst(new Instruction(
context(), SpvOpCompositeConstruct, mty_id, mat_id, opnds));
context(), spv::Op::OpCompositeConstruct, mty_id, mat_id, opnds));
(void)builder.AddInstruction(std::move(mat_inst));
context()->ReplaceAllUsesWith(inst->result_id(), mat_id);
// Turn original instruction into copy so it is valid.
inst->SetOpcode(SpvOpCopyObject);
inst->SetOpcode(spv::Op::OpCopyObject);
inst->SetResultType(EquivFloatTypeId(mty_id, orig_width));
get_def_use_mgr()->AnalyzeInstUse(inst);
return true;
@@ -150,10 +149,11 @@ bool ConvertToHalfPass::MatConvertCleanup(Instruction* inst) {
bool ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
return context()->get_decoration_mgr()->RemoveDecorationsFrom(
id, [](const Instruction& dec) {
if (dec.opcode() == SpvOpDecorate &&
dec.GetSingleWordInOperand(1u) == SpvDecorationRelaxedPrecision)
if (dec.opcode() == spv::Op::OpDecorate &&
spv::Decoration(dec.GetSingleWordInOperand(1u)) ==
spv::Decoration::RelaxedPrecision) {
return true;
else
} else
return false;
});
}
@@ -196,8 +196,8 @@ bool ConvertToHalfPass::ProcessPhi(Instruction* inst, uint32_t from_width,
auto insert_before = bp->tail();
if (insert_before != bp->begin()) {
--insert_before;
if (insert_before->opcode() != SpvOpSelectionMerge &&
insert_before->opcode() != SpvOpLoopMerge)
if (insert_before->opcode() != spv::Op::OpSelectionMerge &&
insert_before->opcode() != spv::Op::OpLoopMerge)
++insert_before;
}
GenConvert(prev_idp, to_width, &*insert_before);
@@ -229,7 +229,8 @@ bool ConvertToHalfPass::ProcessConvert(Instruction* inst) {
// changed to half.
uint32_t val_id = inst->GetSingleWordInOperand(0);
Instruction* val_inst = get_def_use_mgr()->GetDef(val_id);
if (inst->type_id() == val_inst->type_id()) inst->SetOpcode(SpvOpCopyObject);
if (inst->type_id() == val_inst->type_id())
inst->SetOpcode(spv::Op::OpCopyObject);
return true; // modified
}
@@ -251,7 +252,7 @@ bool ConvertToHalfPass::ProcessImageRef(Instruction* inst) {
bool ConvertToHalfPass::ProcessDefault(Instruction* inst) {
// If non-relaxed instruction has changed operands, need to convert
// them back to float32
if (inst->opcode() == SpvOpPhi) return ProcessPhi(inst, 16u, 32u);
if (inst->opcode() == spv::Op::OpPhi) return ProcessPhi(inst, 16u, 32u);
bool modified = false;
inst->ForEachInId([&inst, &modified, this](uint32_t* idp) {
if (converted_ids_.count(*idp) == 0) return;
@@ -269,9 +270,9 @@ bool ConvertToHalfPass::GenHalfInst(Instruction* inst) {
bool inst_relaxed = IsRelaxed(inst->result_id());
if (IsArithmetic(inst) && inst_relaxed)
modified = GenHalfArith(inst);
else if (inst->opcode() == SpvOpPhi && inst_relaxed)
else if (inst->opcode() == spv::Op::OpPhi && inst_relaxed)
modified = ProcessPhi(inst, 32u, 16u);
else if (inst->opcode() == SpvOpFConvert)
else if (inst->opcode() == spv::Op::OpFConvert)
modified = ProcessConvert(inst);
else if (image_ops_.count(inst->opcode()) != 0)
modified = ProcessImageRef(inst);
@@ -350,7 +351,7 @@ Pass::Status ConvertToHalfPass::ProcessImpl() {
};
bool modified = context()->ProcessReachableCallTree(pfn);
// If modified, make sure module has Float16 capability
if (modified) context()->AddCapability(SpvCapabilityFloat16);
if (modified) context()->AddCapability(spv::Capability::Float16);
// Remove all RelaxedPrecision decorations from instructions and globals
for (auto c_id : relaxed_ids_set_) {
modified |= RemoveRelaxedDecoration(c_id);
@@ -371,44 +372,44 @@ Pass::Status ConvertToHalfPass::Process() {
void ConvertToHalfPass::Initialize() {
target_ops_core_ = {
SpvOpVectorExtractDynamic,
SpvOpVectorInsertDynamic,
SpvOpVectorShuffle,
SpvOpCompositeConstruct,
SpvOpCompositeInsert,
SpvOpCompositeExtract,
SpvOpCopyObject,
SpvOpTranspose,
SpvOpConvertSToF,
SpvOpConvertUToF,
// SpvOpFConvert,
// SpvOpQuantizeToF16,
SpvOpFNegate,
SpvOpFAdd,
SpvOpFSub,
SpvOpFMul,
SpvOpFDiv,
SpvOpFMod,
SpvOpVectorTimesScalar,
SpvOpMatrixTimesScalar,
SpvOpVectorTimesMatrix,
SpvOpMatrixTimesVector,
SpvOpMatrixTimesMatrix,
SpvOpOuterProduct,
SpvOpDot,
SpvOpSelect,
SpvOpFOrdEqual,
SpvOpFUnordEqual,
SpvOpFOrdNotEqual,
SpvOpFUnordNotEqual,
SpvOpFOrdLessThan,
SpvOpFUnordLessThan,
SpvOpFOrdGreaterThan,
SpvOpFUnordGreaterThan,
SpvOpFOrdLessThanEqual,
SpvOpFUnordLessThanEqual,
SpvOpFOrdGreaterThanEqual,
SpvOpFUnordGreaterThanEqual,
spv::Op::OpVectorExtractDynamic,
spv::Op::OpVectorInsertDynamic,
spv::Op::OpVectorShuffle,
spv::Op::OpCompositeConstruct,
spv::Op::OpCompositeInsert,
spv::Op::OpCompositeExtract,
spv::Op::OpCopyObject,
spv::Op::OpTranspose,
spv::Op::OpConvertSToF,
spv::Op::OpConvertUToF,
// spv::Op::OpFConvert,
// spv::Op::OpQuantizeToF16,
spv::Op::OpFNegate,
spv::Op::OpFAdd,
spv::Op::OpFSub,
spv::Op::OpFMul,
spv::Op::OpFDiv,
spv::Op::OpFMod,
spv::Op::OpVectorTimesScalar,
spv::Op::OpMatrixTimesScalar,
spv::Op::OpVectorTimesMatrix,
spv::Op::OpMatrixTimesVector,
spv::Op::OpMatrixTimesMatrix,
spv::Op::OpOuterProduct,
spv::Op::OpDot,
spv::Op::OpSelect,
spv::Op::OpFOrdEqual,
spv::Op::OpFUnordEqual,
spv::Op::OpFOrdNotEqual,
spv::Op::OpFUnordNotEqual,
spv::Op::OpFOrdLessThan,
spv::Op::OpFUnordLessThan,
spv::Op::OpFOrdGreaterThan,
spv::Op::OpFUnordGreaterThan,
spv::Op::OpFOrdLessThanEqual,
spv::Op::OpFUnordLessThanEqual,
spv::Op::OpFOrdGreaterThanEqual,
spv::Op::OpFUnordGreaterThanEqual,
};
target_ops_450_ = {
GLSLstd450Round, GLSLstd450RoundEven, GLSLstd450Trunc, GLSLstd450FAbs,
@@ -427,53 +428,53 @@ void ConvertToHalfPass::Initialize() {
GLSLstd450Ldexp, GLSLstd450Length, GLSLstd450Distance, GLSLstd450Cross,
GLSLstd450Normalize, GLSLstd450FaceForward, GLSLstd450Reflect,
GLSLstd450Refract, GLSLstd450NMin, GLSLstd450NMax, GLSLstd450NClamp};
image_ops_ = {SpvOpImageSampleImplicitLod,
SpvOpImageSampleExplicitLod,
SpvOpImageSampleDrefImplicitLod,
SpvOpImageSampleDrefExplicitLod,
SpvOpImageSampleProjImplicitLod,
SpvOpImageSampleProjExplicitLod,
SpvOpImageSampleProjDrefImplicitLod,
SpvOpImageSampleProjDrefExplicitLod,
SpvOpImageFetch,
SpvOpImageGather,
SpvOpImageDrefGather,
SpvOpImageRead,
SpvOpImageSparseSampleImplicitLod,
SpvOpImageSparseSampleExplicitLod,
SpvOpImageSparseSampleDrefImplicitLod,
SpvOpImageSparseSampleDrefExplicitLod,
SpvOpImageSparseSampleProjImplicitLod,
SpvOpImageSparseSampleProjExplicitLod,
SpvOpImageSparseSampleProjDrefImplicitLod,
SpvOpImageSparseSampleProjDrefExplicitLod,
SpvOpImageSparseFetch,
SpvOpImageSparseGather,
SpvOpImageSparseDrefGather,
SpvOpImageSparseTexelsResident,
SpvOpImageSparseRead};
image_ops_ = {spv::Op::OpImageSampleImplicitLod,
spv::Op::OpImageSampleExplicitLod,
spv::Op::OpImageSampleDrefImplicitLod,
spv::Op::OpImageSampleDrefExplicitLod,
spv::Op::OpImageSampleProjImplicitLod,
spv::Op::OpImageSampleProjExplicitLod,
spv::Op::OpImageSampleProjDrefImplicitLod,
spv::Op::OpImageSampleProjDrefExplicitLod,
spv::Op::OpImageFetch,
spv::Op::OpImageGather,
spv::Op::OpImageDrefGather,
spv::Op::OpImageRead,
spv::Op::OpImageSparseSampleImplicitLod,
spv::Op::OpImageSparseSampleExplicitLod,
spv::Op::OpImageSparseSampleDrefImplicitLod,
spv::Op::OpImageSparseSampleDrefExplicitLod,
spv::Op::OpImageSparseSampleProjImplicitLod,
spv::Op::OpImageSparseSampleProjExplicitLod,
spv::Op::OpImageSparseSampleProjDrefImplicitLod,
spv::Op::OpImageSparseSampleProjDrefExplicitLod,
spv::Op::OpImageSparseFetch,
spv::Op::OpImageSparseGather,
spv::Op::OpImageSparseDrefGather,
spv::Op::OpImageSparseTexelsResident,
spv::Op::OpImageSparseRead};
dref_image_ops_ = {
SpvOpImageSampleDrefImplicitLod,
SpvOpImageSampleDrefExplicitLod,
SpvOpImageSampleProjDrefImplicitLod,
SpvOpImageSampleProjDrefExplicitLod,
SpvOpImageDrefGather,
SpvOpImageSparseSampleDrefImplicitLod,
SpvOpImageSparseSampleDrefExplicitLod,
SpvOpImageSparseSampleProjDrefImplicitLod,
SpvOpImageSparseSampleProjDrefExplicitLod,
SpvOpImageSparseDrefGather,
spv::Op::OpImageSampleDrefImplicitLod,
spv::Op::OpImageSampleDrefExplicitLod,
spv::Op::OpImageSampleProjDrefImplicitLod,
spv::Op::OpImageSampleProjDrefExplicitLod,
spv::Op::OpImageDrefGather,
spv::Op::OpImageSparseSampleDrefImplicitLod,
spv::Op::OpImageSparseSampleDrefExplicitLod,
spv::Op::OpImageSparseSampleProjDrefImplicitLod,
spv::Op::OpImageSparseSampleProjDrefExplicitLod,
spv::Op::OpImageSparseDrefGather,
};
closure_ops_ = {
SpvOpVectorExtractDynamic,
SpvOpVectorInsertDynamic,
SpvOpVectorShuffle,
SpvOpCompositeConstruct,
SpvOpCompositeInsert,
SpvOpCompositeExtract,
SpvOpCopyObject,
SpvOpTranspose,
SpvOpPhi,
spv::Op::OpVectorExtractDynamic,
spv::Op::OpVectorInsertDynamic,
spv::Op::OpVectorShuffle,
spv::Op::OpCompositeConstruct,
spv::Op::OpCompositeInsert,
spv::Op::OpCompositeExtract,
spv::Op::OpCopyObject,
spv::Op::OpTranspose,
spv::Op::OpPhi,
};
relaxed_ids_set_.clear();
converted_ids_.clear();

View File

@@ -120,20 +120,26 @@ class ConvertToHalfPass : public Pass {
// Initialize state for converting to half
void Initialize();
struct hasher {
size_t operator()(const spv::Op& op) const noexcept {
return std::hash<uint32_t>()(uint32_t(op));
}
};
// Set of core operations to be processed
std::unordered_set<uint32_t> target_ops_core_;
std::unordered_set<spv::Op, hasher> target_ops_core_;
// Set of 450 extension operations to be processed
std::unordered_set<uint32_t> target_ops_450_;
// Set of sample operations
std::unordered_set<uint32_t> image_ops_;
std::unordered_set<spv::Op, hasher> image_ops_;
// Set of dref sample operations
std::unordered_set<uint32_t> dref_image_ops_;
std::unordered_set<spv::Op, hasher> dref_image_ops_;
// Set of dref sample operations
std::unordered_set<uint32_t> closure_ops_;
std::unordered_set<spv::Op, hasher> closure_ops_;
// Set of ids of all relaxed instructions
std::unordered_set<uint32_t> relaxed_ids_set_;

View File

@@ -70,7 +70,7 @@ uint32_t GetImageTypeOfSampledImage(analysis::TypeManager* type_mgr,
Instruction* GetNonCopyObjectDef(analysis::DefUseManager* def_use_mgr,
uint32_t inst_id) {
Instruction* inst = def_use_mgr->GetDef(inst_id);
while (inst->opcode() == SpvOpCopyObject) {
while (inst->opcode() == spv::Op::OpCopyObject) {
inst_id = inst->GetSingleWordInOperand(0u);
inst = def_use_mgr->GetDef(inst_id);
}
@@ -87,8 +87,9 @@ bool ConvertToSampledImagePass::GetDescriptorSetBinding(
bool found_binding_to_convert = false;
for (auto decorate :
decoration_manager->GetDecorationsFor(inst.result_id(), false)) {
uint32_t decoration = decorate->GetSingleWordInOperand(1u);
if (decoration == SpvDecorationDescriptorSet) {
spv::Decoration decoration =
spv::Decoration(decorate->GetSingleWordInOperand(1u));
if (decoration == spv::Decoration::DescriptorSet) {
if (found_descriptor_set_to_convert) {
assert(false && "A resource has two OpDecorate for the descriptor set");
return false;
@@ -96,7 +97,7 @@ bool ConvertToSampledImagePass::GetDescriptorSetBinding(
descriptor_set_binding->descriptor_set =
decorate->GetSingleWordInOperand(2u);
found_descriptor_set_to_convert = true;
} else if (decoration == SpvDecorationBinding) {
} else if (decoration == spv::Decoration::Binding) {
if (found_binding_to_convert) {
assert(false && "A resource has two OpDecorate for the binding");
return false;
@@ -116,7 +117,7 @@ bool ConvertToSampledImagePass::ShouldResourceBeConverted(
const analysis::Type* ConvertToSampledImagePass::GetVariableType(
const Instruction& variable) const {
if (variable.opcode() != SpvOpVariable) return nullptr;
if (variable.opcode() != spv::Op::OpVariable) return nullptr;
auto* type = context()->get_type_mgr()->GetType(variable.type_id());
auto* pointer_type = type->AsPointer();
if (!pointer_type) return nullptr;
@@ -124,12 +125,12 @@ const analysis::Type* ConvertToSampledImagePass::GetVariableType(
return pointer_type->pointee_type();
}
SpvStorageClass ConvertToSampledImagePass::GetStorageClass(
spv::StorageClass ConvertToSampledImagePass::GetStorageClass(
const Instruction& variable) const {
assert(variable.opcode() == SpvOpVariable);
assert(variable.opcode() == spv::Op::OpVariable);
auto* type = context()->get_type_mgr()->GetType(variable.type_id());
auto* pointer_type = type->AsPointer();
if (!pointer_type) return SpvStorageClassMax;
if (!pointer_type) return spv::StorageClass::Max;
return pointer_type->storage_class();
}
@@ -205,12 +206,12 @@ Pass::Status ConvertToSampledImagePass::Process() {
void ConvertToSampledImagePass::FindUses(const Instruction* inst,
std::vector<Instruction*>* uses,
uint32_t user_opcode) const {
spv::Op user_opcode) const {
auto* def_use_mgr = context()->get_def_use_mgr();
def_use_mgr->ForEachUser(inst, [uses, user_opcode, this](Instruction* user) {
if (user->opcode() == user_opcode) {
uses->push_back(user);
} else if (user->opcode() == SpvOpCopyObject) {
} else if (user->opcode() == spv::Op::OpCopyObject) {
FindUses(user, uses, user_opcode);
}
});
@@ -221,21 +222,21 @@ void ConvertToSampledImagePass::FindUsesOfImage(
auto* def_use_mgr = context()->get_def_use_mgr();
def_use_mgr->ForEachUser(image, [uses, this](Instruction* user) {
switch (user->opcode()) {
case SpvOpImageFetch:
case SpvOpImageRead:
case SpvOpImageWrite:
case SpvOpImageQueryFormat:
case SpvOpImageQueryOrder:
case SpvOpImageQuerySizeLod:
case SpvOpImageQuerySize:
case SpvOpImageQueryLevels:
case SpvOpImageQuerySamples:
case SpvOpImageSparseFetch:
case spv::Op::OpImageFetch:
case spv::Op::OpImageRead:
case spv::Op::OpImageWrite:
case spv::Op::OpImageQueryFormat:
case spv::Op::OpImageQueryOrder:
case spv::Op::OpImageQuerySizeLod:
case spv::Op::OpImageQuerySize:
case spv::Op::OpImageQueryLevels:
case spv::Op::OpImageQuerySamples:
case spv::Op::OpImageSparseFetch:
uses->push_back(user);
default:
break;
}
if (user->opcode() == SpvOpCopyObject) {
if (user->opcode() == spv::Op::OpCopyObject) {
FindUsesOfImage(user, uses);
}
});
@@ -248,7 +249,7 @@ Instruction* ConvertToSampledImagePass::CreateImageExtraction(
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
return builder.AddUnaryOp(
GetImageTypeOfSampledImage(context()->get_type_mgr(), sampled_image),
SpvOpImage, sampled_image->result_id());
spv::Op::OpImage, sampled_image->result_id());
}
uint32_t ConvertToSampledImagePass::GetSampledImageTypeForImage(
@@ -284,7 +285,7 @@ bool ConvertToSampledImagePass::
auto* def_use_mgr = context()->get_def_use_mgr();
uint32_t sampler_id = sampled_image_inst->GetSingleWordInOperand(1u);
auto* sampler_load = def_use_mgr->GetDef(sampler_id);
if (sampler_load->opcode() != SpvOpLoad) return false;
if (sampler_load->opcode() != spv::Op::OpLoad) return false;
auto* sampler = def_use_mgr->GetDef(sampler_load->GetSingleWordInOperand(0u));
DescriptorSetAndBinding sampler_descriptor_set_binding;
return GetDescriptorSetBinding(*sampler, &sampler_descriptor_set_binding) &&
@@ -295,7 +296,7 @@ void ConvertToSampledImagePass::UpdateSampledImageUses(
Instruction* image_load, Instruction* image_extraction,
const DescriptorSetAndBinding& image_descriptor_set_binding) {
std::vector<Instruction*> sampled_image_users;
FindUses(image_load, &sampled_image_users, SpvOpSampledImage);
FindUses(image_load, &sampled_image_users, spv::Op::OpSampledImage);
auto* def_use_mgr = context()->get_def_use_mgr();
for (auto* sampled_image_inst : sampled_image_users) {
@@ -328,7 +329,7 @@ bool ConvertToSampledImagePass::ConvertImageVariableToSampledImage(
context()->get_type_mgr()->GetType(sampled_image_type_id);
if (sampled_image_type == nullptr) return false;
auto storage_class = GetStorageClass(*image_variable);
if (storage_class == SpvStorageClassMax) return false;
if (storage_class == spv::StorageClass::Max) return false;
analysis::Pointer sampled_image_pointer(sampled_image_type, storage_class);
// Make sure |image_variable| is behind its type i.e., avoid the forward
@@ -343,7 +344,7 @@ Pass::Status ConvertToSampledImagePass::UpdateImageVariableToSampledImage(
Instruction* image_variable,
const DescriptorSetAndBinding& descriptor_set_binding) {
std::vector<Instruction*> image_variable_loads;
FindUses(image_variable, &image_variable_loads, SpvOpLoad);
FindUses(image_variable, &image_variable_loads, spv::Op::OpLoad);
if (image_variable_loads.empty()) return Status::SuccessWithoutChange;
const uint32_t sampled_image_type_id =
@@ -364,14 +365,14 @@ Pass::Status ConvertToSampledImagePass::UpdateImageVariableToSampledImage(
bool ConvertToSampledImagePass::DoesSampledImageReferenceImage(
Instruction* sampled_image_inst, Instruction* image_variable) {
if (sampled_image_inst->opcode() != SpvOpSampledImage) return false;
if (sampled_image_inst->opcode() != spv::Op::OpSampledImage) return false;
auto* def_use_mgr = context()->get_def_use_mgr();
auto* image_load = GetNonCopyObjectDef(
def_use_mgr, sampled_image_inst->GetSingleWordInOperand(0u));
if (image_load->opcode() != SpvOpLoad) return false;
if (image_load->opcode() != spv::Op::OpLoad) return false;
auto* image =
GetNonCopyObjectDef(def_use_mgr, image_load->GetSingleWordInOperand(0u));
return image->opcode() == SpvOpVariable &&
return image->opcode() == spv::Op::OpVariable &&
image->result_id() == image_variable->result_id();
}
@@ -381,10 +382,10 @@ Pass::Status ConvertToSampledImagePass::CheckUsesOfSamplerVariable(
if (image_to_be_combined_with == nullptr) return Status::Failure;
std::vector<Instruction*> sampler_variable_loads;
FindUses(sampler_variable, &sampler_variable_loads, SpvOpLoad);
FindUses(sampler_variable, &sampler_variable_loads, spv::Op::OpLoad);
for (auto* load : sampler_variable_loads) {
std::vector<Instruction*> sampled_image_users;
FindUses(load, &sampled_image_users, SpvOpSampledImage);
FindUses(load, &sampled_image_users, spv::Op::OpSampledImage);
for (auto* sampled_image_inst : sampled_image_users) {
if (!DoesSampledImageReferenceImage(sampled_image_inst,
image_to_be_combined_with)) {

View File

@@ -120,13 +120,13 @@ class ConvertToSampledImagePass : public Pass {
const analysis::Type* GetVariableType(const Instruction& variable) const;
// Returns the storage class of |variable|.
SpvStorageClass GetStorageClass(const Instruction& variable) const;
spv::StorageClass GetStorageClass(const Instruction& variable) const;
// Finds |inst|'s users whose opcode is |user_opcode| or users of OpCopyObject
// instructions of |inst| whose opcode is |user_opcode| and puts them in
// |uses|.
void FindUses(const Instruction* inst, std::vector<Instruction*>* uses,
uint32_t user_opcode) const;
spv::Op user_opcode) const;
// Finds OpImage* instructions using |image| or OpCopyObject instructions that
// copy |image| and puts them in |uses|.

View File

@@ -22,12 +22,12 @@ namespace spvtools {
namespace opt {
namespace {
const uint32_t kLoadPointerInOperand = 0;
const uint32_t kStorePointerInOperand = 0;
const uint32_t kStoreObjectInOperand = 1;
const uint32_t kCompositeExtractObjectInOperand = 0;
const uint32_t kTypePointerStorageClassInIdx = 0;
const uint32_t kTypePointerPointeeInIdx = 1;
constexpr uint32_t kLoadPointerInOperand = 0;
constexpr uint32_t kStorePointerInOperand = 0;
constexpr uint32_t kStoreObjectInOperand = 1;
constexpr uint32_t kCompositeExtractObjectInOperand = 0;
constexpr uint32_t kTypePointerStorageClassInIdx = 0;
constexpr uint32_t kTypePointerPointeeInIdx = 1;
bool IsDebugDeclareOrValue(Instruction* di) {
auto dbg_opcode = di->GetCommonDebugOpcode();
@@ -46,8 +46,8 @@ Pass::Status CopyPropagateArrays::Process() {
BasicBlock* entry_bb = &*function.begin();
for (auto var_inst = entry_bb->begin(); var_inst->opcode() == SpvOpVariable;
++var_inst) {
for (auto var_inst = entry_bb->begin();
var_inst->opcode() == spv::Op::OpVariable; ++var_inst) {
if (!IsPointerToArrayType(var_inst->type_id())) {
continue;
}
@@ -76,7 +76,7 @@ Pass::Status CopyPropagateArrays::Process() {
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::FindSourceObjectIfPossible(Instruction* var_inst,
Instruction* store_inst) {
assert(var_inst->opcode() == SpvOpVariable && "Expecting a variable.");
assert(var_inst->opcode() == spv::Op::OpVariable && "Expecting a variable.");
// Check that the variable is a composite object where |store_inst|
// dominates all of its loads.
@@ -114,7 +114,7 @@ Instruction* CopyPropagateArrays::FindStoreInstruction(
Instruction* store_inst = nullptr;
get_def_use_mgr()->WhileEachUser(
var_inst, [&store_inst, var_inst](Instruction* use) {
if (use->opcode() == SpvOpStore &&
if (use->opcode() == spv::Op::OpStore &&
use->GetSingleWordInOperand(kStorePointerInOperand) ==
var_inst->result_id()) {
if (store_inst == nullptr) {
@@ -132,7 +132,7 @@ Instruction* CopyPropagateArrays::FindStoreInstruction(
void CopyPropagateArrays::PropagateObject(Instruction* var_inst,
MemoryObject* source,
Instruction* insertion_point) {
assert(var_inst->opcode() == SpvOpVariable &&
assert(var_inst->opcode() == spv::Op::OpVariable &&
"This function propagates variables.");
Instruction* new_access_chain = BuildNewAccessChain(insertion_point, source);
@@ -166,17 +166,17 @@ Instruction* CopyPropagateArrays::BuildNewAccessChain(
bool CopyPropagateArrays::HasNoStores(Instruction* ptr_inst) {
return get_def_use_mgr()->WhileEachUser(ptr_inst, [this](Instruction* use) {
if (use->opcode() == SpvOpLoad) {
if (use->opcode() == spv::Op::OpLoad) {
return true;
} else if (use->opcode() == SpvOpAccessChain) {
} else if (use->opcode() == spv::Op::OpAccessChain) {
return HasNoStores(use);
} else if (use->IsDecoration() || use->opcode() == SpvOpName) {
} else if (use->IsDecoration() || use->opcode() == spv::Op::OpName) {
return true;
} else if (use->opcode() == SpvOpStore) {
} else if (use->opcode() == spv::Op::OpStore) {
return false;
} else if (use->opcode() == SpvOpImageTexelPointer) {
} else if (use->opcode() == spv::Op::OpImageTexelPointer) {
return true;
} else if (use->opcode() == SpvOpEntryPoint) {
} else if (use->opcode() == spv::Op::OpEntryPoint) {
return true;
}
// Some other instruction. Be conservative.
@@ -193,19 +193,19 @@ bool CopyPropagateArrays::HasValidReferencesOnly(Instruction* ptr_inst,
return get_def_use_mgr()->WhileEachUser(
ptr_inst,
[this, store_inst, dominator_analysis, ptr_inst](Instruction* use) {
if (use->opcode() == SpvOpLoad ||
use->opcode() == SpvOpImageTexelPointer) {
if (use->opcode() == spv::Op::OpLoad ||
use->opcode() == spv::Op::OpImageTexelPointer) {
// TODO: If there are many load in the same BB as |store_inst| the
// time to do the multiple traverses can add up. Consider collecting
// those loads and doing a single traversal.
return dominator_analysis->Dominates(store_inst, use);
} else if (use->opcode() == SpvOpAccessChain) {
} else if (use->opcode() == spv::Op::OpAccessChain) {
return HasValidReferencesOnly(use, store_inst);
} else if (use->IsDecoration() || use->opcode() == SpvOpName) {
} else if (use->IsDecoration() || use->opcode() == spv::Op::OpName) {
return true;
} else if (use->opcode() == SpvOpStore) {
} else if (use->opcode() == spv::Op::OpStore) {
// If we are storing to part of the object it is not an candidate.
return ptr_inst->opcode() == SpvOpVariable &&
return ptr_inst->opcode() == spv::Op::OpVariable &&
store_inst->GetSingleWordInOperand(kStorePointerInOperand) ==
ptr_inst->result_id();
} else if (IsDebugDeclareOrValue(use)) {
@@ -221,15 +221,15 @@ CopyPropagateArrays::GetSourceObjectIfAny(uint32_t result) {
Instruction* result_inst = context()->get_def_use_mgr()->GetDef(result);
switch (result_inst->opcode()) {
case SpvOpLoad:
case spv::Op::OpLoad:
return BuildMemoryObjectFromLoad(result_inst);
case SpvOpCompositeExtract:
case spv::Op::OpCompositeExtract:
return BuildMemoryObjectFromExtract(result_inst);
case SpvOpCompositeConstruct:
case spv::Op::OpCompositeConstruct:
return BuildMemoryObjectFromCompositeConstruct(result_inst);
case SpvOpCopyObject:
case spv::Op::OpCopyObject:
return GetSourceObjectIfAny(result_inst->GetSingleWordInOperand(0));
case SpvOpCompositeInsert:
case spv::Op::OpCompositeInsert:
return BuildMemoryObjectFromInsert(result_inst);
default:
return nullptr;
@@ -251,7 +251,7 @@ CopyPropagateArrays::BuildMemoryObjectFromLoad(Instruction* load_inst) {
//
// It is built in reverse order because the different |OpAccessChain|
// instructions are visited in reverse order from which they are applied.
while (current_inst->opcode() == SpvOpAccessChain) {
while (current_inst->opcode() == spv::Op::OpAccessChain) {
for (uint32_t i = current_inst->NumInOperands() - 1; i >= 1; --i) {
uint32_t element_index_id = current_inst->GetSingleWordInOperand(i);
components_in_reverse.push_back(element_index_id);
@@ -263,7 +263,7 @@ CopyPropagateArrays::BuildMemoryObjectFromLoad(Instruction* load_inst) {
// instruction followed by a series of |OpAccessChain| instructions, then
// return |nullptr| because we cannot identify the owner or access chain
// exactly.
if (current_inst->opcode() != SpvOpVariable) {
if (current_inst->opcode() != spv::Op::OpVariable) {
return nullptr;
}
@@ -276,7 +276,7 @@ CopyPropagateArrays::BuildMemoryObjectFromLoad(Instruction* load_inst) {
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::BuildMemoryObjectFromExtract(Instruction* extract_inst) {
assert(extract_inst->opcode() == SpvOpCompositeExtract &&
assert(extract_inst->opcode() == spv::Op::OpCompositeExtract &&
"Expecting an OpCompositeExtract instruction.");
std::unique_ptr<MemoryObject> result = GetSourceObjectIfAny(
extract_inst->GetSingleWordInOperand(kCompositeExtractObjectInOperand));
@@ -297,7 +297,7 @@ CopyPropagateArrays::BuildMemoryObjectFromExtract(Instruction* extract_inst) {
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::BuildMemoryObjectFromCompositeConstruct(
Instruction* conststruct_inst) {
assert(conststruct_inst->opcode() == SpvOpCompositeConstruct &&
assert(conststruct_inst->opcode() == spv::Op::OpCompositeConstruct &&
"Expecting an OpCompositeConstruct instruction.");
// If every operand in the instruction are part of the same memory object, and
@@ -352,7 +352,7 @@ CopyPropagateArrays::BuildMemoryObjectFromCompositeConstruct(
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::BuildMemoryObjectFromInsert(Instruction* insert_inst) {
assert(insert_inst->opcode() == SpvOpCompositeInsert &&
assert(insert_inst->opcode() == spv::Op::OpCompositeInsert &&
"Expecting an OpCompositeInsert instruction.");
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
@@ -407,7 +407,7 @@ CopyPropagateArrays::BuildMemoryObjectFromInsert(Instruction* insert_inst) {
Instruction* current_insert =
def_use_mgr->GetDef(insert_inst->GetSingleWordInOperand(1));
for (uint32_t i = number_of_elements - 1; i > 0; --i) {
if (current_insert->opcode() != SpvOpCompositeInsert) {
if (current_insert->opcode() != spv::Op::OpCompositeInsert) {
return nullptr;
}
@@ -500,7 +500,7 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
if (IsDebugDeclareOrValue(use)) return true;
switch (use->opcode()) {
case SpvOpLoad: {
case spv::Op::OpLoad: {
analysis::Pointer* pointer_type = type->AsPointer();
uint32_t new_type_id = type_mgr->GetId(pointer_type->pointee_type());
@@ -509,7 +509,7 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
}
return true;
}
case SpvOpAccessChain: {
case spv::Op::OpAccessChain: {
analysis::Pointer* pointer_type = type->AsPointer();
const analysis::Type* pointee_type = pointer_type->pointee_type();
@@ -547,7 +547,7 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
}
return true;
}
case SpvOpCompositeExtract: {
case spv::Op::OpCompositeExtract: {
std::vector<uint32_t> access_chain;
for (uint32_t i = 1; i < use->NumInOperands(); ++i) {
access_chain.push_back(use->GetSingleWordInOperand(i));
@@ -565,13 +565,13 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
}
return true;
}
case SpvOpStore:
case spv::Op::OpStore:
// If needed, we can create an element-by-element copy to change the
// type of the value being stored. This way we can always handled
// stores.
return true;
case SpvOpImageTexelPointer:
case SpvOpName:
case spv::Op::OpImageTexelPointer:
case spv::Op::OpName:
return true;
default:
return use->IsDecoration();
@@ -598,8 +598,8 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
if (use->IsCommonDebugInstr()) {
switch (use->GetCommonDebugOpcode()) {
case CommonDebugInfoDebugDeclare: {
if (new_ptr_inst->opcode() == SpvOpVariable ||
new_ptr_inst->opcode() == SpvOpFunctionParameter) {
if (new_ptr_inst->opcode() == spv::Op::OpVariable ||
new_ptr_inst->opcode() == spv::Op::OpFunctionParameter) {
context()->ForgetUses(use);
use->SetOperand(index, {new_ptr_inst->result_id()});
context()->AnalyzeUses(use);
@@ -640,7 +640,7 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
}
switch (use->opcode()) {
case SpvOpLoad: {
case spv::Op::OpLoad: {
// Replace the actual use.
context()->ForgetUses(use);
use->SetOperand(index, {new_ptr_inst->result_id()});
@@ -658,7 +658,7 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
context()->AnalyzeUses(use);
}
} break;
case SpvOpAccessChain: {
case spv::Op::OpAccessChain: {
// Update the actual use.
context()->ForgetUses(use);
use->SetOperand(index, {new_ptr_inst->result_id()});
@@ -685,7 +685,7 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
pointer_type_inst->GetSingleWordInOperand(kTypePointerPointeeInIdx),
access_chain);
SpvStorageClass storage_class = static_cast<SpvStorageClass>(
spv::StorageClass storage_class = static_cast<spv::StorageClass>(
pointer_type_inst->GetSingleWordInOperand(
kTypePointerStorageClassInIdx));
@@ -700,7 +700,7 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
context()->AnalyzeUses(use);
}
} break;
case SpvOpCompositeExtract: {
case spv::Op::OpCompositeExtract: {
// Update the actual use.
context()->ForgetUses(use);
use->SetOperand(index, {new_ptr_inst->result_id()});
@@ -721,7 +721,7 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
context()->AnalyzeUses(use);
}
} break;
case SpvOpStore:
case spv::Op::OpStore:
// If the use is the pointer, then it is the single store to that
// variable. We do not want to replace it. Instead, it will become
// dead after all of the loads are removed, and ADCE will get rid of it.
@@ -744,11 +744,11 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
context()->AnalyzeUses(use);
}
break;
case SpvOpDecorate:
case spv::Op::OpDecorate:
// We treat an OpImageTexelPointer as a load. The result type should
// always have the Image storage class, and should not need to be
// updated.
case SpvOpImageTexelPointer:
case spv::Op::OpImageTexelPointer:
// Replace the actual use.
context()->ForgetUses(use);
use->SetOperand(index, {new_ptr_inst->result_id()});
@@ -766,13 +766,13 @@ uint32_t CopyPropagateArrays::GetMemberTypeId(
for (uint32_t element_index : access_chain) {
Instruction* type_inst = get_def_use_mgr()->GetDef(id);
switch (type_inst->opcode()) {
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeMatrix:
case SpvOpTypeVector:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeVector:
id = type_inst->GetSingleWordInOperand(0);
break;
case SpvOpTypeStruct:
case spv::Op::OpTypeStruct:
id = type_inst->GetSingleWordInOperand(element_index);
break;
default:

View File

@@ -134,13 +134,13 @@ class CopyPropagateArrays : public MemPass {
var_pointer_inst->GetSingleWordInOperand(1), GetAccessIds());
uint32_t member_pointer_type_id = type_mgr->FindPointerToType(
member_type_id, static_cast<SpvStorageClass>(
member_type_id, static_cast<spv::StorageClass>(
var_pointer_inst->GetSingleWordInOperand(0)));
return member_pointer_type_id;
}
// Returns the storage class of the memory object.
SpvStorageClass GetStorageClass() const {
spv::StorageClass GetStorageClass() const {
analysis::TypeManager* type_mgr =
GetVariable()->context()->get_type_mgr();
const analysis::Pointer* pointer_type =

View File

@@ -78,7 +78,7 @@ void ForwardDataFlowAnalysis::EnqueueUsers(Instruction* inst) {
}
void ForwardDataFlowAnalysis::EnqueueBlockSuccessors(Instruction* inst) {
if (inst->opcode() != SpvOpLabel) return;
if (inst->opcode() != spv::Op::OpLabel) return;
context()
.cfg()
->block(inst->result_id())

View File

@@ -29,28 +29,25 @@
namespace spvtools {
namespace opt {
namespace {
const uint32_t kBranchCondTrueLabIdInIdx = 1;
const uint32_t kBranchCondFalseLabIdInIdx = 2;
} // anonymous namespace
constexpr uint32_t kBranchCondTrueLabIdInIdx = 1;
constexpr uint32_t kBranchCondFalseLabIdInIdx = 2;
} // namespace
bool DeadBranchElimPass::GetConstCondition(uint32_t condId, bool* condVal) {
bool condIsConst;
Instruction* cInst = get_def_use_mgr()->GetDef(condId);
switch (cInst->opcode()) {
case SpvOpConstantNull:
case SpvOpConstantFalse: {
case spv::Op::OpConstantNull:
case spv::Op::OpConstantFalse: {
*condVal = false;
condIsConst = true;
} break;
case SpvOpConstantTrue: {
case spv::Op::OpConstantTrue: {
*condVal = true;
condIsConst = true;
} break;
case SpvOpLogicalNot: {
case spv::Op::OpLogicalNot: {
bool negVal;
condIsConst =
GetConstCondition(cInst->GetSingleWordInOperand(0), &negVal);
@@ -65,13 +62,13 @@ bool DeadBranchElimPass::GetConstInteger(uint32_t selId, uint32_t* selVal) {
Instruction* sInst = get_def_use_mgr()->GetDef(selId);
uint32_t typeId = sInst->type_id();
Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
if (!typeInst || (typeInst->opcode() != SpvOpTypeInt)) return false;
if (!typeInst || (typeInst->opcode() != spv::Op::OpTypeInt)) return false;
// TODO(greg-lunarg): Support non-32 bit ints
if (typeInst->GetSingleWordInOperand(0) != 32) return false;
if (sInst->opcode() == SpvOpConstant) {
if (sInst->opcode() == spv::Op::OpConstant) {
*selVal = sInst->GetSingleWordInOperand(0);
return true;
} else if (sInst->opcode() == SpvOpConstantNull) {
} else if (sInst->opcode() == spv::Op::OpConstantNull) {
*selVal = 0;
return true;
}
@@ -81,7 +78,7 @@ bool DeadBranchElimPass::GetConstInteger(uint32_t selId, uint32_t* selVal) {
void DeadBranchElimPass::AddBranch(uint32_t labelId, BasicBlock* bp) {
assert(get_def_use_mgr()->GetDef(labelId) != nullptr);
std::unique_ptr<Instruction> newBranch(
new Instruction(context(), SpvOpBranch, 0, 0,
new Instruction(context(), spv::Op::OpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
context()->AnalyzeDefUse(&*newBranch);
context()->set_instr_block(&*newBranch, bp);
@@ -115,13 +112,13 @@ bool DeadBranchElimPass::MarkLiveBlocks(
Instruction* terminator = block->terminator();
uint32_t live_lab_id = 0;
// Check if the terminator has a single valid successor.
if (terminator->opcode() == SpvOpBranchConditional) {
if (terminator->opcode() == spv::Op::OpBranchConditional) {
bool condVal;
if (GetConstCondition(terminator->GetSingleWordInOperand(0u), &condVal)) {
live_lab_id = terminator->GetSingleWordInOperand(
condVal ? kBranchCondTrueLabIdInIdx : kBranchCondFalseLabIdInIdx);
}
} else if (terminator->opcode() == SpvOpSwitch) {
} else if (terminator->opcode() == spv::Op::OpSwitch) {
uint32_t sel_val;
if (GetConstInteger(terminator->GetSingleWordInOperand(0u), &sel_val)) {
// Search switch operands for selector value, set live_lab_id to
@@ -194,8 +191,8 @@ bool DeadBranchElimPass::SimplifyBranch(BasicBlock* block,
uint32_t live_lab_id) {
Instruction* merge_inst = block->GetMergeInst();
Instruction* terminator = block->terminator();
if (merge_inst && merge_inst->opcode() == SpvOpSelectionMerge) {
if (merge_inst->NextNode()->opcode() == SpvOpSwitch &&
if (merge_inst && merge_inst->opcode() == spv::Op::OpSelectionMerge) {
if (merge_inst->NextNode()->opcode() == spv::Op::OpSwitch &&
SwitchHasNestedBreak(block->id())) {
if (terminator->NumInOperands() == 2) {
// We cannot remove the branch, and it already has a single case, so no
@@ -266,7 +263,7 @@ bool DeadBranchElimPass::FixPhiNodesInLiveBlocks(
for (auto& block : *func) {
if (live_blocks.count(&block)) {
for (auto iter = block.begin(); iter != block.end();) {
if (iter->opcode() != SpvOpPhi) {
if (iter->opcode() != spv::Op::OpPhi) {
break;
}
@@ -292,7 +289,7 @@ bool DeadBranchElimPass::FixPhiNodesInLiveBlocks(
cont_iter->second == &block && inst->NumInOperands() > 4) {
if (get_def_use_mgr()
->GetDef(inst->GetSingleWordInOperand(i - 1))
->opcode() == SpvOpUndef) {
->opcode() == spv::Op::OpUndef) {
// Already undef incoming value, no change necessary.
operands.push_back(inst->GetInOperand(i - 1));
operands.push_back(inst->GetInOperand(i));
@@ -378,14 +375,14 @@ bool DeadBranchElimPass::EraseDeadBlocks(
if (unreachable_continues.count(&*ebi)) {
uint32_t cont_id = unreachable_continues.find(&*ebi)->second->id();
if (ebi->begin() != ebi->tail() ||
ebi->terminator()->opcode() != SpvOpBranch ||
ebi->terminator()->opcode() != spv::Op::OpBranch ||
ebi->terminator()->GetSingleWordInOperand(0u) != cont_id) {
// Make unreachable, but leave the label.
KillAllInsts(&*ebi, false);
// Add unconditional branch to header.
assert(unreachable_continues.count(&*ebi));
ebi->AddInstruction(MakeUnique<Instruction>(
context(), SpvOpBranch, 0, 0,
context(), spv::Op::OpBranch, 0, 0,
std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {cont_id}}}));
get_def_use_mgr()->AnalyzeInstUse(&*ebi->tail());
context()->set_instr_block(&*ebi->tail(), &*ebi);
@@ -394,12 +391,12 @@ bool DeadBranchElimPass::EraseDeadBlocks(
++ebi;
} else if (unreachable_merges.count(&*ebi)) {
if (ebi->begin() != ebi->tail() ||
ebi->terminator()->opcode() != SpvOpUnreachable) {
ebi->terminator()->opcode() != spv::Op::OpUnreachable) {
// Make unreachable, but leave the label.
KillAllInsts(&*ebi, false);
// Add unreachable terminator.
ebi->AddInstruction(
MakeUnique<Instruction>(context(), SpvOpUnreachable, 0, 0,
MakeUnique<Instruction>(context(), spv::Op::OpUnreachable, 0, 0,
std::initializer_list<Operand>{}));
context()->AnalyzeUses(ebi->terminator());
context()->set_instr_block(ebi->terminator(), &*ebi);
@@ -465,7 +462,7 @@ void DeadBranchElimPass::FixBlockOrder() {
};
// Structured order is more intuitive so use it where possible.
if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) {
if (context()->get_feature_mgr()->HasCapability(spv::Capability::Shader)) {
context()->ProcessReachableCallTree(reorder_structured);
} else {
context()->ProcessReachableCallTree(reorder_dominators);
@@ -477,7 +474,8 @@ Pass::Status DeadBranchElimPass::Process() {
// support required in KillNamesAndDecorates().
// TODO(greg-lunarg): Add support for OpGroupDecorate
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
if (ai.opcode() == spv::Op::OpGroupDecorate)
return Status::SuccessWithoutChange;
// Process all entry point functions
ProcessFunction pfn = [this](Function* fp) {
return EliminateDeadBranches(fp);
@@ -501,7 +499,7 @@ Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge(
Instruction* branch = start_block->terminator();
uint32_t next_block_id = 0;
switch (branch->opcode()) {
case SpvOpBranchConditional:
case spv::Op::OpBranchConditional:
next_block_id = start_block->MergeBlockIdIfAny();
if (next_block_id == 0) {
// If a possible target is the |loop_merge_id| or |loop_continue_id|,
@@ -530,7 +528,7 @@ Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge(
}
}
break;
case SpvOpSwitch:
case spv::Op::OpSwitch:
next_block_id = start_block->MergeBlockIdIfAny();
if (next_block_id == 0) {
// A switch with no merge instructions can have at most 5 targets:
@@ -578,7 +576,7 @@ Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge(
// The fall through is case 3.
}
break;
case SpvOpBranch:
case spv::Op::OpBranch:
// Need to check if this is the header of a loop nested in the
// selection construct.
next_block_id = start_block->MergeBlockIdIfAny();

View File

@@ -23,32 +23,29 @@
namespace spvtools {
namespace opt {
namespace {
const uint32_t kTypeVectorCountInIdx = 1;
const uint32_t kTypeMatrixCountInIdx = 1;
const uint32_t kTypeArrayLengthIdInIdx = 1;
const uint32_t kTypeIntWidthInIdx = 0;
const uint32_t kConstantValueInIdx = 0;
const uint32_t kInsertObjectIdInIdx = 0;
const uint32_t kInsertCompositeIdInIdx = 1;
} // anonymous namespace
constexpr uint32_t kTypeVectorCountInIdx = 1;
constexpr uint32_t kTypeMatrixCountInIdx = 1;
constexpr uint32_t kTypeArrayLengthIdInIdx = 1;
constexpr uint32_t kTypeIntWidthInIdx = 0;
constexpr uint32_t kConstantValueInIdx = 0;
constexpr uint32_t kInsertObjectIdInIdx = 0;
constexpr uint32_t kInsertCompositeIdInIdx = 1;
} // namespace
uint32_t DeadInsertElimPass::NumComponents(Instruction* typeInst) {
switch (typeInst->opcode()) {
case SpvOpTypeVector: {
case spv::Op::OpTypeVector: {
return typeInst->GetSingleWordInOperand(kTypeVectorCountInIdx);
} break;
case SpvOpTypeMatrix: {
case spv::Op::OpTypeMatrix: {
return typeInst->GetSingleWordInOperand(kTypeMatrixCountInIdx);
} break;
case SpvOpTypeArray: {
case spv::Op::OpTypeArray: {
uint32_t lenId =
typeInst->GetSingleWordInOperand(kTypeArrayLengthIdInIdx);
Instruction* lenInst = get_def_use_mgr()->GetDef(lenId);
if (lenInst->opcode() != SpvOpConstant) return 0;
if (lenInst->opcode() != spv::Op::OpConstant) return 0;
uint32_t lenTypeId = lenInst->type_id();
Instruction* lenTypeInst = get_def_use_mgr()->GetDef(lenTypeId);
// TODO(greg-lunarg): Support non-32-bit array length
@@ -56,7 +53,7 @@ uint32_t DeadInsertElimPass::NumComponents(Instruction* typeInst) {
return 0;
return lenInst->GetSingleWordInOperand(kConstantValueInIdx);
} break;
case SpvOpTypeStruct: {
case spv::Op::OpTypeStruct: {
return typeInst->NumInOperands();
} break;
default: { return 0; } break;
@@ -68,10 +65,10 @@ void DeadInsertElimPass::MarkInsertChain(
uint32_t extOffset, std::unordered_set<uint32_t>* visited_phis) {
// Not currently optimizing array inserts.
Instruction* typeInst = get_def_use_mgr()->GetDef(insertChain->type_id());
if (typeInst->opcode() == SpvOpTypeArray) return;
if (typeInst->opcode() == spv::Op::OpTypeArray) return;
// Insert chains are only composed of inserts and phis
if (insertChain->opcode() != SpvOpCompositeInsert &&
insertChain->opcode() != SpvOpPhi)
if (insertChain->opcode() != spv::Op::OpCompositeInsert &&
insertChain->opcode() != spv::Op::OpPhi)
return;
// If extract indices are empty, mark all subcomponents if type
// is constant length.
@@ -89,7 +86,7 @@ void DeadInsertElimPass::MarkInsertChain(
}
}
Instruction* insInst = insertChain;
while (insInst->opcode() == SpvOpCompositeInsert) {
while (insInst->opcode() == spv::Op::OpCompositeInsert) {
// If no extract indices, mark insert and inserted object (which might
// also be an insert chain) and continue up the chain though the input
// composite.
@@ -139,7 +136,7 @@ void DeadInsertElimPass::MarkInsertChain(
insInst = get_def_use_mgr()->GetDef(compId);
}
// If insert chain ended with phi, do recursive call on each operand
if (insInst->opcode() != SpvOpPhi) return;
if (insInst->opcode() != spv::Op::OpPhi) return;
// Mark phi visited to prevent potential infinite loop. If phi is already
// visited, return to avoid infinite loop.
if (visited_phis->count(insInst->result_id()) != 0) return;
@@ -179,17 +176,17 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(Function* func) {
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
// Only process Inserts and composite Phis
SpvOp op = ii->opcode();
spv::Op op = ii->opcode();
Instruction* typeInst = get_def_use_mgr()->GetDef(ii->type_id());
if (op != SpvOpCompositeInsert &&
(op != SpvOpPhi || !spvOpcodeIsComposite(typeInst->opcode())))
if (op != spv::Op::OpCompositeInsert &&
(op != spv::Op::OpPhi || !spvOpcodeIsComposite(typeInst->opcode())))
continue;
// The marking algorithm can be expensive for large arrays and the
// efficacy of eliminating dead inserts into arrays is questionable.
// Skip optimizing array inserts for now. Just mark them live.
// TODO(greg-lunarg): Eliminate dead array inserts
if (op == SpvOpCompositeInsert) {
if (typeInst->opcode() == SpvOpTypeArray) {
if (op == spv::Op::OpCompositeInsert) {
if (typeInst->opcode() == spv::Op::OpTypeArray) {
liveInserts_.insert(ii->result_id());
continue;
}
@@ -198,11 +195,11 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(Function* func) {
get_def_use_mgr()->ForEachUser(id, [&ii, this](Instruction* user) {
if (user->IsCommonDebugInstr()) return;
switch (user->opcode()) {
case SpvOpCompositeInsert:
case SpvOpPhi:
case spv::Op::OpCompositeInsert:
case spv::Op::OpPhi:
// Use by insert or phi does not initiate marking
break;
case SpvOpCompositeExtract: {
case spv::Op::OpCompositeExtract: {
// Capture extract indices
std::vector<uint32_t> extIndices;
uint32_t icnt = 0;
@@ -226,7 +223,7 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(Function* func) {
std::vector<Instruction*> dead_instructions;
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
if (ii->opcode() != SpvOpCompositeInsert) continue;
if (ii->opcode() != spv::Op::OpCompositeInsert) continue;
const uint32_t id = ii->result_id();
if (liveInserts_.find(id) != liveInserts_.end()) continue;
const uint32_t replId =

View File

@@ -33,7 +33,7 @@ Pass::Status DeadVariableElimination::Process() {
// Get the reference count for all of the global OpVariable instructions.
for (auto& inst : context()->types_values()) {
if (inst.opcode() != SpvOp::SpvOpVariable) {
if (inst.opcode() != spv::Op::OpVariable) {
continue;
}
@@ -43,11 +43,11 @@ Pass::Status DeadVariableElimination::Process() {
// Check the linkage. If it is exported, it could be reference somewhere
// else, so we must keep the variable around.
get_decoration_mgr()->ForEachDecoration(
result_id, SpvDecorationLinkageAttributes,
result_id, uint32_t(spv::Decoration::LinkageAttributes),
[&count](const Instruction& linkage_instruction) {
uint32_t last_operand = linkage_instruction.NumOperands() - 1;
if (linkage_instruction.GetSingleWordOperand(last_operand) ==
SpvLinkageTypeExport) {
if (spv::LinkageType(linkage_instruction.GetSingleWordOperand(
last_operand)) == spv::LinkageType::Export) {
count = kMustKeep;
}
});
@@ -57,7 +57,8 @@ Pass::Status DeadVariableElimination::Process() {
// at the uses and count the number of real references.
count = 0;
get_def_use_mgr()->ForEachUser(result_id, [&count](Instruction* user) {
if (!IsAnnotationInst(user->opcode()) && user->opcode() != SpvOpName) {
if (!IsAnnotationInst(user->opcode()) &&
user->opcode() != spv::Op::OpName) {
++count;
}
});
@@ -81,7 +82,7 @@ Pass::Status DeadVariableElimination::Process() {
void DeadVariableElimination::DeleteVariable(uint32_t result_id) {
Instruction* inst = get_def_use_mgr()->GetDef(result_id);
assert(inst->opcode() == SpvOpVariable &&
assert(inst->opcode() == spv::Op::OpVariable &&
"Should not be trying to delete anything other than an OpVariable.");
// Look for an initializer that references another variable. We need to know
@@ -93,7 +94,7 @@ void DeadVariableElimination::DeleteVariable(uint32_t result_id) {
// TODO: Handle OpSpecConstantOP which might be defined in terms of other
// variables. Will probably require a unified dead code pass that does all
// instruction types. (Issue 906)
if (initializer->opcode() == SpvOpVariable) {
if (initializer->opcode() == spv::Op::OpVariable) {
uint32_t initializer_id = initializer->result_id();
size_t& count = reference_count_[initializer_id];
if (count != kMustKeep) {

View File

@@ -22,32 +22,31 @@
// Constants for OpenCL.DebugInfo.100 & NonSemantic.Shader.DebugInfo.100
// extension instructions.
static const uint32_t kOpLineOperandLineIndex = 1;
static const uint32_t kLineOperandIndexDebugFunction = 7;
static const uint32_t kLineOperandIndexDebugLexicalBlock = 5;
static const uint32_t kLineOperandIndexDebugLine = 5;
static const uint32_t kDebugFunctionOperandFunctionIndex = 13;
static const uint32_t kDebugFunctionDefinitionOperandDebugFunctionIndex = 4;
static const uint32_t kDebugFunctionDefinitionOperandOpFunctionIndex = 5;
static const uint32_t kDebugFunctionOperandParentIndex = 9;
static const uint32_t kDebugTypeCompositeOperandParentIndex = 9;
static const uint32_t kDebugLexicalBlockOperandParentIndex = 7;
static const uint32_t kDebugInlinedAtOperandInlinedIndex = 6;
static const uint32_t kDebugExpressOperandOperationIndex = 4;
static const uint32_t kDebugDeclareOperandLocalVariableIndex = 4;
static const uint32_t kDebugDeclareOperandVariableIndex = 5;
static const uint32_t kDebugValueOperandExpressionIndex = 6;
static const uint32_t kDebugOperationOperandOperationIndex = 4;
static const uint32_t kOpVariableOperandStorageClassIndex = 2;
static const uint32_t kDebugLocalVariableOperandParentIndex = 9;
static const uint32_t kExtInstInstructionInIdx = 1;
static const uint32_t kDebugGlobalVariableOperandFlagsIndex = 12;
static const uint32_t kDebugLocalVariableOperandFlagsIndex = 10;
namespace spvtools {
namespace opt {
namespace analysis {
namespace {
constexpr uint32_t kOpLineOperandLineIndex = 1;
constexpr uint32_t kLineOperandIndexDebugFunction = 7;
constexpr uint32_t kLineOperandIndexDebugLexicalBlock = 5;
constexpr uint32_t kLineOperandIndexDebugLine = 5;
constexpr uint32_t kDebugFunctionOperandFunctionIndex = 13;
constexpr uint32_t kDebugFunctionDefinitionOperandDebugFunctionIndex = 4;
constexpr uint32_t kDebugFunctionDefinitionOperandOpFunctionIndex = 5;
constexpr uint32_t kDebugFunctionOperandParentIndex = 9;
constexpr uint32_t kDebugTypeCompositeOperandParentIndex = 9;
constexpr uint32_t kDebugLexicalBlockOperandParentIndex = 7;
constexpr uint32_t kDebugInlinedAtOperandInlinedIndex = 6;
constexpr uint32_t kDebugExpressOperandOperationIndex = 4;
constexpr uint32_t kDebugDeclareOperandLocalVariableIndex = 4;
constexpr uint32_t kDebugDeclareOperandVariableIndex = 5;
constexpr uint32_t kDebugValueOperandExpressionIndex = 6;
constexpr uint32_t kDebugOperationOperandOperationIndex = 4;
constexpr uint32_t kOpVariableOperandStorageClassIndex = 2;
constexpr uint32_t kDebugLocalVariableOperandParentIndex = 9;
constexpr uint32_t kExtInstInstructionInIdx = 1;
constexpr uint32_t kDebugGlobalVariableOperandFlagsIndex = 12;
constexpr uint32_t kDebugLocalVariableOperandFlagsIndex = 10;
void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) {
assert(dbg_inlined_at);
@@ -156,7 +155,8 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
uint32_t AddNewConstInGlobals(IRContext* context, uint32_t const_value) {
uint32_t id = context->TakeNextId();
std::unique_ptr<Instruction> new_const(new Instruction(
context, SpvOpConstant, context->get_type_mgr()->GetUIntTypeId(), id,
context, spv::Op::OpConstant, context->get_type_mgr()->GetUIntTypeId(),
id,
{
{spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
{const_value}},
@@ -212,7 +212,7 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
break;
}
} else {
if (line->opcode() == SpvOpLine) {
if (line->opcode() == spv::Op::OpLine) {
line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex);
} else if (line->GetShader100DebugOpcode() ==
NonSemanticShaderDebugInfo100DebugLine) {
@@ -230,18 +230,19 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
// constants that may be generated here is likely not significant
// and will likely be cleaned up in later passes.
if (line_number_type == spv_operand_type_t::SPV_OPERAND_TYPE_ID &&
line->opcode() == SpvOpLine) {
line->opcode() == spv::Op::OpLine) {
if (!context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse) ||
!context()->AreAnalysesValid(IRContext::Analysis::kAnalysisConstants))
line_number = AddNewConstInGlobals(context(), line_number);
else
line_number = context()->get_constant_mgr()->GetUIntConst(line_number);
line_number =
context()->get_constant_mgr()->GetUIntConstId(line_number);
}
}
uint32_t result_id = context()->TakeNextId();
std::unique_ptr<Instruction> inlined_at(new Instruction(
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
context(), spv::Op::OpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
result_id,
{
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {setId}},
@@ -334,8 +335,8 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
deref_operation = std::unique_ptr<Instruction>(new Instruction(
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
result_id,
context(), spv::Op::OpExtInst,
context()->get_type_mgr()->GetVoidTypeId(), result_id,
{
{SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
@@ -344,11 +345,11 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
{static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
}));
} else {
uint32_t deref_id = context()->get_constant_mgr()->GetUIntConst(
uint32_t deref_id = context()->get_constant_mgr()->GetUIntConstId(
NonSemanticShaderDebugInfo100Deref);
deref_operation = std::unique_ptr<Instruction>(
new Instruction(context(), SpvOpExtInst,
new Instruction(context(), spv::Op::OpExtInst,
context()->get_type_mgr()->GetVoidTypeId(), result_id,
{
{SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
@@ -390,7 +391,7 @@ Instruction* DebugInfoManager::GetDebugInfoNone() {
uint32_t result_id = context()->TakeNextId();
std::unique_ptr<Instruction> dbg_info_none_inst(new Instruction(
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
context(), spv::Op::OpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
result_id,
{
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
@@ -414,7 +415,7 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() {
uint32_t result_id = context()->TakeNextId();
std::unique_ptr<Instruction> empty_debug_expr(new Instruction(
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
context(), spv::Op::OpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
result_id,
{
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
@@ -527,7 +528,7 @@ bool DebugInfoManager::IsDeclareVisibleToInstr(Instruction* dbg_declare,
assert(scope != nullptr);
std::vector<uint32_t> scope_ids;
if (scope->opcode() == SpvOpPhi) {
if (scope->opcode() == spv::Op::OpPhi) {
scope_ids.push_back(scope->GetDebugScope().GetLexicalScope());
for (uint32_t i = 0; i < scope->NumInOperands(); i += 2) {
auto* value = context()->get_def_use_mgr()->GetDef(
@@ -571,8 +572,8 @@ bool DebugInfoManager::AddDebugValueForVariable(Instruction* scope_and_line,
// Avoid inserting the new DebugValue between OpPhi or OpVariable
// instructions.
Instruction* insert_before = insert_pos->NextNode();
while (insert_before->opcode() == SpvOpPhi ||
insert_before->opcode() == SpvOpVariable) {
while (insert_before->opcode() == spv::Op::OpPhi ||
insert_before->opcode() == spv::Op::OpVariable) {
insert_before = insert_before->NextNode();
}
modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id, insert_before,
@@ -653,9 +654,10 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
}
auto* var = context()->get_def_use_mgr()->GetDef(var_id);
if (var->opcode() == SpvOpVariable &&
SpvStorageClass(var->GetSingleWordOperand(
kOpVariableOperandStorageClassIndex)) == SpvStorageClassFunction) {
if (var->opcode() == spv::Op::OpVariable &&
spv::StorageClass(
var->GetSingleWordOperand(kOpVariableOperandStorageClassIndex)) ==
spv::StorageClass::Function) {
return var_id;
}
return 0;
@@ -762,8 +764,8 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
CommonDebugInfoDebugGlobalVariable) {
return;
}
assert(local_var->opcode() == SpvOpVariable ||
local_var->opcode() == SpvOpFunctionParameter);
assert(local_var->opcode() == spv::Op::OpVariable ||
local_var->opcode() == spv::Op::OpFunctionParameter);
// Convert |dbg_global_var| to DebugLocalVariable
dbg_global_var->SetInOperand(kExtInstInstructionInIdx,
@@ -780,7 +782,7 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
// Create a DebugDeclare
std::unique_ptr<Instruction> new_dbg_decl(new Instruction(
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
context(), spv::Op::OpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
context()->TakeNextId(),
{
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
@@ -794,7 +796,7 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
}));
// Must insert after all OpVariables in block
Instruction* insert_before = local_var;
while (insert_before->opcode() == SpvOpVariable)
while (insert_before->opcode() == spv::Op::OpVariable)
insert_before = insert_before->NextNode();
auto* added_dbg_decl = insert_before->InsertBefore(std::move(new_dbg_decl));
if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))

View File

@@ -22,6 +22,9 @@
#include "source/opt/ir_context.h"
namespace spvtools {
namespace opt {
namespace analysis {
namespace {
using InstructionVector = std::vector<const spvtools::opt::Instruction*>;
using DecorationSet = std::set<std::u32string>;
@@ -49,10 +52,6 @@ bool IsSubset(const DecorationSet& a, const DecorationSet& b) {
}
} // namespace
namespace spvtools {
namespace opt {
namespace analysis {
bool DecorationManager::RemoveDecorationsFrom(
uint32_t id, std::function<bool(const Instruction&)> pred) {
bool was_modified = false;
@@ -76,8 +75,8 @@ bool DecorationManager::RemoveDecorationsFrom(
// applying the group.
std::unordered_set<const Instruction*> indirect_decorations_to_remove;
for (Instruction* inst : decorations_info.indirect_decorations) {
assert(inst->opcode() == SpvOpGroupDecorate ||
inst->opcode() == SpvOpGroupMemberDecorate);
assert(inst->opcode() == spv::Op::OpGroupDecorate ||
inst->opcode() == spv::Op::OpGroupMemberDecorate);
std::vector<Instruction*> group_decorations_to_keep;
const uint32_t group_id = inst->GetSingleWordInOperand(0u);
@@ -99,7 +98,8 @@ bool DecorationManager::RemoveDecorationsFrom(
}
// Otherwise, remove |id| from the targets of |group_id|
const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
const uint32_t stride =
inst->opcode() == spv::Op::OpGroupDecorate ? 1u : 2u;
for (uint32_t i = 1u; i < inst->NumInOperands();) {
if (inst->GetSingleWordInOperand(i) != id) {
i += stride;
@@ -212,16 +212,16 @@ bool DecorationManager::HaveTheSameDecorations(uint32_t id1,
}
switch (inst->opcode()) {
case SpvOpDecorate:
case spv::Op::OpDecorate:
decorate_set->emplace(std::move(decoration_payload));
break;
case SpvOpMemberDecorate:
case spv::Op::OpMemberDecorate:
member_decorate_set->emplace(std::move(decoration_payload));
break;
case SpvOpDecorateId:
case spv::Op::OpDecorateId:
decorate_id_set->emplace(std::move(decoration_payload));
break;
case SpvOpDecorateStringGOOGLE:
case spv::Op::OpDecorateStringGOOGLE:
decorate_string_set->emplace(std::move(decoration_payload));
break;
default:
@@ -278,16 +278,16 @@ bool DecorationManager::HaveSubsetOfDecorations(uint32_t id1,
}
switch (inst->opcode()) {
case SpvOpDecorate:
case spv::Op::OpDecorate:
decorate_set->emplace(std::move(decoration_payload));
break;
case SpvOpMemberDecorate:
case spv::Op::OpMemberDecorate:
member_decorate_set->emplace(std::move(decoration_payload));
break;
case SpvOpDecorateId:
case spv::Op::OpDecorateId:
decorate_id_set->emplace(std::move(decoration_payload));
break;
case SpvOpDecorateStringGOOGLE:
case spv::Op::OpDecorateStringGOOGLE:
decorate_string_set->emplace(std::move(decoration_payload));
break;
default:
@@ -328,10 +328,10 @@ bool DecorationManager::AreDecorationsTheSame(const Instruction* inst1,
const Instruction* inst2,
bool ignore_target) const {
switch (inst1->opcode()) {
case SpvOpDecorate:
case SpvOpMemberDecorate:
case SpvOpDecorateId:
case SpvOpDecorateStringGOOGLE:
case spv::Op::OpDecorate:
case spv::Op::OpMemberDecorate:
case spv::Op::OpDecorateId:
case spv::Op::OpDecorateStringGOOGLE:
break;
default:
return false;
@@ -358,17 +358,18 @@ void DecorationManager::AnalyzeDecorations() {
void DecorationManager::AddDecoration(Instruction* inst) {
switch (inst->opcode()) {
case SpvOpDecorate:
case SpvOpDecorateId:
case SpvOpDecorateStringGOOGLE:
case SpvOpMemberDecorate: {
case spv::Op::OpDecorate:
case spv::Op::OpDecorateId:
case spv::Op::OpDecorateStringGOOGLE:
case spv::Op::OpMemberDecorate: {
const auto target_id = inst->GetSingleWordInOperand(0u);
id_to_decoration_insts_[target_id].direct_decorations.push_back(inst);
break;
}
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate: {
const uint32_t start = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
case spv::Op::OpGroupDecorate:
case spv::Op::OpGroupMemberDecorate: {
const uint32_t start =
inst->opcode() == spv::Op::OpGroupDecorate ? 1u : 2u;
const uint32_t stride = start;
for (uint32_t i = start; i < inst->NumInOperands(); i += stride) {
const auto target_id = inst->GetSingleWordInOperand(i);
@@ -384,7 +385,7 @@ void DecorationManager::AddDecoration(Instruction* inst) {
}
}
void DecorationManager::AddDecoration(SpvOp opcode,
void DecorationManager::AddDecoration(spv::Op opcode,
std::vector<Operand> opnds) {
IRContext* ctx = module_->context();
std::unique_ptr<Instruction> newDecoOp(
@@ -394,7 +395,7 @@ void DecorationManager::AddDecoration(SpvOp opcode,
void DecorationManager::AddDecoration(uint32_t inst_id, uint32_t decoration) {
AddDecoration(
SpvOpDecorate,
spv::Op::OpDecorate,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}}});
}
@@ -402,7 +403,7 @@ void DecorationManager::AddDecoration(uint32_t inst_id, uint32_t decoration) {
void DecorationManager::AddDecorationVal(uint32_t inst_id, uint32_t decoration,
uint32_t decoration_value) {
AddDecoration(
SpvOpDecorate,
spv::Op::OpDecorate,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
@@ -413,7 +414,7 @@ void DecorationManager::AddMemberDecoration(uint32_t inst_id, uint32_t member,
uint32_t decoration,
uint32_t decoration_value) {
AddDecoration(
SpvOpMemberDecorate,
spv::Op::OpMemberDecorate,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {member}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}},
@@ -436,9 +437,10 @@ std::vector<T> DecorationManager::InternalGetDecorationsFor(
[include_linkage,
&decorations](const std::vector<Instruction*>& direct_decorations) {
for (Instruction* inst : direct_decorations) {
const bool is_linkage = inst->opcode() == SpvOpDecorate &&
inst->GetSingleWordInOperand(1u) ==
SpvDecorationLinkageAttributes;
const bool is_linkage =
inst->opcode() == spv::Op::OpDecorate &&
spv::Decoration(inst->GetSingleWordInOperand(1u)) ==
spv::Decoration::LinkageAttributes;
if (include_linkage || !is_linkage) decorations.push_back(inst);
}
};
@@ -462,14 +464,14 @@ bool DecorationManager::WhileEachDecoration(
std::function<bool(const Instruction&)> f) {
for (const Instruction* inst : GetDecorationsFor(id, true)) {
switch (inst->opcode()) {
case SpvOpMemberDecorate:
case spv::Op::OpMemberDecorate:
if (inst->GetSingleWordInOperand(2) == decoration) {
if (!f(*inst)) return false;
}
break;
case SpvOpDecorate:
case SpvOpDecorateId:
case SpvOpDecorateStringGOOGLE:
case spv::Op::OpDecorate:
case spv::Op::OpDecorateId:
case spv::Op::OpDecorateStringGOOGLE:
if (inst->GetSingleWordInOperand(1) == decoration) {
if (!f(*inst)) return false;
}
@@ -523,14 +525,14 @@ void DecorationManager::CloneDecorations(uint32_t from, uint32_t to) {
decoration_list->second.indirect_decorations;
for (Instruction* inst : indirect_decorations) {
switch (inst->opcode()) {
case SpvOpGroupDecorate:
case spv::Op::OpGroupDecorate:
context->ForgetUses(inst);
// add |to| to list of decorated id's
inst->AddOperand(
Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
context->AnalyzeUses(inst);
break;
case SpvOpGroupMemberDecorate: {
case spv::Op::OpGroupMemberDecorate: {
context->ForgetUses(inst);
// for each (id == from), add (to, literal) as operands
const uint32_t num_operands = inst->NumOperands();
@@ -554,13 +556,13 @@ void DecorationManager::CloneDecorations(uint32_t from, uint32_t to) {
void DecorationManager::CloneDecorations(
uint32_t from, uint32_t to,
const std::vector<SpvDecoration>& decorations_to_copy) {
const std::vector<spv::Decoration>& decorations_to_copy) {
const auto decoration_list = id_to_decoration_insts_.find(from);
if (decoration_list == id_to_decoration_insts_.end()) return;
auto context = module_->context();
for (Instruction* inst : decoration_list->second.direct_decorations) {
if (std::find(decorations_to_copy.begin(), decorations_to_copy.end(),
inst->GetSingleWordInOperand(1)) ==
spv::Decoration(inst->GetSingleWordInOperand(1))) ==
decorations_to_copy.end()) {
continue;
}
@@ -579,11 +581,11 @@ void DecorationManager::CloneDecorations(
decoration_list->second.indirect_decorations;
for (Instruction* inst : indirect_decorations) {
switch (inst->opcode()) {
case SpvOpGroupDecorate:
case spv::Op::OpGroupDecorate:
CloneDecorations(inst->GetSingleWordInOperand(0), to,
decorations_to_copy);
break;
case SpvOpGroupMemberDecorate: {
case spv::Op::OpGroupMemberDecorate: {
assert(false && "The source id is not suppose to be a type.");
break;
}
@@ -599,18 +601,19 @@ void DecorationManager::RemoveDecoration(Instruction* inst) {
};
switch (inst->opcode()) {
case SpvOpDecorate:
case SpvOpDecorateId:
case SpvOpDecorateStringGOOGLE:
case SpvOpMemberDecorate: {
case spv::Op::OpDecorate:
case spv::Op::OpDecorateId:
case spv::Op::OpDecorateStringGOOGLE:
case spv::Op::OpMemberDecorate: {
const auto target_id = inst->GetSingleWordInOperand(0u);
auto const iter = id_to_decoration_insts_.find(target_id);
if (iter == id_to_decoration_insts_.end()) return;
remove_from_container(iter->second.direct_decorations);
} break;
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate: {
const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
case spv::Op::OpGroupDecorate:
case spv::Op::OpGroupMemberDecorate: {
const uint32_t stride =
inst->opcode() == spv::Op::OpGroupDecorate ? 1u : 2u;
for (uint32_t i = 1u; i < inst->NumInOperands(); i += stride) {
const auto target_id = inst->GetSingleWordInOperand(i);
auto const iter = id_to_decoration_insts_.find(target_id);

View File

@@ -71,14 +71,14 @@ class DecorationManager {
bool include_linkage);
std::vector<const Instruction*> GetDecorationsFor(uint32_t id,
bool include_linkage) const;
// Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate
// instructions that apply the same decorations but to different IDs, still
// count as being the same.
// Returns whether two IDs have the same decorations. Two
// spv::Op::OpGroupDecorate instructions that apply the same decorations but
// to different IDs, still count as being the same.
bool HaveTheSameDecorations(uint32_t id1, uint32_t id2) const;
// Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate
// instructions that apply the same decorations but to different IDs, still
// count as being the same.
// Returns whether two IDs have the same decorations. Two
// spv::Op::OpGroupDecorate instructions that apply the same decorations but
// to different IDs, still count as being the same.
bool HaveSubsetOfDecorations(uint32_t id1, uint32_t id2) const;
// Returns whether the two decorations instructions are the same and are
@@ -123,14 +123,15 @@ class DecorationManager {
// Same as above, but only clone the decoration if the decoration operand is
// in |decorations_to_copy|. This function has the extra restriction that
// |from| and |to| must not be an object, not a type.
void CloneDecorations(uint32_t from, uint32_t to,
const std::vector<SpvDecoration>& decorations_to_copy);
void CloneDecorations(
uint32_t from, uint32_t to,
const std::vector<spv::Decoration>& decorations_to_copy);
// Informs the decoration manager of a new decoration that it needs to track.
void AddDecoration(Instruction* inst);
// Add decoration with |opcode| and operands |opnds|.
void AddDecoration(SpvOp opcode, const std::vector<Operand> opnds);
void AddDecoration(spv::Op opcode, const std::vector<Operand> opnds);
// Add |decoration| of |inst_id| to module.
void AddDecoration(uint32_t inst_id, uint32_t decoration);
@@ -195,9 +196,9 @@ class DecorationManager {
// Mapping from ids to the instructions applying a decoration to those ids.
// In other words, for each id you get all decoration instructions
// referencing that id, be it directly (SpvOpDecorate, SpvOpMemberDecorate
// and SpvOpDecorateId), or indirectly (SpvOpGroupDecorate,
// SpvOpMemberGroupDecorate).
// referencing that id, be it directly (spv::Op::OpDecorate,
// spv::Op::OpMemberDecorate and spv::Op::OpDecorateId), or indirectly
// (spv::Op::OpGroupDecorate, spv::Op::OpMemberGroupDecorate).
std::unordered_map<uint32_t, TargetData> id_to_decoration_insts_;
// The enclosing module.
Module* module_;

View File

@@ -22,8 +22,9 @@ namespace opt {
namespace {
bool IsDecorationBinding(Instruction* inst) {
if (inst->opcode() != SpvOpDecorate) return false;
return inst->GetSingleWordInOperand(1u) == SpvDecorationBinding;
if (inst->opcode() != spv::Op::OpDecorate) return false;
return spv::Decoration(inst->GetSingleWordInOperand(1u)) ==
spv::Decoration::Binding;
}
} // namespace
@@ -56,7 +57,7 @@ bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
bool failed = !get_def_use_mgr()->WhileEachUser(
var->result_id(),
[this, &access_chain_work_list, &load_work_list](Instruction* use) {
if (use->opcode() == SpvOpName) {
if (use->opcode() == spv::Op::OpName) {
return true;
}
@@ -65,11 +66,11 @@ bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
}
switch (use->opcode()) {
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
access_chain_work_list.push_back(use);
return true;
case SpvOpLoad:
case spv::Op::OpLoad:
load_work_list.push_back(use);
return true;
default:
@@ -184,7 +185,7 @@ void DescriptorScalarReplacement::CopyDecorationsForNewVariable(
// Handle OpMemberDecorate instructions.
for (auto old_decoration : get_decoration_mgr()->GetDecorationsFor(
old_var_type->result_id(), true)) {
assert(old_decoration->opcode() == SpvOpMemberDecorate);
assert(old_decoration->opcode() == spv::Op::OpMemberDecorate);
if (old_decoration->GetSingleWordInOperand(1u) != index) continue;
CreateNewDecorationForMemberDecorate(old_decoration, new_var_id);
}
@@ -212,8 +213,8 @@ uint32_t DescriptorScalarReplacement::GetNewBindingForElement(
void DescriptorScalarReplacement::CreateNewDecorationForNewVariable(
Instruction* old_decoration, uint32_t new_var_id, uint32_t new_binding) {
assert(old_decoration->opcode() == SpvOpDecorate ||
old_decoration->opcode() == SpvOpDecorateString);
assert(old_decoration->opcode() == spv::Op::OpDecorate ||
old_decoration->opcode() == spv::Op::OpDecorateString);
std::unique_ptr<Instruction> new_decoration(old_decoration->Clone(context()));
new_decoration->SetInOperand(0, {new_var_id});
@@ -231,25 +232,25 @@ void DescriptorScalarReplacement::CreateNewDecorationForMemberDecorate(
auto new_decorate_operand_end = old_member_decoration->end();
operands.insert(operands.end(), new_decorate_operand_begin,
new_decorate_operand_end);
get_decoration_mgr()->AddDecoration(SpvOpDecorate, std::move(operands));
get_decoration_mgr()->AddDecoration(spv::Op::OpDecorate, std::move(operands));
}
uint32_t DescriptorScalarReplacement::CreateReplacementVariable(
Instruction* var, uint32_t idx) {
// The storage class for the new variable is the same as the original.
SpvStorageClass storage_class =
static_cast<SpvStorageClass>(var->GetSingleWordInOperand(0));
spv::StorageClass storage_class =
static_cast<spv::StorageClass>(var->GetSingleWordInOperand(0));
// The type for the new variable will be a pointer to type of the elements of
// the array.
uint32_t ptr_type_id = var->type_id();
Instruction* ptr_type_inst = get_def_use_mgr()->GetDef(ptr_type_id);
assert(ptr_type_inst->opcode() == SpvOpTypePointer &&
assert(ptr_type_inst->opcode() == spv::Op::OpTypePointer &&
"Variable should be a pointer to an array or structure.");
uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1);
Instruction* pointee_type_inst = get_def_use_mgr()->GetDef(pointee_type_id);
const bool is_array = pointee_type_inst->opcode() == SpvOpTypeArray;
const bool is_struct = pointee_type_inst->opcode() == SpvOpTypeStruct;
const bool is_array = pointee_type_inst->opcode() == spv::Op::OpTypeArray;
const bool is_struct = pointee_type_inst->opcode() == spv::Op::OpTypeStruct;
assert((is_array || is_struct) &&
"Variable should be a pointer to an array or structure.");
@@ -263,7 +264,7 @@ uint32_t DescriptorScalarReplacement::CreateReplacementVariable(
// Create the variable.
uint32_t id = TakeNextId();
std::unique_ptr<Instruction> variable(
new Instruction(context(), SpvOpVariable, ptr_element_type_id, id,
new Instruction(context(), spv::Op::OpVariable, ptr_element_type_id, id,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_STORAGE_CLASS,
{static_cast<uint32_t>(storage_class)}}}));
@@ -293,7 +294,7 @@ uint32_t DescriptorScalarReplacement::CreateReplacementVariable(
}
std::unique_ptr<Instruction> new_name(new Instruction(
context(), SpvOpName, 0, 0,
context(), spv::Op::OpName, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {id}},
{SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}));
@@ -315,14 +316,14 @@ uint32_t DescriptorScalarReplacement::GetNumBindingsUsedByType(
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
// If it's a pointer, look at the underlying type.
if (type_inst->opcode() == SpvOpTypePointer) {
if (type_inst->opcode() == spv::Op::OpTypePointer) {
type_id = type_inst->GetSingleWordInOperand(1);
type_inst = get_def_use_mgr()->GetDef(type_id);
}
// Arrays consume N*M binding numbers where N is the array length, and M is
// the number of bindings used by each array element.
if (type_inst->opcode() == SpvOpTypeArray) {
if (type_inst->opcode() == spv::Op::OpTypeArray) {
uint32_t element_type_id = type_inst->GetSingleWordInOperand(0);
uint32_t length_id = type_inst->GetSingleWordInOperand(1);
const analysis::Constant* length_const =
@@ -335,7 +336,7 @@ uint32_t DescriptorScalarReplacement::GetNumBindingsUsedByType(
// The number of bindings consumed by a structure is the sum of the bindings
// used by its members.
if (type_inst->opcode() == SpvOpTypeStruct &&
if (type_inst->opcode() == spv::Op::OpTypeStruct &&
!descsroautil::IsTypeOfStructuredBuffer(context(), type_inst)) {
uint32_t sum = 0;
for (uint32_t i = 0; i < type_inst->NumInOperands(); i++)
@@ -353,12 +354,12 @@ bool DescriptorScalarReplacement::ReplaceLoadedValue(Instruction* var,
// |value| is the OpLoad instruction that has loaded |var|.
// The function expects all users of |value| to be OpCompositeExtract
// instructions. Otherwise the function returns false with an error message.
assert(value->opcode() == SpvOpLoad);
assert(value->opcode() == spv::Op::OpLoad);
assert(value->GetSingleWordInOperand(0) == var->result_id());
std::vector<Instruction*> work_list;
bool failed = !get_def_use_mgr()->WhileEachUser(
value->result_id(), [this, &work_list](Instruction* use) {
if (use->opcode() != SpvOpCompositeExtract) {
if (use->opcode() != spv::Op::OpCompositeExtract) {
context()->EmitErrorMessage(
"Variable cannot be replaced: invalid instruction", use);
return false;
@@ -384,7 +385,7 @@ bool DescriptorScalarReplacement::ReplaceLoadedValue(Instruction* var,
bool DescriptorScalarReplacement::ReplaceCompositeExtract(
Instruction* var, Instruction* extract) {
assert(extract->opcode() == SpvOpCompositeExtract);
assert(extract->opcode() == spv::Op::OpCompositeExtract);
// We're currently only supporting extractions of one index at a time. If we
// need to, we can handle cases with multiple indexes in the future.
if (extract->NumInOperands() != 2) {
@@ -400,7 +401,7 @@ bool DescriptorScalarReplacement::ReplaceCompositeExtract(
// OpCompositeExtract.
uint32_t load_id = TakeNextId();
std::unique_ptr<Instruction> load(
new Instruction(context(), SpvOpLoad, extract->type_id(), load_id,
new Instruction(context(), spv::Op::OpLoad, extract->type_id(), load_id,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {replacement_var}}}));
Instruction* load_instr = load.get();

View File

@@ -17,12 +17,11 @@
namespace spvtools {
namespace opt {
namespace {
const uint32_t kOpAccessChainInOperandIndexes = 1;
constexpr uint32_t kOpAccessChainInOperandIndexes = 1;
// Returns the length of array type |type|.
uint32_t GetLengthOfArrayType(IRContext* context, Instruction* type) {
assert(type->opcode() == SpvOpTypeArray && "type must be array");
assert(type->opcode() == spv::Op::OpTypeArray && "type must be array");
uint32_t length_id = type->GetSingleWordInOperand(1);
const analysis::Constant* length_const =
context->get_constant_mgr()->FindDeclaredConstant(length_id);
@@ -35,20 +34,20 @@ uint32_t GetLengthOfArrayType(IRContext* context, Instruction* type) {
namespace descsroautil {
bool IsDescriptorArray(IRContext* context, Instruction* var) {
if (var->opcode() != SpvOpVariable) {
if (var->opcode() != spv::Op::OpVariable) {
return false;
}
uint32_t ptr_type_id = var->type_id();
Instruction* ptr_type_inst = context->get_def_use_mgr()->GetDef(ptr_type_id);
if (ptr_type_inst->opcode() != SpvOpTypePointer) {
if (ptr_type_inst->opcode() != spv::Op::OpTypePointer) {
return false;
}
uint32_t var_type_id = ptr_type_inst->GetSingleWordInOperand(1);
Instruction* var_type_inst = context->get_def_use_mgr()->GetDef(var_type_id);
if (var_type_inst->opcode() != SpvOpTypeArray &&
var_type_inst->opcode() != SpvOpTypeStruct) {
if (var_type_inst->opcode() != spv::Op::OpTypeArray &&
var_type_inst->opcode() != spv::Op::OpTypeStruct) {
return false;
}
@@ -59,23 +58,23 @@ bool IsDescriptorArray(IRContext* context, Instruction* var) {
}
if (!context->get_decoration_mgr()->HasDecoration(
var->result_id(), SpvDecorationDescriptorSet)) {
var->result_id(), uint32_t(spv::Decoration::DescriptorSet))) {
return false;
}
return context->get_decoration_mgr()->HasDecoration(var->result_id(),
SpvDecorationBinding);
return context->get_decoration_mgr()->HasDecoration(
var->result_id(), uint32_t(spv::Decoration::Binding));
}
bool IsTypeOfStructuredBuffer(IRContext* context, const Instruction* type) {
if (type->opcode() != SpvOpTypeStruct) {
if (type->opcode() != spv::Op::OpTypeStruct) {
return false;
}
// All buffers have offset decorations for members of their structure types.
// This is how we distinguish it from a structure of descriptors.
return context->get_decoration_mgr()->HasDecoration(type->result_id(),
SpvDecorationOffset);
return context->get_decoration_mgr()->HasDecoration(
type->result_id(), uint32_t(spv::Decoration::Offset));
}
const analysis::Constant* GetAccessChainIndexAsConst(
@@ -99,15 +98,15 @@ uint32_t GetNumberOfElementsForArrayOrStruct(IRContext* context,
Instruction* var) {
uint32_t ptr_type_id = var->type_id();
Instruction* ptr_type_inst = context->get_def_use_mgr()->GetDef(ptr_type_id);
assert(ptr_type_inst->opcode() == SpvOpTypePointer &&
assert(ptr_type_inst->opcode() == spv::Op::OpTypePointer &&
"Variable should be a pointer to an array or structure.");
uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1);
Instruction* pointee_type_inst =
context->get_def_use_mgr()->GetDef(pointee_type_id);
if (pointee_type_inst->opcode() == SpvOpTypeArray) {
if (pointee_type_inst->opcode() == spv::Op::OpTypeArray) {
return GetLengthOfArrayType(context, pointee_type_inst);
}
assert(pointee_type_inst->opcode() == SpvOpTypeStruct &&
assert(pointee_type_inst->opcode() == spv::Op::OpTypeStruct &&
"Variable should be a pointer to an array or structure.");
return pointee_type_inst->NumInOperands();
}

View File

@@ -64,7 +64,7 @@ bool DominatorAnalysisBase::Dominates(Instruction* a, Instruction* b) const {
// We handle OpLabel instructions explicitly since they are not stored in the
// instruction list.
if (current->opcode() == SpvOpLabel) {
if (current->opcode() == spv::Op::OpLabel) {
return true;
}

View File

@@ -55,8 +55,8 @@ namespace {
// called on each node traversed BEFORE their children.
template <typename BBType, typename SuccessorLambda, typename PreLambda,
typename PostLambda>
static void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
PreLambda pre, PostLambda post) {
void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
PreLambda pre, PostLambda post) {
auto no_terminal_blocks = [](const BBType*) { return false; };
CFA<BBType>::DepthFirstTraversal(bb, successors, pre, post,
no_terminal_blocks);
@@ -73,9 +73,8 @@ static void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
// PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
// called on each node traversed after their children.
template <typename BBType, typename SuccessorLambda, typename PostLambda>
static void DepthFirstSearchPostOrder(const BBType* bb,
SuccessorLambda successors,
PostLambda post) {
void DepthFirstSearchPostOrder(const BBType* bb, SuccessorLambda successors,
PostLambda post) {
// Ignore preorder operation.
auto nop_preorder = [](const BBType*) {};
DepthFirstSearch(bb, successors, nop_preorder, post);

View File

@@ -40,7 +40,7 @@ Pass::Status EliminateDeadConstantPass::Process() {
context()->get_def_use_mgr()->ForEachUse(
const_id, [&count](Instruction* user, uint32_t index) {
(void)index;
SpvOp op = user->opcode();
spv::Op op = user->opcode();
if (!(IsAnnotationInst(op) || IsDebug1Inst(op) || IsDebug2Inst(op) ||
IsDebug3Inst(op))) {
++count;
@@ -59,9 +59,9 @@ Pass::Status EliminateDeadConstantPass::Process() {
Instruction* inst = *working_list.begin();
// Back propagate if the instruction contains IDs in its operands.
switch (inst->opcode()) {
case SpvOp::SpvOpConstantComposite:
case SpvOp::SpvOpSpecConstantComposite:
case SpvOp::SpvOpSpecConstantOp:
case spv::Op::OpConstantComposite:
case spv::Op::OpSpecConstantComposite:
case spv::Op::OpSpecConstantOp:
for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
// SpecConstantOp instruction contains 'opcode' as its operand. Need
// to exclude such operands when decreasing uses.

View File

@@ -28,12 +28,12 @@ Module::iterator EliminateFunction(IRContext* context,
->ForEachInst(
[context, first_func, func_iter, &seen_func_end,
&to_kill](Instruction* inst) {
if (inst->opcode() == SpvOpFunctionEnd) {
if (inst->opcode() == spv::Op::OpFunctionEnd) {
seen_func_end = true;
}
// Move non-semantic instructions to the previous function or
// global values if this is the first function.
if (seen_func_end && inst->opcode() == SpvOpExtInst) {
if (seen_func_end && inst->opcode() == spv::Op::OpExtInst) {
assert(inst->IsNonSemanticInstruction());
if (to_kill.find(inst) != to_kill.end()) return;
std::unique_ptr<Instruction> clone(inst->Clone(context));

View File

@@ -1,189 +0,0 @@
// Copyright (c) 2022 The Khronos Group Inc.
// Copyright (c) 2022 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/opt/eliminate_dead_input_components_pass.h"
#include <set>
#include <vector>
#include "source/opt/instruction.h"
#include "source/opt/ir_builder.h"
#include "source/opt/ir_context.h"
#include "source/util/bit_vector.h"
namespace {
const uint32_t kAccessChainBaseInIdx = 0;
const uint32_t kAccessChainIndex0InIdx = 1;
const uint32_t kConstantValueInIdx = 0;
const uint32_t kVariableStorageClassInIdx = 0;
} // namespace
namespace spvtools {
namespace opt {
Pass::Status EliminateDeadInputComponentsPass::Process() {
// Current functionality assumes shader capability
if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
return Status::SuccessWithoutChange;
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
analysis::TypeManager* type_mgr = context()->get_type_mgr();
bool modified = false;
std::vector<std::pair<Instruction*, unsigned>> arrays_to_change;
for (auto& var : context()->types_values()) {
if (var.opcode() != SpvOpVariable) {
continue;
}
analysis::Type* var_type = type_mgr->GetType(var.type_id());
analysis::Pointer* ptr_type = var_type->AsPointer();
if (ptr_type == nullptr) {
continue;
}
if (ptr_type->storage_class() != SpvStorageClassInput) {
continue;
}
const analysis::Array* arr_type = ptr_type->pointee_type()->AsArray();
if (arr_type != nullptr) {
unsigned arr_len_id = arr_type->LengthId();
Instruction* arr_len_inst = def_use_mgr->GetDef(arr_len_id);
if (arr_len_inst->opcode() != SpvOpConstant) {
continue;
}
// SPIR-V requires array size is >= 1, so this works for signed or
// unsigned size
unsigned original_max =
arr_len_inst->GetSingleWordInOperand(kConstantValueInIdx) - 1;
unsigned max_idx = FindMaxIndex(var, original_max);
if (max_idx != original_max) {
ChangeArrayLength(var, max_idx + 1);
modified = true;
}
continue;
}
const analysis::Struct* struct_type = ptr_type->pointee_type()->AsStruct();
if (struct_type == nullptr) continue;
const auto elt_types = struct_type->element_types();
unsigned original_max = static_cast<unsigned>(elt_types.size()) - 1;
unsigned max_idx = FindMaxIndex(var, original_max);
if (max_idx != original_max) {
ChangeStructLength(var, max_idx + 1);
modified = true;
}
}
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
unsigned EliminateDeadInputComponentsPass::FindMaxIndex(Instruction& var,
unsigned original_max) {
unsigned max = 0;
bool seen_non_const_ac = false;
assert(var.opcode() == SpvOpVariable && "must be variable");
context()->get_def_use_mgr()->WhileEachUser(
var.result_id(), [&max, &seen_non_const_ac, var, this](Instruction* use) {
auto use_opcode = use->opcode();
if (use_opcode == SpvOpLoad || use_opcode == SpvOpCopyMemory ||
use_opcode == SpvOpCopyMemorySized ||
use_opcode == SpvOpCopyObject) {
seen_non_const_ac = true;
return false;
}
if (use->opcode() != SpvOpAccessChain &&
use->opcode() != SpvOpInBoundsAccessChain) {
return true;
}
// OpAccessChain with no indices currently not optimized
if (use->NumInOperands() == 1) {
seen_non_const_ac = true;
return false;
}
unsigned base_id = use->GetSingleWordInOperand(kAccessChainBaseInIdx);
USE_ASSERT(base_id == var.result_id() && "unexpected base");
unsigned idx_id = use->GetSingleWordInOperand(kAccessChainIndex0InIdx);
Instruction* idx_inst = context()->get_def_use_mgr()->GetDef(idx_id);
if (idx_inst->opcode() != SpvOpConstant) {
seen_non_const_ac = true;
return false;
}
unsigned value = idx_inst->GetSingleWordInOperand(kConstantValueInIdx);
if (value > max) max = value;
return true;
});
return seen_non_const_ac ? original_max : max;
}
void EliminateDeadInputComponentsPass::ChangeArrayLength(Instruction& arr_var,
unsigned length) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
analysis::Pointer* ptr_type =
type_mgr->GetType(arr_var.type_id())->AsPointer();
const analysis::Array* arr_ty = ptr_type->pointee_type()->AsArray();
assert(arr_ty && "expecting array type");
uint32_t length_id = const_mgr->GetUIntConst(length);
analysis::Array new_arr_ty(arr_ty->element_type(),
arr_ty->GetConstantLengthInfo(length_id, length));
analysis::Type* reg_new_arr_ty = type_mgr->GetRegisteredType(&new_arr_ty);
analysis::Pointer new_ptr_ty(reg_new_arr_ty, SpvStorageClassInput);
analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
arr_var.SetResultType(new_ptr_ty_id);
def_use_mgr->AnalyzeInstUse(&arr_var);
// Move arr_var after its new type to preserve order
USE_ASSERT(arr_var.GetSingleWordInOperand(kVariableStorageClassInIdx) !=
SpvStorageClassFunction &&
"cannot move Function variable");
Instruction* new_ptr_ty_inst = def_use_mgr->GetDef(new_ptr_ty_id);
arr_var.RemoveFromList();
arr_var.InsertAfter(new_ptr_ty_inst);
}
void EliminateDeadInputComponentsPass::ChangeStructLength(
Instruction& struct_var, unsigned length) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::Pointer* ptr_type =
type_mgr->GetType(struct_var.type_id())->AsPointer();
const analysis::Struct* struct_ty = ptr_type->pointee_type()->AsStruct();
assert(struct_ty && "expecting struct type");
const auto orig_elt_types = struct_ty->element_types();
std::vector<const analysis::Type*> new_elt_types;
for (unsigned u = 0; u < length; ++u)
new_elt_types.push_back(orig_elt_types[u]);
analysis::Struct new_struct_ty(new_elt_types);
analysis::Type* reg_new_struct_ty =
type_mgr->GetRegisteredType(&new_struct_ty);
uint32_t new_struct_ty_id = type_mgr->GetTypeInstruction(reg_new_struct_ty);
uint32_t old_struct_ty_id = type_mgr->GetTypeInstruction(struct_ty);
analysis::DecorationManager* deco_mgr = context()->get_decoration_mgr();
deco_mgr->CloneDecorations(old_struct_ty_id, new_struct_ty_id);
analysis::Pointer new_ptr_ty(reg_new_struct_ty, SpvStorageClassInput);
analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
struct_var.SetResultType(new_ptr_ty_id);
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
def_use_mgr->AnalyzeInstUse(&struct_var);
// Move struct_var after its new type to preserve order
USE_ASSERT(struct_var.GetSingleWordInOperand(kVariableStorageClassInIdx) !=
SpvStorageClassFunction &&
"cannot move Function variable");
Instruction* new_ptr_ty_inst = def_use_mgr->GetDef(new_ptr_ty_id);
struct_var.RemoveFromList();
struct_var.InsertAfter(new_ptr_ty_inst);
}
} // namespace opt
} // namespace spvtools

View File

@@ -0,0 +1,258 @@
// Copyright (c) 2022 The Khronos Group Inc.
// Copyright (c) 2022 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/opt/eliminate_dead_io_components_pass.h"
#include <set>
#include <vector>
#include "source/opt/instruction.h"
#include "source/opt/ir_builder.h"
#include "source/opt/ir_context.h"
#include "source/util/bit_vector.h"
namespace spvtools {
namespace opt {
namespace {
constexpr uint32_t kAccessChainBaseInIdx = 0;
constexpr uint32_t kAccessChainIndex0InIdx = 1;
constexpr uint32_t kAccessChainIndex1InIdx = 2;
constexpr uint32_t kConstantValueInIdx = 0;
} // namespace
Pass::Status EliminateDeadIOComponentsPass::Process() {
// Only process input and output variables
if (elim_sclass_ != spv::StorageClass::Input &&
elim_sclass_ != spv::StorageClass::Output) {
if (consumer()) {
std::string message =
"EliminateDeadIOComponentsPass only valid for input and output "
"variables.";
consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
}
return Status::Failure;
}
// If safe mode, only process Input variables in vertex shader
const auto stage = context()->GetStage();
if (safe_mode_ && !(stage == spv::ExecutionModel::Vertex &&
elim_sclass_ == spv::StorageClass::Input))
return Status::SuccessWithoutChange;
// Current functionality assumes shader capability.
if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
return Status::SuccessWithoutChange;
// Current functionality assumes vert, frag, tesc, tese or geom shader.
// TODO(issue #4988): Add GLCompute.
if (stage != spv::ExecutionModel::Vertex &&
stage != spv::ExecutionModel::Fragment &&
stage != spv::ExecutionModel::TessellationControl &&
stage != spv::ExecutionModel::TessellationEvaluation &&
stage != spv::ExecutionModel::Geometry)
return Status::SuccessWithoutChange;
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
analysis::TypeManager* type_mgr = context()->get_type_mgr();
bool modified = false;
std::vector<Instruction*> vars_to_move;
for (auto& var : context()->types_values()) {
if (var.opcode() != spv::Op::OpVariable) {
continue;
}
analysis::Type* var_type = type_mgr->GetType(var.type_id());
analysis::Pointer* ptr_type = var_type->AsPointer();
if (ptr_type == nullptr) {
continue;
}
const auto sclass = ptr_type->storage_class();
if (sclass != elim_sclass_) {
continue;
}
// For tesc, or input variables in tese or geom shaders,
// there is a outer per-vertex-array that must be ignored
// for the purposes of this analysis/optimization. Do the
// analysis on the inner type in these cases.
bool skip_first_index = false;
auto core_type = ptr_type->pointee_type();
if (stage == spv::ExecutionModel::TessellationControl ||
(sclass == spv::StorageClass::Input &&
(stage == spv::ExecutionModel::TessellationEvaluation ||
stage == spv::ExecutionModel::Geometry))) {
auto arr_type = core_type->AsArray();
if (!arr_type) continue;
core_type = arr_type->element_type();
skip_first_index = true;
}
const analysis::Array* arr_type = core_type->AsArray();
if (arr_type != nullptr) {
// Only process array if input of vertex shader, or output of
// fragment shader. Otherwise, if one shader has a runtime index and the
// other does not, interface incompatibility can occur.
if (!((sclass == spv::StorageClass::Input &&
stage == spv::ExecutionModel::Vertex) ||
(sclass == spv::StorageClass::Output &&
stage == spv::ExecutionModel::Fragment)))
continue;
unsigned arr_len_id = arr_type->LengthId();
Instruction* arr_len_inst = def_use_mgr->GetDef(arr_len_id);
if (arr_len_inst->opcode() != spv::Op::OpConstant) {
continue;
}
// SPIR-V requires array size is >= 1, so this works for signed or
// unsigned size.
unsigned original_max =
arr_len_inst->GetSingleWordInOperand(kConstantValueInIdx) - 1;
unsigned max_idx = FindMaxIndex(var, original_max);
if (max_idx != original_max) {
ChangeArrayLength(var, max_idx + 1);
vars_to_move.push_back(&var);
modified = true;
}
continue;
}
const analysis::Struct* struct_type = core_type->AsStruct();
if (struct_type == nullptr) continue;
const auto elt_types = struct_type->element_types();
unsigned original_max = static_cast<unsigned>(elt_types.size()) - 1;
unsigned max_idx = FindMaxIndex(var, original_max, skip_first_index);
if (max_idx != original_max) {
ChangeIOVarStructLength(var, max_idx + 1);
vars_to_move.push_back(&var);
modified = true;
}
}
// Move changed vars after their new type instruction to preserve backward
// referencing.
for (auto var : vars_to_move) {
auto type_id = var->type_id();
auto type_inst = def_use_mgr->GetDef(type_id);
var->RemoveFromList();
var->InsertAfter(type_inst);
}
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
unsigned EliminateDeadIOComponentsPass::FindMaxIndex(
const Instruction& var, const unsigned original_max,
const bool skip_first_index) {
unsigned max = 0;
bool seen_non_const_ac = false;
assert(var.opcode() == spv::Op::OpVariable && "must be variable");
context()->get_def_use_mgr()->WhileEachUser(
var.result_id(), [&max, &seen_non_const_ac, var, skip_first_index,
this](Instruction* use) {
auto use_opcode = use->opcode();
if (use_opcode == spv::Op::OpLoad || use_opcode == spv::Op::OpStore ||
use_opcode == spv::Op::OpCopyMemory ||
use_opcode == spv::Op::OpCopyMemorySized ||
use_opcode == spv::Op::OpCopyObject) {
seen_non_const_ac = true;
return false;
}
if (use->opcode() != spv::Op::OpAccessChain &&
use->opcode() != spv::Op::OpInBoundsAccessChain) {
return true;
}
// OpAccessChain with no indices currently not optimized
if (use->NumInOperands() == 1 ||
(skip_first_index && use->NumInOperands() == 2)) {
seen_non_const_ac = true;
return false;
}
const unsigned base_id =
use->GetSingleWordInOperand(kAccessChainBaseInIdx);
USE_ASSERT(base_id == var.result_id() && "unexpected base");
const unsigned in_idx = skip_first_index ? kAccessChainIndex1InIdx
: kAccessChainIndex0InIdx;
const unsigned idx_id = use->GetSingleWordInOperand(in_idx);
Instruction* idx_inst = context()->get_def_use_mgr()->GetDef(idx_id);
if (idx_inst->opcode() != spv::Op::OpConstant) {
seen_non_const_ac = true;
return false;
}
unsigned value = idx_inst->GetSingleWordInOperand(kConstantValueInIdx);
if (value > max) max = value;
return true;
});
return seen_non_const_ac ? original_max : max;
}
void EliminateDeadIOComponentsPass::ChangeArrayLength(Instruction& arr_var,
unsigned length) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
analysis::Pointer* ptr_type =
type_mgr->GetType(arr_var.type_id())->AsPointer();
const analysis::Array* arr_ty = ptr_type->pointee_type()->AsArray();
assert(arr_ty && "expecting array type");
uint32_t length_id = const_mgr->GetUIntConstId(length);
analysis::Array new_arr_ty(arr_ty->element_type(),
arr_ty->GetConstantLengthInfo(length_id, length));
analysis::Type* reg_new_arr_ty = type_mgr->GetRegisteredType(&new_arr_ty);
analysis::Pointer new_ptr_ty(reg_new_arr_ty, ptr_type->storage_class());
analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
arr_var.SetResultType(new_ptr_ty_id);
def_use_mgr->AnalyzeInstUse(&arr_var);
}
void EliminateDeadIOComponentsPass::ChangeIOVarStructLength(Instruction& io_var,
unsigned length) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::Pointer* ptr_type =
type_mgr->GetType(io_var.type_id())->AsPointer();
auto core_type = ptr_type->pointee_type();
// Check for per-vertex-array of struct from tesc, tese and geom and grab
// embedded struct type.
const auto arr_type = core_type->AsArray();
if (arr_type) core_type = arr_type->element_type();
const analysis::Struct* struct_ty = core_type->AsStruct();
assert(struct_ty && "expecting struct type");
const auto orig_elt_types = struct_ty->element_types();
std::vector<const analysis::Type*> new_elt_types;
for (unsigned u = 0; u < length; ++u)
new_elt_types.push_back(orig_elt_types[u]);
analysis::Struct new_struct_ty(new_elt_types);
uint32_t old_struct_ty_id = type_mgr->GetTypeInstruction(struct_ty);
std::vector<Instruction*> decorations =
context()->get_decoration_mgr()->GetDecorationsFor(old_struct_ty_id,
true);
for (auto dec : decorations) {
if (dec->opcode() == spv::Op::OpMemberDecorate) {
uint32_t midx = dec->GetSingleWordInOperand(1);
if (midx >= length) continue;
}
type_mgr->AttachDecoration(*dec, &new_struct_ty);
}
// Clone name instructions for new struct type
analysis::Type* reg_new_str_ty = type_mgr->GetRegisteredType(&new_struct_ty);
uint32_t new_struct_ty_id = type_mgr->GetTypeInstruction(reg_new_str_ty);
context()->CloneNames(old_struct_ty_id, new_struct_ty_id, length);
// Attach new type to var
analysis::Type* reg_new_var_ty = reg_new_str_ty;
if (arr_type) {
analysis::Array new_arr_ty(reg_new_var_ty, arr_type->length_info());
reg_new_var_ty = type_mgr->GetRegisteredType(&new_arr_ty);
}
analysis::Pointer new_ptr_ty(reg_new_var_ty, elim_sclass_);
analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
io_var.SetResultType(new_ptr_ty_id);
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
def_use_mgr->AnalyzeInstUse(&io_var);
}
} // namespace opt
} // namespace spvtools

View File

@@ -26,14 +26,15 @@ namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class EliminateDeadInputComponentsPass : public Pass {
class EliminateDeadIOComponentsPass : public Pass {
public:
explicit EliminateDeadInputComponentsPass() {}
explicit EliminateDeadIOComponentsPass(spv::StorageClass elim_sclass,
bool safe_mode = true)
: elim_sclass_(elim_sclass), safe_mode_(safe_mode) {}
const char* name() const override {
return "eliminate-dead-input-components";
}
Status Process() override;
// Return the mask of preserved Analyses.
@@ -50,13 +51,22 @@ class EliminateDeadInputComponentsPass : public Pass {
// Find the max constant used to index the variable declared by |var|
// through OpAccessChain or OpInBoundsAccessChain. If any non-constant
// indices or non-Op*AccessChain use of |var|, return |original_max|.
unsigned FindMaxIndex(Instruction& var, unsigned original_max);
unsigned FindMaxIndex(const Instruction& var, const unsigned original_max,
const bool skip_first_index = false);
// Change the length of the array |inst| to |length|
void ChangeArrayLength(Instruction& inst, unsigned length);
// Change the length of the struct |struct_var| to |length|
void ChangeStructLength(Instruction& struct_var, unsigned length);
// Change the length of the struct in |io_var| to |length|. |io_var|
// is either the struct or a per-vertex-array of the struct.
void ChangeIOVarStructLength(Instruction& io_var, unsigned length);
// Storage class to be optimized. Must be Input or Output.
spv::StorageClass elim_sclass_;
// Only make changes that will not cause interface incompatibility if done
// standalone. Currently this is only Input variables in vertex shaders.
bool safe_mode_;
};
} // namespace opt

View File

@@ -17,17 +17,16 @@
#include "ir_builder.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace opt {
namespace {
const uint32_t kRemovedMember = 0xFFFFFFFF;
const uint32_t kSpecConstOpOpcodeIdx = 0;
constexpr uint32_t kRemovedMember = 0xFFFFFFFF;
constexpr uint32_t kSpecConstOpOpcodeIdx = 0;
constexpr uint32_t kArrayElementTypeIdx = 0;
} // namespace
namespace spvtools {
namespace opt {
Pass::Status EliminateDeadMembersPass::Process() {
if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
return Status::SuccessWithoutChange;
FindLiveMembers();
@@ -41,27 +40,27 @@ void EliminateDeadMembersPass::FindLiveMembers() {
// Until we have implemented the rewriting of OpSpecConsantOp instructions,
// we have to mark them as fully used just to be safe.
for (auto& inst : get_module()->types_values()) {
if (inst.opcode() == SpvOpSpecConstantOp) {
switch (inst.GetSingleWordInOperand(kSpecConstOpOpcodeIdx)) {
case SpvOpCompositeExtract:
if (inst.opcode() == spv::Op::OpSpecConstantOp) {
switch (spv::Op(inst.GetSingleWordInOperand(kSpecConstOpOpcodeIdx))) {
case spv::Op::OpCompositeExtract:
MarkMembersAsLiveForExtract(&inst);
break;
case SpvOpCompositeInsert:
case spv::Op::OpCompositeInsert:
// Nothing specific to do.
break;
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
assert(false && "Not implemented yet.");
break;
default:
break;
}
} else if (inst.opcode() == SpvOpVariable) {
switch (inst.GetSingleWordInOperand(0)) {
case SpvStorageClassInput:
case SpvStorageClassOutput:
} else if (inst.opcode() == spv::Op::OpVariable) {
switch (spv::StorageClass(inst.GetSingleWordInOperand(0))) {
case spv::StorageClass::Input:
case spv::StorageClass::Output:
MarkPointeeTypeAsFullUsed(inst.type_id());
break;
default:
@@ -86,34 +85,34 @@ void EliminateDeadMembersPass::FindLiveMembers(const Function& function) {
void EliminateDeadMembersPass::FindLiveMembers(const Instruction* inst) {
switch (inst->opcode()) {
case SpvOpStore:
case spv::Op::OpStore:
MarkMembersAsLiveForStore(inst);
break;
case SpvOpCopyMemory:
case SpvOpCopyMemorySized:
case spv::Op::OpCopyMemory:
case spv::Op::OpCopyMemorySized:
MarkMembersAsLiveForCopyMemory(inst);
break;
case SpvOpCompositeExtract:
case spv::Op::OpCompositeExtract:
MarkMembersAsLiveForExtract(inst);
break;
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
MarkMembersAsLiveForAccessChain(inst);
break;
case SpvOpReturnValue:
case spv::Op::OpReturnValue:
// This should be an issue only if we are returning from the entry point.
// However, for now I will keep it more conservative because functions are
// often inlined leaving only the entry points.
MarkOperandTypeAsFullyUsed(inst, 0);
break;
case SpvOpArrayLength:
case spv::Op::OpArrayLength:
MarkMembersAsLiveForArrayLength(inst);
break;
case SpvOpLoad:
case SpvOpCompositeInsert:
case SpvOpCompositeConstruct:
case spv::Op::OpLoad:
case spv::Op::OpCompositeInsert:
case spv::Op::OpCompositeConstruct:
break;
default:
// This path is here for safety. All instructions that can reference
@@ -131,7 +130,7 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForStore(
// memory that is read outside of the shader. Other passes can remove all
// store to memory that is not visible outside of the shader, so we do not
// complicate the code for now.
assert(inst->opcode() == SpvOpStore);
assert(inst->opcode() == spv::Op::OpStore);
uint32_t object_id = inst->GetSingleWordInOperand(1);
Instruction* object_inst = context()->get_def_use_mgr()->GetDef(object_id);
uint32_t object_type_id = object_inst->type_id();
@@ -143,15 +142,15 @@ void EliminateDeadMembersPass::MarkTypeAsFullyUsed(uint32_t type_id) {
assert(type_inst != nullptr);
switch (type_inst->opcode()) {
case SpvOpTypeStruct:
case spv::Op::OpTypeStruct:
// Mark every member and its type as fully used.
for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) {
used_members_[type_id].insert(i);
MarkTypeAsFullyUsed(type_inst->GetSingleWordInOperand(i));
}
break;
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
MarkTypeAsFullyUsed(
type_inst->GetSingleWordInOperand(kArrayElementTypeIdx));
break;
@@ -162,7 +161,7 @@ void EliminateDeadMembersPass::MarkTypeAsFullyUsed(uint32_t type_id) {
void EliminateDeadMembersPass::MarkPointeeTypeAsFullUsed(uint32_t ptr_type_id) {
Instruction* ptr_type_inst = get_def_use_mgr()->GetDef(ptr_type_id);
assert(ptr_type_inst->opcode() == SpvOpTypePointer);
assert(ptr_type_inst->opcode() == spv::Op::OpTypePointer);
MarkTypeAsFullyUsed(ptr_type_inst->GetSingleWordInOperand(1));
}
@@ -178,12 +177,13 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForCopyMemory(
void EliminateDeadMembersPass::MarkMembersAsLiveForExtract(
const Instruction* inst) {
assert(inst->opcode() == SpvOpCompositeExtract ||
(inst->opcode() == SpvOpSpecConstantOp &&
inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx) ==
SpvOpCompositeExtract));
assert(inst->opcode() == spv::Op::OpCompositeExtract ||
(inst->opcode() == spv::Op::OpSpecConstantOp &&
spv::Op(inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx)) ==
spv::Op::OpCompositeExtract));
uint32_t first_operand = (inst->opcode() == SpvOpSpecConstantOp ? 1 : 0);
uint32_t first_operand =
(inst->opcode() == spv::Op::OpSpecConstantOp ? 1 : 0);
uint32_t composite_id = inst->GetSingleWordInOperand(first_operand);
Instruction* composite_inst = get_def_use_mgr()->GetDef(composite_id);
uint32_t type_id = composite_inst->type_id();
@@ -192,14 +192,14 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForExtract(
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
uint32_t member_idx = inst->GetSingleWordInOperand(i);
switch (type_inst->opcode()) {
case SpvOpTypeStruct:
case spv::Op::OpTypeStruct:
used_members_[type_id].insert(member_idx);
type_id = type_inst->GetSingleWordInOperand(member_idx);
break;
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
type_id = type_inst->GetSingleWordInOperand(0);
break;
default:
@@ -210,10 +210,10 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForExtract(
void EliminateDeadMembersPass::MarkMembersAsLiveForAccessChain(
const Instruction* inst) {
assert(inst->opcode() == SpvOpAccessChain ||
inst->opcode() == SpvOpInBoundsAccessChain ||
inst->opcode() == SpvOpPtrAccessChain ||
inst->opcode() == SpvOpInBoundsPtrAccessChain);
assert(inst->opcode() == spv::Op::OpAccessChain ||
inst->opcode() == spv::Op::OpInBoundsAccessChain ||
inst->opcode() == spv::Op::OpPtrAccessChain ||
inst->opcode() == spv::Op::OpInBoundsPtrAccessChain);
uint32_t pointer_id = inst->GetSingleWordInOperand(0);
Instruction* pointer_inst = get_def_use_mgr()->GetDef(pointer_id);
@@ -225,14 +225,14 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForAccessChain(
// For a pointer access chain, we need to skip the |element| index. It is not
// a reference to the member of a struct, and it does not change the type.
uint32_t i = (inst->opcode() == SpvOpAccessChain ||
inst->opcode() == SpvOpInBoundsAccessChain
uint32_t i = (inst->opcode() == spv::Op::OpAccessChain ||
inst->opcode() == spv::Op::OpInBoundsAccessChain
? 1
: 2);
for (; i < inst->NumInOperands(); ++i) {
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
switch (type_inst->opcode()) {
case SpvOpTypeStruct: {
case spv::Op::OpTypeStruct: {
const analysis::IntConstant* member_idx =
const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
->AsIntConstant();
@@ -242,10 +242,10 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForAccessChain(
used_members_[type_id].insert(index);
type_id = type_inst->GetSingleWordInOperand(index);
} break;
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
type_id = type_inst->GetSingleWordInOperand(0);
break;
default:
@@ -263,7 +263,7 @@ void EliminateDeadMembersPass::MarkOperandTypeAsFullyUsed(
void EliminateDeadMembersPass::MarkMembersAsLiveForArrayLength(
const Instruction* inst) {
assert(inst->opcode() == SpvOpArrayLength);
assert(inst->opcode() == spv::Op::OpArrayLength);
uint32_t object_id = inst->GetSingleWordInOperand(0);
Instruction* object_inst = get_def_use_mgr()->GetDef(object_id);
uint32_t pointer_type_id = object_inst->type_id();
@@ -278,7 +278,7 @@ bool EliminateDeadMembersPass::RemoveDeadMembers() {
// First update all of the OpTypeStruct instructions.
get_module()->ForEachInst([&modified, this](Instruction* inst) {
switch (inst->opcode()) {
case SpvOpTypeStruct:
case spv::Op::OpTypeStruct:
modified |= UpdateOpTypeStruct(inst);
break;
default:
@@ -289,47 +289,47 @@ bool EliminateDeadMembersPass::RemoveDeadMembers() {
// Now update all of the instructions that reference the OpTypeStructs.
get_module()->ForEachInst([&modified, this](Instruction* inst) {
switch (inst->opcode()) {
case SpvOpMemberName:
case spv::Op::OpMemberName:
modified |= UpdateOpMemberNameOrDecorate(inst);
break;
case SpvOpMemberDecorate:
case spv::Op::OpMemberDecorate:
modified |= UpdateOpMemberNameOrDecorate(inst);
break;
case SpvOpGroupMemberDecorate:
case spv::Op::OpGroupMemberDecorate:
modified |= UpdateOpGroupMemberDecorate(inst);
break;
case SpvOpSpecConstantComposite:
case SpvOpConstantComposite:
case SpvOpCompositeConstruct:
case spv::Op::OpSpecConstantComposite:
case spv::Op::OpConstantComposite:
case spv::Op::OpCompositeConstruct:
modified |= UpdateConstantComposite(inst);
break;
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
modified |= UpdateAccessChain(inst);
break;
case SpvOpCompositeExtract:
case spv::Op::OpCompositeExtract:
modified |= UpdateCompsiteExtract(inst);
break;
case SpvOpCompositeInsert:
case spv::Op::OpCompositeInsert:
modified |= UpdateCompositeInsert(inst);
break;
case SpvOpArrayLength:
case spv::Op::OpArrayLength:
modified |= UpdateOpArrayLength(inst);
break;
case SpvOpSpecConstantOp:
switch (inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx)) {
case SpvOpCompositeExtract:
case spv::Op::OpSpecConstantOp:
switch (spv::Op(inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx))) {
case spv::Op::OpCompositeExtract:
modified |= UpdateCompsiteExtract(inst);
break;
case SpvOpCompositeInsert:
case spv::Op::OpCompositeInsert:
modified |= UpdateCompositeInsert(inst);
break;
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
assert(false && "Not implemented yet.");
break;
default:
@@ -344,7 +344,7 @@ bool EliminateDeadMembersPass::RemoveDeadMembers() {
}
bool EliminateDeadMembersPass::UpdateOpTypeStruct(Instruction* inst) {
assert(inst->opcode() == SpvOpTypeStruct);
assert(inst->opcode() == spv::Op::OpTypeStruct);
const auto& live_members = used_members_[inst->result_id()];
if (live_members.size() == inst->NumInOperands()) {
@@ -362,8 +362,8 @@ bool EliminateDeadMembersPass::UpdateOpTypeStruct(Instruction* inst) {
}
bool EliminateDeadMembersPass::UpdateOpMemberNameOrDecorate(Instruction* inst) {
assert(inst->opcode() == SpvOpMemberName ||
inst->opcode() == SpvOpMemberDecorate);
assert(inst->opcode() == spv::Op::OpMemberName ||
inst->opcode() == spv::Op::OpMemberDecorate);
uint32_t type_id = inst->GetSingleWordInOperand(0);
auto live_members = used_members_.find(type_id);
@@ -388,7 +388,7 @@ bool EliminateDeadMembersPass::UpdateOpMemberNameOrDecorate(Instruction* inst) {
}
bool EliminateDeadMembersPass::UpdateOpGroupMemberDecorate(Instruction* inst) {
assert(inst->opcode() == SpvOpGroupMemberDecorate);
assert(inst->opcode() == spv::Op::OpGroupMemberDecorate);
bool modified = false;
@@ -429,9 +429,9 @@ bool EliminateDeadMembersPass::UpdateOpGroupMemberDecorate(Instruction* inst) {
}
bool EliminateDeadMembersPass::UpdateConstantComposite(Instruction* inst) {
assert(inst->opcode() == SpvOpSpecConstantComposite ||
inst->opcode() == SpvOpConstantComposite ||
inst->opcode() == SpvOpCompositeConstruct);
assert(inst->opcode() == spv::Op::OpSpecConstantComposite ||
inst->opcode() == spv::Op::OpConstantComposite ||
inst->opcode() == spv::Op::OpCompositeConstruct);
uint32_t type_id = inst->type_id();
bool modified = false;
@@ -450,10 +450,10 @@ bool EliminateDeadMembersPass::UpdateConstantComposite(Instruction* inst) {
}
bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) {
assert(inst->opcode() == SpvOpAccessChain ||
inst->opcode() == SpvOpInBoundsAccessChain ||
inst->opcode() == SpvOpPtrAccessChain ||
inst->opcode() == SpvOpInBoundsPtrAccessChain);
assert(inst->opcode() == spv::Op::OpAccessChain ||
inst->opcode() == spv::Op::OpInBoundsAccessChain ||
inst->opcode() == spv::Op::OpPtrAccessChain ||
inst->opcode() == spv::Op::OpInBoundsPtrAccessChain);
uint32_t pointer_id = inst->GetSingleWordInOperand(0);
Instruction* pointer_inst = get_def_use_mgr()->GetDef(pointer_id);
@@ -467,8 +467,8 @@ bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) {
new_operands.emplace_back(inst->GetInOperand(0));
// For pointer access chains we want to copy the element operand.
if (inst->opcode() == SpvOpPtrAccessChain ||
inst->opcode() == SpvOpInBoundsPtrAccessChain) {
if (inst->opcode() == spv::Op::OpPtrAccessChain ||
inst->opcode() == spv::Op::OpInBoundsPtrAccessChain) {
new_operands.emplace_back(inst->GetInOperand(1));
}
@@ -476,7 +476,7 @@ bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) {
i < inst->NumInOperands(); ++i) {
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
switch (type_inst->opcode()) {
case SpvOpTypeStruct: {
case spv::Op::OpTypeStruct: {
const analysis::IntConstant* member_idx =
const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
->AsIntConstant();
@@ -501,10 +501,10 @@ bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) {
// index.
type_id = type_inst->GetSingleWordInOperand(new_member_idx);
} break;
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
new_operands.emplace_back(inst->GetInOperand(i));
type_id = type_inst->GetSingleWordInOperand(0);
break;
@@ -539,13 +539,13 @@ uint32_t EliminateDeadMembersPass::GetNewMemberIndex(uint32_t type_id,
}
bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) {
assert(inst->opcode() == SpvOpCompositeExtract ||
(inst->opcode() == SpvOpSpecConstantOp &&
inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx) ==
SpvOpCompositeExtract));
assert(inst->opcode() == spv::Op::OpCompositeExtract ||
(inst->opcode() == spv::Op::OpSpecConstantOp &&
spv::Op(inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx)) ==
spv::Op::OpCompositeExtract));
uint32_t first_operand = 0;
if (inst->opcode() == SpvOpSpecConstantOp) {
if (inst->opcode() == spv::Op::OpSpecConstantOp) {
first_operand = 1;
}
uint32_t object_id = inst->GetSingleWordInOperand(first_operand);
@@ -569,15 +569,15 @@ bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) {
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
switch (type_inst->opcode()) {
case SpvOpTypeStruct:
case spv::Op::OpTypeStruct:
// The type will have already been rewritten, so use the new member
// index.
type_id = type_inst->GetSingleWordInOperand(new_member_idx);
break;
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
type_id = type_inst->GetSingleWordInOperand(0);
break;
default:
@@ -594,13 +594,13 @@ bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) {
}
bool EliminateDeadMembersPass::UpdateCompositeInsert(Instruction* inst) {
assert(inst->opcode() == SpvOpCompositeInsert ||
(inst->opcode() == SpvOpSpecConstantOp &&
inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx) ==
SpvOpCompositeInsert));
assert(inst->opcode() == spv::Op::OpCompositeInsert ||
(inst->opcode() == spv::Op::OpSpecConstantOp &&
spv::Op(inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx)) ==
spv::Op::OpCompositeInsert));
uint32_t first_operand = 0;
if (inst->opcode() == SpvOpSpecConstantOp) {
if (inst->opcode() == spv::Op::OpSpecConstantOp) {
first_operand = 1;
}
@@ -630,15 +630,15 @@ bool EliminateDeadMembersPass::UpdateCompositeInsert(Instruction* inst) {
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
switch (type_inst->opcode()) {
case SpvOpTypeStruct:
case spv::Op::OpTypeStruct:
// The type will have already been rewritten, so use the new member
// index.
type_id = type_inst->GetSingleWordInOperand(new_member_idx);
break;
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeVector:
case SpvOpTypeMatrix:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeVector:
case spv::Op::OpTypeMatrix:
type_id = type_inst->GetSingleWordInOperand(0);
break;
default:

View File

@@ -0,0 +1,237 @@
// Copyright (c) 2022 The Khronos Group Inc.
// Copyright (c) 2022 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/opt/eliminate_dead_output_stores_pass.h"
#include "source/opt/instruction.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace opt {
namespace {
constexpr uint32_t kDecorationLocationInIdx = 2;
constexpr uint32_t kOpDecorateMemberMemberInIdx = 1;
constexpr uint32_t kOpDecorateBuiltInLiteralInIdx = 2;
constexpr uint32_t kOpDecorateMemberBuiltInLiteralInIdx = 3;
constexpr uint32_t kOpAccessChainIdx0InIdx = 1;
constexpr uint32_t kOpConstantValueInIdx = 0;
} // namespace
Pass::Status EliminateDeadOutputStoresPass::Process() {
// Current functionality assumes shader capability
if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
return Status::SuccessWithoutChange;
Pass::Status status = DoDeadOutputStoreElimination();
return status;
}
void EliminateDeadOutputStoresPass::InitializeElimination() {
kill_list_.clear();
}
bool EliminateDeadOutputStoresPass::IsLiveBuiltin(uint32_t bi) {
return live_builtins_->find(bi) != live_builtins_->end();
}
bool EliminateDeadOutputStoresPass::AnyLocsAreLive(uint32_t start,
uint32_t count) {
auto finish = start + count;
for (uint32_t u = start; u < finish; ++u) {
if (live_locs_->find(u) != live_locs_->end()) return true;
}
return false;
}
void EliminateDeadOutputStoresPass::KillAllStoresOfRef(Instruction* ref) {
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
if (ref->opcode() == spv::Op::OpStore) {
kill_list_.push_back(ref);
return;
}
assert((ref->opcode() == spv::Op::OpAccessChain ||
ref->opcode() == spv::Op::OpInBoundsAccessChain) &&
"unexpected use of output variable");
def_use_mgr->ForEachUser(ref, [this](Instruction* user) {
if (user->opcode() == spv::Op::OpStore) kill_list_.push_back(user);
});
}
void EliminateDeadOutputStoresPass::KillAllDeadStoresOfLocRef(
Instruction* ref, Instruction* var) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::DecorationManager* deco_mgr = context()->get_decoration_mgr();
analysis::LivenessManager* live_mgr = context()->get_liveness_mgr();
// Find variable location if present.
uint32_t start_loc = 0;
auto var_id = var->result_id();
bool no_loc = deco_mgr->WhileEachDecoration(
var_id, uint32_t(spv::Decoration::Location),
[&start_loc](const Instruction& deco) {
assert(deco.opcode() == spv::Op::OpDecorate && "unexpected decoration");
start_loc = deco.GetSingleWordInOperand(kDecorationLocationInIdx);
return false;
});
// Find patch decoration if present
bool is_patch = !deco_mgr->WhileEachDecoration(
var_id, uint32_t(spv::Decoration::Patch), [](const Instruction& deco) {
if (deco.opcode() != spv::Op::OpDecorate)
assert(false && "unexpected decoration");
return false;
});
// Compute offset and final type of reference. If no location found
// or any stored locations are live, return without removing stores.
auto ptr_type = type_mgr->GetType(var->type_id())->AsPointer();
assert(ptr_type && "unexpected var type");
auto var_type = ptr_type->pointee_type();
uint32_t ref_loc = start_loc;
auto curr_type = var_type;
if (ref->opcode() == spv::Op::OpAccessChain ||
ref->opcode() == spv::Op::OpInBoundsAccessChain) {
live_mgr->AnalyzeAccessChainLoc(ref, &curr_type, &ref_loc, &no_loc,
is_patch, /* input */ false);
}
if (no_loc || AnyLocsAreLive(ref_loc, live_mgr->GetLocSize(curr_type)))
return;
// Kill all stores based on this reference
KillAllStoresOfRef(ref);
}
void EliminateDeadOutputStoresPass::KillAllDeadStoresOfBuiltinRef(
Instruction* ref, Instruction* var) {
auto deco_mgr = context()->get_decoration_mgr();
auto def_use_mgr = context()->get_def_use_mgr();
auto type_mgr = context()->get_type_mgr();
auto live_mgr = context()->get_liveness_mgr();
// Search for builtin decoration of base variable
uint32_t builtin = uint32_t(spv::BuiltIn::Max);
auto var_id = var->result_id();
(void)deco_mgr->WhileEachDecoration(
var_id, uint32_t(spv::Decoration::BuiltIn),
[&builtin](const Instruction& deco) {
assert(deco.opcode() == spv::Op::OpDecorate && "unexpected decoration");
builtin = deco.GetSingleWordInOperand(kOpDecorateBuiltInLiteralInIdx);
return false;
});
// If analyzed builtin and not live, kill stores.
if (builtin != uint32_t(spv::BuiltIn::Max)) {
if (live_mgr->IsAnalyzedBuiltin(builtin) && !IsLiveBuiltin(builtin))
KillAllStoresOfRef(ref);
return;
}
// Search for builtin decoration on indexed member
auto ref_op = ref->opcode();
if (ref_op != spv::Op::OpAccessChain &&
ref_op != spv::Op::OpInBoundsAccessChain) {
return;
}
uint32_t in_idx = kOpAccessChainIdx0InIdx;
analysis::Type* var_type = type_mgr->GetType(var->type_id());
analysis::Pointer* ptr_type = var_type->AsPointer();
auto curr_type = ptr_type->pointee_type();
auto arr_type = curr_type->AsArray();
if (arr_type) {
curr_type = arr_type->element_type();
++in_idx;
}
auto str_type = curr_type->AsStruct();
auto str_type_id = type_mgr->GetId(str_type);
auto member_idx_id = ref->GetSingleWordInOperand(in_idx);
auto member_idx_inst = def_use_mgr->GetDef(member_idx_id);
assert(member_idx_inst->opcode() == spv::Op::OpConstant &&
"unexpected non-constant index");
auto ac_idx = member_idx_inst->GetSingleWordInOperand(kOpConstantValueInIdx);
(void)deco_mgr->WhileEachDecoration(
str_type_id, uint32_t(spv::Decoration::BuiltIn),
[ac_idx, &builtin](const Instruction& deco) {
assert(deco.opcode() == spv::Op::OpMemberDecorate &&
"unexpected decoration");
auto deco_idx =
deco.GetSingleWordInOperand(kOpDecorateMemberMemberInIdx);
if (deco_idx == ac_idx) {
builtin =
deco.GetSingleWordInOperand(kOpDecorateMemberBuiltInLiteralInIdx);
return false;
}
return true;
});
assert(builtin != uint32_t(spv::BuiltIn::Max) && "builtin not found");
// If analyzed builtin and not live, kill stores.
if (live_mgr->IsAnalyzedBuiltin(builtin) && !IsLiveBuiltin(builtin))
KillAllStoresOfRef(ref);
}
Pass::Status EliminateDeadOutputStoresPass::DoDeadOutputStoreElimination() {
// Current implementation only supports vert, tesc, tese, geom shaders
auto stage = context()->GetStage();
if (stage != spv::ExecutionModel::Vertex &&
stage != spv::ExecutionModel::TessellationControl &&
stage != spv::ExecutionModel::TessellationEvaluation &&
stage != spv::ExecutionModel::Geometry)
return Status::Failure;
InitializeElimination();
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::DecorationManager* deco_mgr = context()->get_decoration_mgr();
// Process all output variables
for (auto& var : context()->types_values()) {
if (var.opcode() != spv::Op::OpVariable) {
continue;
}
analysis::Type* var_type = type_mgr->GetType(var.type_id());
analysis::Pointer* ptr_type = var_type->AsPointer();
if (ptr_type->storage_class() != spv::StorageClass::Output) {
continue;
}
// If builtin decoration on variable, process as builtin.
auto var_id = var.result_id();
bool is_builtin = false;
if (deco_mgr->HasDecoration(var_id, uint32_t(spv::Decoration::BuiltIn))) {
is_builtin = true;
} else {
// If interface block with builtin members, process as builtin.
// Strip off outer array type if present.
auto curr_type = ptr_type->pointee_type();
auto arr_type = curr_type->AsArray();
if (arr_type) curr_type = arr_type->element_type();
auto str_type = curr_type->AsStruct();
if (str_type) {
auto str_type_id = type_mgr->GetId(str_type);
if (deco_mgr->HasDecoration(str_type_id,
uint32_t(spv::Decoration::BuiltIn)))
is_builtin = true;
}
}
// For each store or access chain using var, if dead builtin or all its
// locations are dead, kill store or all access chain's stores
def_use_mgr->ForEachUser(
var_id, [this, &var, is_builtin](Instruction* user) {
auto op = user->opcode();
if (op == spv::Op::OpEntryPoint || op == spv::Op::OpName ||
op == spv::Op::OpDecorate)
return;
if (is_builtin)
KillAllDeadStoresOfBuiltinRef(user, &var);
else
KillAllDeadStoresOfLocRef(user, &var);
});
}
for (auto& kinst : kill_list_) context()->KillInst(kinst);
return kill_list_.empty() ? Status::SuccessWithoutChange
: Status::SuccessWithChange;
}
} // namespace opt
} // namespace spvtools

View File

@@ -0,0 +1,87 @@
// Copyright (c) 2022 The Khronos Group Inc.
// Copyright (c) 2022 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_OPT_ELIMINATE_DEAD_OUTPUT_STORES_H_
#define SOURCE_OPT_ELIMINATE_DEAD_OUTPUT_STORES_H_
#include <unordered_set>
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
#include "source/opt/pass.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class EliminateDeadOutputStoresPass : public Pass {
public:
explicit EliminateDeadOutputStoresPass(
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins)
: live_locs_(live_locs), live_builtins_(live_builtins) {}
const char* name() const override { return "eliminate-dead-output-stores"; }
Status Process() override;
// Return the mask of preserved Analyses.
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse |
IRContext::kAnalysisInstrToBlockMapping |
IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG |
IRContext::kAnalysisDominatorAnalysis |
IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap |
IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
}
private:
// Initialize elimination
void InitializeElimination();
// Do dead output store analysis
Status DoDeadOutputStoreAnalysis();
// Do dead output store analysis
Status DoDeadOutputStoreElimination();
// Mark all locations live
void MarkAllLocsLive();
// Kill all stores resulting from |ref|.
void KillAllStoresOfRef(Instruction* ref);
// Kill all dead stores resulting from |user| of loc-based |var|.
void KillAllDeadStoresOfLocRef(Instruction* user, Instruction* var);
// Kill all dead stores resulting from |user| of builtin |var|.
void KillAllDeadStoresOfBuiltinRef(Instruction* user, Instruction* var);
// Return true if any of |count| locations starting at location |start| are
// live.
bool AnyLocsAreLive(uint32_t start, uint32_t count);
// Return true if builtin |bi| is live.
bool IsLiveBuiltin(uint32_t bi);
std::unordered_set<uint32_t>* live_locs_;
std::unordered_set<uint32_t>* live_builtins_;
std::vector<Instruction*> kill_list_;
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_ELIMINATE_DEAD_OUTPUT_STORES_H_

View File

@@ -36,7 +36,7 @@ void FeatureManager::AddExtensions(Module* module) {
}
void FeatureManager::AddExtension(Instruction* ext) {
assert(ext->opcode() == SpvOpExtension &&
assert(ext->opcode() == spv::Op::OpExtension &&
"Expecting an extension instruction.");
const std::string name = ext->GetInOperand(0u).AsString();
@@ -51,27 +51,27 @@ void FeatureManager::RemoveExtension(Extension ext) {
extensions_.Remove(ext);
}
void FeatureManager::AddCapability(SpvCapability cap) {
void FeatureManager::AddCapability(spv::Capability cap) {
if (capabilities_.Contains(cap)) return;
capabilities_.Add(cap);
spv_operand_desc desc = {};
if (SPV_SUCCESS ==
grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) {
if (SPV_SUCCESS == grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
uint32_t(cap), &desc)) {
CapabilitySet(desc->numCapabilities, desc->capabilities)
.ForEach([this](SpvCapability c) { AddCapability(c); });
.ForEach([this](spv::Capability c) { AddCapability(c); });
}
}
void FeatureManager::RemoveCapability(SpvCapability cap) {
void FeatureManager::RemoveCapability(spv::Capability cap) {
if (!capabilities_.Contains(cap)) return;
capabilities_.Remove(cap);
}
void FeatureManager::AddCapabilities(Module* module) {
for (Instruction& inst : module->capabilities()) {
AddCapability(static_cast<SpvCapability>(inst.GetSingleWordInOperand(0)));
AddCapability(static_cast<spv::Capability>(inst.GetSingleWordInOperand(0)));
}
}

View File

@@ -34,12 +34,12 @@ class FeatureManager {
void RemoveExtension(Extension extension);
// Returns true if |cap| is an enabled capability in the module.
bool HasCapability(SpvCapability cap) const {
bool HasCapability(spv::Capability cap) const {
return capabilities_.Contains(cap);
}
// Removes the given |capability| from the current FeatureManager.
void RemoveCapability(SpvCapability capability);
void RemoveCapability(spv::Capability capability);
// Analyzes |module| and records enabled extensions and capabilities.
void Analyze(Module* module);
@@ -66,7 +66,7 @@ class FeatureManager {
// Adds the given |capability| and all implied capabilities into the current
// FeatureManager.
void AddCapability(SpvCapability capability);
void AddCapability(spv::Capability capability);
// Add the extension |ext| to the feature manager.
void AddExtension(Instruction* ext);

View File

@@ -29,7 +29,7 @@ Pass::Status FixFuncCallArgumentsPass::Process() {
if (ModuleHasASingleFunction()) return Status::SuccessWithoutChange;
for (auto& func : *get_module()) {
func.ForEachInst([this, &modified](Instruction* inst) {
if (inst->opcode() == SpvOpFunctionCall) {
if (inst->opcode() == spv::Op::OpFunctionCall) {
modified |= FixFuncCallArguments(inst);
}
});
@@ -44,7 +44,7 @@ bool FixFuncCallArgumentsPass::FixFuncCallArguments(
Operand& op = func_call_inst->GetInOperand(i);
if (op.type != SPV_OPERAND_TYPE_ID) continue;
Instruction* operand_inst = get_def_use_mgr()->GetDef(op.AsId());
if (operand_inst->opcode() == SpvOpAccessChain) {
if (operand_inst->opcode() == spv::Op::OpAccessChain) {
uint32_t var_id =
ReplaceAccessChainFuncCallArguments(func_call_inst, operand_inst);
func_call_inst->SetInOperand(i, {var_id});
@@ -71,10 +71,11 @@ uint32_t FixFuncCallArgumentsPass::ReplaceAccessChainFuncCallArguments(
Instruction* op_type =
get_def_use_mgr()->GetDef(op_ptr_type->GetSingleWordInOperand(1));
uint32_t varType = context()->get_type_mgr()->FindPointerToType(
op_type->result_id(), SpvStorageClassFunction);
op_type->result_id(), spv::StorageClass::Function);
// Create new variable
builder.SetInsertPoint(variable_insertion_point);
Instruction* var = builder.AddVariable(varType, SpvStorageClassFunction);
Instruction* var =
builder.AddVariable(varType, uint32_t(spv::StorageClass::Function));
// Load access chain to the new variable before function call
builder.SetInsertPoint(func_call_inst);

View File

@@ -26,7 +26,7 @@ Pass::Status FixStorageClass::Process() {
bool modified = false;
get_module()->ForEachInst([this, &modified](Instruction* inst) {
if (inst->opcode() == SpvOpVariable) {
if (inst->opcode() == spv::Op::OpVariable) {
std::set<uint32_t> seen;
std::vector<std::pair<Instruction*, uint32_t>> uses;
get_def_use_mgr()->ForEachUse(inst,
@@ -37,7 +37,7 @@ Pass::Status FixStorageClass::Process() {
for (auto& use : uses) {
modified |= PropagateStorageClass(
use.first,
static_cast<SpvStorageClass>(inst->GetSingleWordInOperand(0)),
static_cast<spv::StorageClass>(inst->GetSingleWordInOperand(0)),
&seen);
assert(seen.empty() && "Seen was not properly reset.");
modified |=
@@ -50,14 +50,14 @@ Pass::Status FixStorageClass::Process() {
}
bool FixStorageClass::PropagateStorageClass(Instruction* inst,
SpvStorageClass storage_class,
spv::StorageClass storage_class,
std::set<uint32_t>* seen) {
if (!IsPointerResultType(inst)) {
return false;
}
if (IsPointerToStorageClass(inst, storage_class)) {
if (inst->opcode() == SpvOpPhi) {
if (inst->opcode() == spv::Op::OpPhi) {
if (!seen->insert(inst->result_id()).second) {
return false;
}
@@ -71,34 +71,34 @@ bool FixStorageClass::PropagateStorageClass(Instruction* inst,
modified |= PropagateStorageClass(use, storage_class, seen);
}
if (inst->opcode() == SpvOpPhi) {
if (inst->opcode() == spv::Op::OpPhi) {
seen->erase(inst->result_id());
}
return modified;
}
switch (inst->opcode()) {
case SpvOpAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpCopyObject:
case SpvOpPhi:
case SpvOpSelect:
case spv::Op::OpAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpCopyObject:
case spv::Op::OpPhi:
case spv::Op::OpSelect:
FixInstructionStorageClass(inst, storage_class, seen);
return true;
case SpvOpFunctionCall:
case spv::Op::OpFunctionCall:
// We cannot be sure of the actual connection between the storage class
// of the parameter and the storage class of the result, so we should not
// do anything. If the result type needs to be fixed, the function call
// should be inlined.
return false;
case SpvOpImageTexelPointer:
case SpvOpLoad:
case SpvOpStore:
case SpvOpCopyMemory:
case SpvOpCopyMemorySized:
case SpvOpVariable:
case SpvOpBitcast:
case spv::Op::OpImageTexelPointer:
case spv::Op::OpLoad:
case spv::Op::OpStore:
case spv::Op::OpCopyMemory:
case spv::Op::OpCopyMemorySized:
case spv::Op::OpVariable:
case spv::Op::OpBitcast:
// Nothing to change for these opcode. The result type is the same
// regardless of the storage class of the operand.
return false;
@@ -109,9 +109,9 @@ bool FixStorageClass::PropagateStorageClass(Instruction* inst,
}
}
void FixStorageClass::FixInstructionStorageClass(Instruction* inst,
SpvStorageClass storage_class,
std::set<uint32_t>* seen) {
void FixStorageClass::FixInstructionStorageClass(
Instruction* inst, spv::StorageClass storage_class,
std::set<uint32_t>* seen) {
assert(IsPointerResultType(inst) &&
"The result type of the instruction must be a pointer.");
@@ -126,10 +126,10 @@ void FixStorageClass::FixInstructionStorageClass(Instruction* inst,
}
void FixStorageClass::ChangeResultStorageClass(
Instruction* inst, SpvStorageClass storage_class) const {
Instruction* inst, spv::StorageClass storage_class) const {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
Instruction* result_type_inst = get_def_use_mgr()->GetDef(inst->type_id());
assert(result_type_inst->opcode() == SpvOpTypePointer);
assert(result_type_inst->opcode() == spv::Op::OpTypePointer);
uint32_t pointee_type_id = result_type_inst->GetSingleWordInOperand(1);
uint32_t new_result_type_id =
type_mgr->FindPointerToType(pointee_type_id, storage_class);
@@ -147,7 +147,7 @@ bool FixStorageClass::IsPointerResultType(Instruction* inst) {
}
bool FixStorageClass::IsPointerToStorageClass(Instruction* inst,
SpvStorageClass storage_class) {
spv::StorageClass storage_class) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::Type* pType = type_mgr->GetType(inst->type_id());
const analysis::Pointer* result_type = pType->AsPointer();
@@ -180,39 +180,39 @@ bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id,
// particular type, then we want find that type.
uint32_t new_type_id = 0;
switch (inst->opcode()) {
case SpvOpAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpInBoundsPtrAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
if (op_idx == 2) {
new_type_id = WalkAccessChainType(inst, type_id);
}
break;
case SpvOpCopyObject:
case spv::Op::OpCopyObject:
new_type_id = type_id;
break;
case SpvOpPhi:
case spv::Op::OpPhi:
if (seen->insert(inst->result_id()).second) {
new_type_id = type_id;
}
break;
case SpvOpSelect:
case spv::Op::OpSelect:
if (op_idx > 2) {
new_type_id = type_id;
}
break;
case SpvOpFunctionCall:
case spv::Op::OpFunctionCall:
// We cannot be sure of the actual connection between the type
// of the parameter and the type of the result, so we should not
// do anything. If the result type needs to be fixed, the function call
// should be inlined.
return false;
case SpvOpLoad: {
case spv::Op::OpLoad: {
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
new_type_id = type_inst->GetSingleWordInOperand(1);
break;
}
case SpvOpStore: {
case spv::Op::OpStore: {
uint32_t obj_id = inst->GetSingleWordInOperand(1);
Instruction* obj_inst = get_def_use_mgr()->GetDef(obj_id);
uint32_t obj_type_id = obj_inst->type_id();
@@ -237,18 +237,18 @@ bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id,
context()->UpdateDefUse(inst);
}
} break;
case SpvOpCopyMemory:
case SpvOpCopyMemorySized:
case spv::Op::OpCopyMemory:
case spv::Op::OpCopyMemorySized:
// TODO: May need to expand the copy as we do with the stores.
break;
case SpvOpCompositeConstruct:
case SpvOpCompositeExtract:
case SpvOpCompositeInsert:
case spv::Op::OpCompositeConstruct:
case spv::Op::OpCompositeExtract:
case spv::Op::OpCompositeInsert:
// TODO: DXC does not seem to generate code that will require changes to
// these opcode. The can be implemented when they come up.
break;
case SpvOpImageTexelPointer:
case SpvOpBitcast:
case spv::Op::OpImageTexelPointer:
case spv::Op::OpBitcast:
// Nothing to change for these opcode. The result type is the same
// regardless of the type of the operand.
return false;
@@ -278,7 +278,7 @@ bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id,
PropagateType(use.first, new_type_id, use.second, seen);
}
if (inst->opcode() == SpvOpPhi) {
if (inst->opcode() == spv::Op::OpPhi) {
seen->erase(inst->result_id());
}
}
@@ -288,12 +288,12 @@ bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id,
uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) {
uint32_t start_idx = 0;
switch (inst->opcode()) {
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
start_idx = 1;
break;
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
start_idx = 2;
break;
default:
@@ -302,19 +302,19 @@ uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) {
}
Instruction* orig_type_inst = get_def_use_mgr()->GetDef(id);
assert(orig_type_inst->opcode() == SpvOpTypePointer);
assert(orig_type_inst->opcode() == spv::Op::OpTypePointer);
id = orig_type_inst->GetSingleWordInOperand(1);
for (uint32_t i = start_idx; i < inst->NumInOperands(); ++i) {
Instruction* type_inst = get_def_use_mgr()->GetDef(id);
switch (type_inst->opcode()) {
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case SpvOpTypeMatrix:
case SpvOpTypeVector:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
case spv::Op::OpTypeMatrix:
case spv::Op::OpTypeVector:
id = type_inst->GetSingleWordInOperand(0);
break;
case SpvOpTypeStruct: {
case spv::Op::OpTypeStruct: {
const analysis::Constant* index_const =
context()->get_constant_mgr()->FindDeclaredConstant(
inst->GetSingleWordInOperand(i));
@@ -330,8 +330,8 @@ uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) {
}
return context()->get_type_mgr()->FindPointerToType(
id,
static_cast<SpvStorageClass>(orig_type_inst->GetSingleWordInOperand(0)));
id, static_cast<spv::StorageClass>(
orig_type_inst->GetSingleWordInOperand(0)));
}
// namespace opt

View File

@@ -48,7 +48,7 @@ class FixStorageClass : public Pass {
// appropriate, and propagates the change to the users of |inst| as well.
// Returns true of any changes were made.
// |seen| is used to track OpPhi instructions that should not be processed.
bool PropagateStorageClass(Instruction* inst, SpvStorageClass storage_class,
bool PropagateStorageClass(Instruction* inst, spv::StorageClass storage_class,
std::set<uint32_t>* seen);
// Changes the storage class of the result of |inst| to |storage_class|.
@@ -58,13 +58,13 @@ class FixStorageClass : public Pass {
// |seen| is used to track OpPhi instructions that should not be processed by
// |PropagateStorageClass|
void FixInstructionStorageClass(Instruction* inst,
SpvStorageClass storage_class,
spv::StorageClass storage_class,
std::set<uint32_t>* seen);
// Changes the storage class of the result of |inst| to |storage_class|. The
// result type of |inst| must be a pointer.
void ChangeResultStorageClass(Instruction* inst,
SpvStorageClass storage_class) const;
spv::StorageClass storage_class) const;
// Returns true if the result type of |inst| is a pointer.
bool IsPointerResultType(Instruction* inst);
@@ -72,7 +72,7 @@ class FixStorageClass : public Pass {
// Returns true if the result of |inst| is a pointer to storage class
// |storage_class|.
bool IsPointerToStorageClass(Instruction* inst,
SpvStorageClass storage_class);
spv::StorageClass storage_class);
// Change |inst| to match that operand |op_idx| now has type |type_id|, and
// adjust any uses of |inst| accordingly. Returns true if the code changed.

View File

@@ -49,16 +49,16 @@ Pass::Status FlattenDecorationPass::Process() {
// Rely on unordered_map::operator[] to create its entries on first access.
for (const auto& inst : annotations) {
switch (inst.opcode()) {
case SpvOp::SpvOpDecorationGroup:
case spv::Op::OpDecorationGroup:
group_ids.insert(inst.result_id());
break;
case SpvOp::SpvOpGroupDecorate: {
case spv::Op::OpGroupDecorate: {
Words& words = normal_uses[inst.GetSingleWordInOperand(0)];
for (uint32_t i = 1; i < inst.NumInOperandWords(); i++) {
words.push_back(inst.GetSingleWordInOperand(i));
}
} break;
case SpvOp::SpvOpGroupMemberDecorate: {
case spv::Op::OpGroupMemberDecorate: {
Words& words = member_uses[inst.GetSingleWordInOperand(0)];
for (uint32_t i = 1; i < inst.NumInOperandWords(); i++) {
words.push_back(inst.GetSingleWordInOperand(i));
@@ -77,12 +77,12 @@ Pass::Status FlattenDecorationPass::Process() {
// Should we replace this instruction?
bool replace = false;
switch (inst_iter->opcode()) {
case SpvOp::SpvOpDecorationGroup:
case SpvOp::SpvOpGroupDecorate:
case SpvOp::SpvOpGroupMemberDecorate:
case spv::Op::OpDecorationGroup:
case spv::Op::OpGroupDecorate:
case spv::Op::OpGroupMemberDecorate:
replace = true;
break;
case SpvOp::SpvOpDecorate: {
case spv::Op::OpDecorate: {
// If this decoration targets a group, then replace it
// by sets of normal and member decorations.
const uint32_t group = inst_iter->GetSingleWordOperand(0);
@@ -115,7 +115,7 @@ Pass::Status FlattenDecorationPass::Process() {
operands.insert(operands.end(), decoration_operands_iter,
inst_iter->end());
std::unique_ptr<Instruction> new_inst(new Instruction(
context(), SpvOp::SpvOpMemberDecorate, 0, 0, operands));
context(), spv::Op::OpMemberDecorate, 0, 0, operands));
inst_iter = inst_iter.InsertBefore(std::move(new_inst));
++inst_iter;
replace = true;
@@ -146,7 +146,7 @@ Pass::Status FlattenDecorationPass::Process() {
if (!group_ids.empty()) {
for (auto debug_inst_iter = context()->debug2_begin();
debug_inst_iter != context()->debug2_end();) {
if (debug_inst_iter->opcode() == SpvOp::SpvOpName) {
if (debug_inst_iter->opcode() == spv::Op::OpName) {
const uint32_t target = debug_inst_iter->GetSingleWordOperand(0);
if (group_ids.count(target)) {
debug_inst_iter = debug_inst_iter.Erase();

View File

@@ -42,23 +42,24 @@ namespace {
} // namespace
uint32_t InstructionFolder::UnaryOperate(SpvOp opcode, uint32_t operand) const {
uint32_t InstructionFolder::UnaryOperate(spv::Op opcode,
uint32_t operand) const {
switch (opcode) {
// Arthimetics
case SpvOp::SpvOpSNegate: {
case spv::Op::OpSNegate: {
int32_t s_operand = static_cast<int32_t>(operand);
if (s_operand == std::numeric_limits<int32_t>::min()) {
return s_operand;
}
return -s_operand;
}
case SpvOp::SpvOpNot:
case spv::Op::OpNot:
return ~operand;
case SpvOp::SpvOpLogicalNot:
case spv::Op::OpLogicalNot:
return !static_cast<bool>(operand);
case SpvOp::SpvOpUConvert:
case spv::Op::OpUConvert:
return operand;
case SpvOp::SpvOpSConvert:
case spv::Op::OpSConvert:
return operand;
default:
assert(false &&
@@ -67,31 +68,31 @@ uint32_t InstructionFolder::UnaryOperate(SpvOp opcode, uint32_t operand) const {
}
}
uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
uint32_t InstructionFolder::BinaryOperate(spv::Op opcode, uint32_t a,
uint32_t b) const {
switch (opcode) {
// Arthimetics
case SpvOp::SpvOpIAdd:
case spv::Op::OpIAdd:
return a + b;
case SpvOp::SpvOpISub:
case spv::Op::OpISub:
return a - b;
case SpvOp::SpvOpIMul:
case spv::Op::OpIMul:
return a * b;
case SpvOp::SpvOpUDiv:
case spv::Op::OpUDiv:
if (b != 0) {
return a / b;
} else {
// Dividing by 0 is undefined, so we will just pick 0.
return 0;
}
case SpvOp::SpvOpSDiv:
case spv::Op::OpSDiv:
if (b != 0u) {
return (static_cast<int32_t>(a)) / (static_cast<int32_t>(b));
} else {
// Dividing by 0 is undefined, so we will just pick 0.
return 0;
}
case SpvOp::SpvOpSRem: {
case spv::Op::OpSRem: {
// The sign of non-zero result comes from the first operand: a. This is
// guaranteed by C++11 rules for integer division operator. The division
// result is rounded toward zero, so the result of '%' has the sign of
@@ -103,10 +104,10 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
return 0;
}
}
case SpvOp::SpvOpSMod: {
case spv::Op::OpSMod: {
// The sign of non-zero result comes from the second operand: b
if (b != 0u) {
int32_t rem = BinaryOperate(SpvOp::SpvOpSRem, a, b);
int32_t rem = BinaryOperate(spv::Op::OpSRem, a, b);
int32_t b_prim = static_cast<int32_t>(b);
return (rem + b_prim) % b_prim;
} else {
@@ -114,7 +115,7 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
return 0;
}
}
case SpvOp::SpvOpUMod:
case spv::Op::OpUMod:
if (b != 0u) {
return (a % b);
} else {
@@ -123,7 +124,7 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
}
// Shifting
case SpvOp::SpvOpShiftRightLogical:
case spv::Op::OpShiftRightLogical:
if (b >= 32) {
// This is undefined behaviour when |b| > 32. Choose 0 for consistency.
// When |b| == 32, doing the shift in C++ in undefined, but the result
@@ -131,7 +132,7 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
return 0;
}
return a >> b;
case SpvOp::SpvOpShiftRightArithmetic:
case spv::Op::OpShiftRightArithmetic:
if (b > 32) {
// This is undefined behaviour. Choose 0 for consistency.
return 0;
@@ -146,7 +147,7 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
}
}
return (static_cast<int32_t>(a)) >> b;
case SpvOp::SpvOpShiftLeftLogical:
case spv::Op::OpShiftLeftLogical:
if (b >= 32) {
// This is undefined behaviour when |b| > 32. Choose 0 for consistency.
// When |b| == 32, doing the shift in C++ in undefined, but the result
@@ -156,43 +157,43 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
return a << b;
// Bitwise operations
case SpvOp::SpvOpBitwiseOr:
case spv::Op::OpBitwiseOr:
return a | b;
case SpvOp::SpvOpBitwiseAnd:
case spv::Op::OpBitwiseAnd:
return a & b;
case SpvOp::SpvOpBitwiseXor:
case spv::Op::OpBitwiseXor:
return a ^ b;
// Logical
case SpvOp::SpvOpLogicalEqual:
case spv::Op::OpLogicalEqual:
return (static_cast<bool>(a)) == (static_cast<bool>(b));
case SpvOp::SpvOpLogicalNotEqual:
case spv::Op::OpLogicalNotEqual:
return (static_cast<bool>(a)) != (static_cast<bool>(b));
case SpvOp::SpvOpLogicalOr:
case spv::Op::OpLogicalOr:
return (static_cast<bool>(a)) || (static_cast<bool>(b));
case SpvOp::SpvOpLogicalAnd:
case spv::Op::OpLogicalAnd:
return (static_cast<bool>(a)) && (static_cast<bool>(b));
// Comparison
case SpvOp::SpvOpIEqual:
case spv::Op::OpIEqual:
return a == b;
case SpvOp::SpvOpINotEqual:
case spv::Op::OpINotEqual:
return a != b;
case SpvOp::SpvOpULessThan:
case spv::Op::OpULessThan:
return a < b;
case SpvOp::SpvOpSLessThan:
case spv::Op::OpSLessThan:
return (static_cast<int32_t>(a)) < (static_cast<int32_t>(b));
case SpvOp::SpvOpUGreaterThan:
case spv::Op::OpUGreaterThan:
return a > b;
case SpvOp::SpvOpSGreaterThan:
case spv::Op::OpSGreaterThan:
return (static_cast<int32_t>(a)) > (static_cast<int32_t>(b));
case SpvOp::SpvOpULessThanEqual:
case spv::Op::OpULessThanEqual:
return a <= b;
case SpvOp::SpvOpSLessThanEqual:
case spv::Op::OpSLessThanEqual:
return (static_cast<int32_t>(a)) <= (static_cast<int32_t>(b));
case SpvOp::SpvOpUGreaterThanEqual:
case spv::Op::OpUGreaterThanEqual:
return a >= b;
case SpvOp::SpvOpSGreaterThanEqual:
case spv::Op::OpSGreaterThanEqual:
return (static_cast<int32_t>(a)) >= (static_cast<int32_t>(b));
default:
assert(false &&
@@ -201,10 +202,10 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
}
}
uint32_t InstructionFolder::TernaryOperate(SpvOp opcode, uint32_t a, uint32_t b,
uint32_t c) const {
uint32_t InstructionFolder::TernaryOperate(spv::Op opcode, uint32_t a,
uint32_t b, uint32_t c) const {
switch (opcode) {
case SpvOp::SpvOpSelect:
case spv::Op::OpSelect:
return (static_cast<bool>(a)) ? b : c;
default:
assert(false &&
@@ -214,7 +215,7 @@ uint32_t InstructionFolder::TernaryOperate(SpvOp opcode, uint32_t a, uint32_t b,
}
uint32_t InstructionFolder::OperateWords(
SpvOp opcode, const std::vector<uint32_t>& operand_words) const {
spv::Op opcode, const std::vector<uint32_t>& operand_words) const {
switch (operand_words.size()) {
case 1:
return UnaryOperate(opcode, operand_words.front());
@@ -233,7 +234,7 @@ bool InstructionFolder::FoldInstructionInternal(Instruction* inst) const {
auto identity_map = [](uint32_t id) { return id; };
Instruction* folded_inst = FoldInstructionToConstant(inst, identity_map);
if (folded_inst != nullptr) {
inst->SetOpcode(SpvOpCopyObject);
inst->SetOpcode(spv::Op::OpCopyObject);
inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {folded_inst->result_id()}}});
return true;
}
@@ -256,7 +257,7 @@ bool InstructionFolder::FoldInstructionInternal(Instruction* inst) const {
// result in 32 bit word. Scalar constants with longer than 32-bit width are
// not accepted in this function.
uint32_t InstructionFolder::FoldScalars(
SpvOp opcode,
spv::Op opcode,
const std::vector<const analysis::Constant*>& operands) const {
assert(IsFoldableOpcode(opcode) &&
"Unhandled instruction opcode in FoldScalars");
@@ -282,7 +283,7 @@ uint32_t InstructionFolder::FoldScalars(
bool InstructionFolder::FoldBinaryIntegerOpToConstant(
Instruction* inst, const std::function<uint32_t(uint32_t)>& id_map,
uint32_t* result) const {
SpvOp opcode = inst->opcode();
spv::Op opcode = inst->opcode();
analysis::ConstantManager* const_manger = context_->get_constant_mgr();
uint32_t ids[2];
@@ -300,7 +301,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
switch (opcode) {
// Arthimetics
case SpvOp::SpvOpIMul:
case spv::Op::OpIMul:
for (uint32_t i = 0; i < 2; i++) {
if (constants[i] != nullptr && constants[i]->IsZero()) {
*result = 0;
@@ -308,11 +309,11 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
}
}
break;
case SpvOp::SpvOpUDiv:
case SpvOp::SpvOpSDiv:
case SpvOp::SpvOpSRem:
case SpvOp::SpvOpSMod:
case SpvOp::SpvOpUMod:
case spv::Op::OpUDiv:
case spv::Op::OpSDiv:
case spv::Op::OpSRem:
case spv::Op::OpSMod:
case spv::Op::OpUMod:
// This changes undefined behaviour (ie divide by 0) into a 0.
for (uint32_t i = 0; i < 2; i++) {
if (constants[i] != nullptr && constants[i]->IsZero()) {
@@ -323,8 +324,8 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
break;
// Shifting
case SpvOp::SpvOpShiftRightLogical:
case SpvOp::SpvOpShiftLeftLogical:
case spv::Op::OpShiftRightLogical:
case spv::Op::OpShiftLeftLogical:
if (constants[1] != nullptr) {
// When shifting by a value larger than the size of the result, the
// result is undefined. We are setting the undefined behaviour to a
@@ -339,7 +340,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
break;
// Bitwise operations
case SpvOp::SpvOpBitwiseOr:
case spv::Op::OpBitwiseOr:
for (uint32_t i = 0; i < 2; i++) {
if (constants[i] != nullptr) {
// TODO: Change the mask against a value based on the bit width of the
@@ -353,7 +354,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
}
}
break;
case SpvOp::SpvOpBitwiseAnd:
case spv::Op::OpBitwiseAnd:
for (uint32_t i = 0; i < 2; i++) {
if (constants[i] != nullptr) {
if (constants[i]->IsZero()) {
@@ -365,7 +366,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
break;
// Comparison
case SpvOp::SpvOpULessThan:
case spv::Op::OpULessThan:
if (constants[0] != nullptr &&
constants[0]->GetU32BitValue() == UINT32_MAX) {
*result = false;
@@ -376,7 +377,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
return true;
}
break;
case SpvOp::SpvOpSLessThan:
case spv::Op::OpSLessThan:
if (constants[0] != nullptr &&
constants[0]->GetS32BitValue() == INT32_MAX) {
*result = false;
@@ -388,7 +389,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
return true;
}
break;
case SpvOp::SpvOpUGreaterThan:
case spv::Op::OpUGreaterThan:
if (constants[0] != nullptr && constants[0]->IsZero()) {
*result = false;
return true;
@@ -399,7 +400,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
return true;
}
break;
case SpvOp::SpvOpSGreaterThan:
case spv::Op::OpSGreaterThan:
if (constants[0] != nullptr &&
constants[0]->GetS32BitValue() == INT32_MIN) {
*result = false;
@@ -411,7 +412,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
return true;
}
break;
case SpvOp::SpvOpULessThanEqual:
case spv::Op::OpULessThanEqual:
if (constants[0] != nullptr && constants[0]->IsZero()) {
*result = true;
return true;
@@ -422,7 +423,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
return true;
}
break;
case SpvOp::SpvOpSLessThanEqual:
case spv::Op::OpSLessThanEqual:
if (constants[0] != nullptr &&
constants[0]->GetS32BitValue() == INT32_MIN) {
*result = true;
@@ -434,7 +435,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
return true;
}
break;
case SpvOp::SpvOpUGreaterThanEqual:
case spv::Op::OpUGreaterThanEqual:
if (constants[0] != nullptr &&
constants[0]->GetU32BitValue() == UINT32_MAX) {
*result = true;
@@ -445,7 +446,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
return true;
}
break;
case SpvOp::SpvOpSGreaterThanEqual:
case spv::Op::OpSGreaterThanEqual:
if (constants[0] != nullptr &&
constants[0]->GetS32BitValue() == INT32_MAX) {
*result = true;
@@ -466,7 +467,7 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
bool InstructionFolder::FoldBinaryBooleanOpToConstant(
Instruction* inst, const std::function<uint32_t(uint32_t)>& id_map,
uint32_t* result) const {
SpvOp opcode = inst->opcode();
spv::Op opcode = inst->opcode();
analysis::ConstantManager* const_manger = context_->get_constant_mgr();
uint32_t ids[2];
@@ -484,7 +485,7 @@ bool InstructionFolder::FoldBinaryBooleanOpToConstant(
switch (opcode) {
// Logical
case SpvOp::SpvOpLogicalOr:
case spv::Op::OpLogicalOr:
for (uint32_t i = 0; i < 2; i++) {
if (constants[i] != nullptr) {
if (constants[i]->value()) {
@@ -494,7 +495,7 @@ bool InstructionFolder::FoldBinaryBooleanOpToConstant(
}
}
break;
case SpvOp::SpvOpLogicalAnd:
case spv::Op::OpLogicalAnd:
for (uint32_t i = 0; i < 2; i++) {
if (constants[i] != nullptr) {
if (!constants[i]->value()) {
@@ -526,7 +527,7 @@ bool InstructionFolder::FoldIntegerOpToConstant(
}
std::vector<uint32_t> InstructionFolder::FoldVectors(
SpvOp opcode, uint32_t num_dims,
spv::Op opcode, uint32_t num_dims,
const std::vector<const analysis::Constant*>& operands) const {
assert(IsFoldableOpcode(opcode) &&
"Unhandled instruction opcode in FoldVectors");
@@ -570,44 +571,44 @@ std::vector<uint32_t> InstructionFolder::FoldVectors(
return result;
}
bool InstructionFolder::IsFoldableOpcode(SpvOp opcode) const {
bool InstructionFolder::IsFoldableOpcode(spv::Op opcode) const {
// NOTE: Extend to more opcodes as new cases are handled in the folder
// functions.
switch (opcode) {
case SpvOp::SpvOpBitwiseAnd:
case SpvOp::SpvOpBitwiseOr:
case SpvOp::SpvOpBitwiseXor:
case SpvOp::SpvOpIAdd:
case SpvOp::SpvOpIEqual:
case SpvOp::SpvOpIMul:
case SpvOp::SpvOpINotEqual:
case SpvOp::SpvOpISub:
case SpvOp::SpvOpLogicalAnd:
case SpvOp::SpvOpLogicalEqual:
case SpvOp::SpvOpLogicalNot:
case SpvOp::SpvOpLogicalNotEqual:
case SpvOp::SpvOpLogicalOr:
case SpvOp::SpvOpNot:
case SpvOp::SpvOpSDiv:
case SpvOp::SpvOpSelect:
case SpvOp::SpvOpSGreaterThan:
case SpvOp::SpvOpSGreaterThanEqual:
case SpvOp::SpvOpShiftLeftLogical:
case SpvOp::SpvOpShiftRightArithmetic:
case SpvOp::SpvOpShiftRightLogical:
case SpvOp::SpvOpSLessThan:
case SpvOp::SpvOpSLessThanEqual:
case SpvOp::SpvOpSMod:
case SpvOp::SpvOpSNegate:
case SpvOp::SpvOpSRem:
case SpvOp::SpvOpSConvert:
case SpvOp::SpvOpUConvert:
case SpvOp::SpvOpUDiv:
case SpvOp::SpvOpUGreaterThan:
case SpvOp::SpvOpUGreaterThanEqual:
case SpvOp::SpvOpULessThan:
case SpvOp::SpvOpULessThanEqual:
case SpvOp::SpvOpUMod:
case spv::Op::OpBitwiseAnd:
case spv::Op::OpBitwiseOr:
case spv::Op::OpBitwiseXor:
case spv::Op::OpIAdd:
case spv::Op::OpIEqual:
case spv::Op::OpIMul:
case spv::Op::OpINotEqual:
case spv::Op::OpISub:
case spv::Op::OpLogicalAnd:
case spv::Op::OpLogicalEqual:
case spv::Op::OpLogicalNot:
case spv::Op::OpLogicalNotEqual:
case spv::Op::OpLogicalOr:
case spv::Op::OpNot:
case spv::Op::OpSDiv:
case spv::Op::OpSelect:
case spv::Op::OpSGreaterThan:
case spv::Op::OpSGreaterThanEqual:
case spv::Op::OpShiftLeftLogical:
case spv::Op::OpShiftRightArithmetic:
case spv::Op::OpShiftRightLogical:
case spv::Op::OpSLessThan:
case spv::Op::OpSLessThanEqual:
case spv::Op::OpSMod:
case spv::Op::OpSNegate:
case spv::Op::OpSRem:
case spv::Op::OpSConvert:
case spv::Op::OpUConvert:
case spv::Op::OpUDiv:
case spv::Op::OpUGreaterThan:
case spv::Op::OpUGreaterThanEqual:
case spv::Op::OpULessThan:
case spv::Op::OpULessThanEqual:
case spv::Op::OpUMod:
return true;
default:
return false;
@@ -685,11 +686,11 @@ Instruction* InstructionFolder::FoldInstructionToConstant(
bool InstructionFolder::IsFoldableType(Instruction* type_inst) const {
// Support 32-bit integers.
if (type_inst->opcode() == SpvOpTypeInt) {
if (type_inst->opcode() == spv::Op::OpTypeInt) {
return type_inst->GetSingleWordInOperand(0) == 32;
}
// Support booleans.
if (type_inst->opcode() == SpvOpTypeBool) {
if (type_inst->opcode() == spv::Op::OpTypeBool) {
return true;
}
// Nothing else yet.
@@ -699,7 +700,7 @@ bool InstructionFolder::IsFoldableType(Instruction* type_inst) const {
bool InstructionFolder::FoldInstruction(Instruction* inst) const {
bool modified = false;
Instruction* folded_inst(inst);
while (folded_inst->opcode() != SpvOpCopyObject &&
while (folded_inst->opcode() != spv::Op::OpCopyObject &&
FoldInstructionInternal(&*folded_inst)) {
modified = true;
}

View File

@@ -55,7 +55,7 @@ class InstructionFolder {
// IsFoldableOpcode test. If any error occurs during folding, the folder will
// fail with a call to assert.
uint32_t FoldScalars(
SpvOp opcode,
spv::Op opcode,
const std::vector<const analysis::Constant*>& operands) const;
// Returns the result of performing an operation with the given |opcode| over
@@ -72,12 +72,12 @@ class InstructionFolder {
// IsFoldableOpcode test. If any error occurs during folding, the folder will
// fail with a call to assert.
std::vector<uint32_t> FoldVectors(
SpvOp opcode, uint32_t num_dims,
spv::Op opcode, uint32_t num_dims,
const std::vector<const analysis::Constant*>& operands) const;
// Returns true if |opcode| represents an operation handled by FoldScalars or
// FoldVectors.
bool IsFoldableOpcode(SpvOp opcode) const;
bool IsFoldableOpcode(spv::Op opcode) const;
// Returns true if |cst| is supported by FoldScalars and FoldVectors.
bool IsFoldableConstant(const analysis::Constant* cst) const;
@@ -126,22 +126,22 @@ class InstructionFolder {
// Returns the single-word result from performing the given unary operation on
// the operand value which is passed in as a 32-bit word.
uint32_t UnaryOperate(SpvOp opcode, uint32_t operand) const;
uint32_t UnaryOperate(spv::Op opcode, uint32_t operand) const;
// Returns the single-word result from performing the given binary operation
// on the operand values which are passed in as two 32-bit word.
uint32_t BinaryOperate(SpvOp opcode, uint32_t a, uint32_t b) const;
uint32_t BinaryOperate(spv::Op opcode, uint32_t a, uint32_t b) const;
// Returns the single-word result from performing the given ternary operation
// on the operand values which are passed in as three 32-bit word.
uint32_t TernaryOperate(SpvOp opcode, uint32_t a, uint32_t b,
uint32_t TernaryOperate(spv::Op opcode, uint32_t a, uint32_t b,
uint32_t c) const;
// Returns the single-word result from performing the given operation on the
// operand words. This only works with 32-bit operations and uses boolean
// convention that 0u is false, and anything else is boolean true.
// TODO(qining): Support operands other than 32-bit wide.
uint32_t OperateWords(SpvOp opcode,
uint32_t OperateWords(spv::Op opcode,
const std::vector<uint32_t>& operand_words) const;
bool FoldInstructionInternal(Instruction* inst) const;

View File

@@ -66,14 +66,14 @@ Pass::Status FoldSpecConstantOpAndCompositePass::Process() {
if (const_mgr->GetType(inst) &&
!const_mgr->GetType(inst)->decoration_empty())
continue;
switch (SpvOp opcode = inst->opcode()) {
switch (spv::Op opcode = inst->opcode()) {
// Records the values of Normal Constants.
case SpvOp::SpvOpConstantTrue:
case SpvOp::SpvOpConstantFalse:
case SpvOp::SpvOpConstant:
case SpvOp::SpvOpConstantNull:
case SpvOp::SpvOpConstantComposite:
case SpvOp::SpvOpSpecConstantComposite: {
case spv::Op::OpConstantTrue:
case spv::Op::OpConstantFalse:
case spv::Op::OpConstant:
case spv::Op::OpConstantNull:
case spv::Op::OpConstantComposite:
case spv::Op::OpSpecConstantComposite: {
// A Constant instance will be created if the given instruction is a
// Normal Constant whose value(s) are fixed. Note that for a composite
// Spec Constant defined with OpSpecConstantComposite instruction, if
@@ -84,8 +84,8 @@ Pass::Status FoldSpecConstantOpAndCompositePass::Process() {
if (auto const_value = const_mgr->GetConstantFromInst(inst)) {
// Need to replace the OpSpecConstantComposite instruction with a
// corresponding OpConstantComposite instruction.
if (opcode == SpvOp::SpvOpSpecConstantComposite) {
inst->SetOpcode(SpvOp::SpvOpConstantComposite);
if (opcode == spv::Op::OpSpecConstantComposite) {
inst->SetOpcode(spv::Op::OpConstantComposite);
modified = true;
}
const_mgr->MapConstantToInst(const_value, inst);
@@ -99,7 +99,7 @@ Pass::Status FoldSpecConstantOpAndCompositePass::Process() {
// Constants will be added to id_to_const_val_ and const_val_to_id_ so
// that we can use the new Normal Constants when folding following Spec
// Constants.
case SpvOp::SpvOpSpecConstantOp:
case spv::Op::OpSpecConstantOp:
modified |= ProcessOpSpecConstantOp(&inst_iter);
break;
default:
@@ -118,11 +118,11 @@ bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp(
"The first in-operand of OpSpecConstantOp instruction must be of "
"SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER type");
switch (static_cast<SpvOp>(inst->GetSingleWordInOperand(0))) {
case SpvOp::SpvOpCompositeExtract:
case SpvOp::SpvOpVectorShuffle:
case SpvOp::SpvOpCompositeInsert:
case SpvOp::SpvOpQuantizeToF16:
switch (static_cast<spv::Op>(inst->GetSingleWordInOperand(0))) {
case spv::Op::OpCompositeExtract:
case spv::Op::OpVectorShuffle:
case spv::Op::OpCompositeInsert:
case spv::Op::OpQuantizeToF16:
folded_inst = FoldWithInstructionFolder(pos);
break;
default:
@@ -165,7 +165,7 @@ Instruction* FoldSpecConstantOpAndCompositePass::FoldWithInstructionFolder(
// instruction and pass it to the instruction folder.
std::unique_ptr<Instruction> inst((*inst_iter_ptr)->Clone(context()));
inst->SetOpcode(
static_cast<SpvOp>((*inst_iter_ptr)->GetSingleWordInOperand(0)));
static_cast<spv::Op>((*inst_iter_ptr)->GetSingleWordInOperand(0)));
inst->RemoveOperand(2);
// We want the current instruction to be replaced by an |OpConstant*|
@@ -289,7 +289,7 @@ Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation(
const Instruction* inst = &**pos;
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
const analysis::Type* result_type = const_mgr->GetType(inst);
SpvOp spec_opcode = static_cast<SpvOp>(inst->GetSingleWordInOperand(0));
spv::Op spec_opcode = static_cast<spv::Op>(inst->GetSingleWordInOperand(0));
// Check and collect operands.
std::vector<const analysis::Constant*> operands;

File diff suppressed because it is too large Load Diff

View File

@@ -64,7 +64,7 @@ class FoldingRules {
virtual ~FoldingRules() = default;
const FoldingRuleSet& GetRulesForInstruction(Instruction* inst) const {
if (inst->opcode() != SpvOpExtInst) {
if (inst->opcode() != spv::Op::OpExtInst) {
auto it = rules_.find(inst->opcode());
if (it != rules_.end()) {
return it->second;
@@ -86,8 +86,14 @@ class FoldingRules {
virtual void AddFoldingRules();
protected:
struct hasher {
size_t operator()(const spv::Op& op) const noexcept {
return std::hash<uint32_t>()(uint32_t(op));
}
};
// The folding rules for core instructions.
std::unordered_map<uint32_t, FoldingRuleSet> rules_;
std::unordered_map<spv::Op, FoldingRuleSet, hasher> rules_;
// The folding rules for extended instructions.
struct Key {

View File

@@ -23,21 +23,21 @@ Pass::Status FreezeSpecConstantValuePass::Process() {
auto ctx = context();
ctx->module()->ForEachInst([&modified, ctx](Instruction* inst) {
switch (inst->opcode()) {
case SpvOp::SpvOpSpecConstant:
inst->SetOpcode(SpvOp::SpvOpConstant);
case spv::Op::OpSpecConstant:
inst->SetOpcode(spv::Op::OpConstant);
modified = true;
break;
case SpvOp::SpvOpSpecConstantTrue:
inst->SetOpcode(SpvOp::SpvOpConstantTrue);
case spv::Op::OpSpecConstantTrue:
inst->SetOpcode(spv::Op::OpConstantTrue);
modified = true;
break;
case SpvOp::SpvOpSpecConstantFalse:
inst->SetOpcode(SpvOp::SpvOpConstantFalse);
case spv::Op::OpSpecConstantFalse:
inst->SetOpcode(spv::Op::OpConstantFalse);
modified = true;
break;
case SpvOp::SpvOpDecorate:
if (inst->GetSingleWordInOperand(1) ==
SpvDecoration::SpvDecorationSpecId) {
case spv::Op::OpDecorate:
if (spv::Decoration(inst->GetSingleWordInOperand(1)) ==
spv::Decoration::SpecId) {
ctx->KillInst(inst);
modified = true;
}

View File

@@ -264,7 +264,7 @@ std::string Function::PrettyPrint(uint32_t options) const {
std::ostringstream str;
ForEachInst([&str, options](const Instruction* inst) {
str << inst->PrettyPrint(options);
if (inst->opcode() != SpvOpFunctionEnd) {
if (inst->opcode() != spv::Op::OpFunctionEnd) {
str << std::endl;
}
});

View File

@@ -253,7 +253,7 @@ inline void Function::RemoveEmptyBlocks() {
auto first_empty =
std::remove_if(std::begin(blocks_), std::end(blocks_),
[](const std::unique_ptr<BasicBlock>& bb) -> bool {
return bb->GetLabelInst()->opcode() == SpvOpNop;
return bb->GetLabelInst()->opcode() == spv::Op::OpNop;
});
blocks_.erase(first_empty, std::end(blocks_));
}

View File

@@ -158,7 +158,6 @@
#include "source/util/make_unique.h"
#include "spirv-tools/libspirv.h"
#include "spirv/unified1/GLSL.std.450.h"
#include "spirv/unified1/spirv.h"
#include "type_manager.h"
#include "types.h"
@@ -194,14 +193,15 @@ spvtools::DiagnosticStream GraphicsRobustAccessPass::Fail() {
spv_result_t GraphicsRobustAccessPass::IsCompatibleModule() {
auto* feature_mgr = context()->get_feature_mgr();
if (!feature_mgr->HasCapability(SpvCapabilityShader))
if (!feature_mgr->HasCapability(spv::Capability::Shader))
return Fail() << "Can only process Shader modules";
if (feature_mgr->HasCapability(SpvCapabilityVariablePointers))
if (feature_mgr->HasCapability(spv::Capability::VariablePointers))
return Fail() << "Can't process modules with VariablePointers capability";
if (feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer))
if (feature_mgr->HasCapability(
spv::Capability::VariablePointersStorageBuffer))
return Fail() << "Can't process modules with VariablePointersStorageBuffer "
"capability";
if (feature_mgr->HasCapability(SpvCapabilityRuntimeDescriptorArrayEXT)) {
if (feature_mgr->HasCapability(spv::Capability::RuntimeDescriptorArrayEXT)) {
// These have a RuntimeArray outside of Block-decorated struct. There
// is no way to compute the array length from within SPIR-V.
return Fail() << "Can't process modules with RuntimeDescriptorArrayEXT "
@@ -210,8 +210,9 @@ spv_result_t GraphicsRobustAccessPass::IsCompatibleModule() {
{
auto* inst = context()->module()->GetMemoryModel();
const auto addressing_model = inst->GetSingleWordOperand(0);
if (addressing_model != SpvAddressingModelLogical)
const auto addressing_model =
spv::AddressingModel(inst->GetSingleWordOperand(0));
if (addressing_model != spv::AddressingModel::Logical)
return Fail() << "Addressing model must be Logical. Found "
<< inst->PrettyPrint();
}
@@ -237,11 +238,11 @@ bool GraphicsRobustAccessPass::ProcessAFunction(opt::Function* function) {
for (auto& block : *function) {
for (auto& inst : block) {
switch (inst.opcode()) {
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
access_chains.push_back(&inst);
break;
case SpvOpImageTexelPointer:
case spv::Op::OpImageTexelPointer:
image_texel_pointers.push_back(&inst);
break;
default:
@@ -268,7 +269,7 @@ void GraphicsRobustAccessPass::ClampIndicesForAccessChain(
auto* def_use_mgr = context()->get_def_use_mgr();
auto* type_mgr = context()->get_type_mgr();
const bool have_int64_cap =
context()->get_feature_mgr()->HasCapability(SpvCapabilityInt64);
context()->get_feature_mgr()->HasCapability(spv::Capability::Int64);
// Replaces one of the OpAccessChain index operands with a new value.
// Updates def-use analysis.
@@ -451,7 +452,7 @@ void GraphicsRobustAccessPass::ClampIndicesForAccessChain(
// It doesn't matter if 1 is signed or unsigned.
auto* one = GetValueForType(1, wider_type);
auto* count_minus_1 = InsertInst(
&inst, SpvOpISub, type_mgr->GetId(wider_type), TakeNextId(),
&inst, spv::Op::OpISub, type_mgr->GetId(wider_type), TakeNextId(),
{{SPV_OPERAND_TYPE_ID, {count_inst->result_id()}},
{SPV_OPERAND_TYPE_ID, {one->result_id()}}});
auto* zero = GetValueForType(0, wider_type);
@@ -486,15 +487,15 @@ void GraphicsRobustAccessPass::ClampIndicesForAccessChain(
Instruction* index_inst = GetDef(index_id);
switch (pointee_type->opcode()) {
case SpvOpTypeMatrix: // Use column count
case SpvOpTypeVector: // Use component count
case spv::Op::OpTypeMatrix: // Use column count
case spv::Op::OpTypeVector: // Use component count
{
const uint32_t count = pointee_type->GetSingleWordOperand(2);
clamp_to_literal_count(idx, count);
pointee_type = GetDef(pointee_type->GetSingleWordOperand(1));
} break;
case SpvOpTypeArray: {
case spv::Op::OpTypeArray: {
// The array length can be a spec constant, so go through the general
// case.
Instruction* array_len = GetDef(pointee_type->GetSingleWordOperand(2));
@@ -502,11 +503,11 @@ void GraphicsRobustAccessPass::ClampIndicesForAccessChain(
pointee_type = GetDef(pointee_type->GetSingleWordOperand(1));
} break;
case SpvOpTypeStruct: {
case spv::Op::OpTypeStruct: {
// SPIR-V requires the index to be an OpConstant.
// We need to know the index literal value so we can compute the next
// pointee type.
if (index_inst->opcode() != SpvOpConstant ||
if (index_inst->opcode() != spv::Op::OpConstant ||
!constant_mgr->GetConstantFromInst(index_inst)
->type()
->AsInteger()) {
@@ -537,7 +538,7 @@ void GraphicsRobustAccessPass::ClampIndicesForAccessChain(
// No need to clamp this index. We just checked that it's valid.
} break;
case SpvOpTypeRuntimeArray: {
case spv::Op::OpTypeRuntimeArray: {
auto* array_len = MakeRuntimeArrayLengthInst(&inst, idx);
if (!array_len) { // We've already signaled an error.
return;
@@ -571,7 +572,7 @@ uint32_t GraphicsRobustAccessPass::GetGlslInsts() {
module_status_.glsl_insts_id = TakeNextId();
std::vector<uint32_t> words = spvtools::utils::MakeVector(glsl);
auto import_inst = MakeUnique<Instruction>(
context(), SpvOpExtInstImport, 0, module_status_.glsl_insts_id,
context(), spv::Op::OpExtInstImport, 0, module_status_.glsl_insts_id,
std::initializer_list<Operand>{
Operand{SPV_OPERAND_TYPE_LITERAL_STRING, std::move(words)}});
Instruction* inst = import_inst.get();
@@ -609,8 +610,8 @@ opt::Instruction* opt::GraphicsRobustAccessPass::WidenInteger(
auto type_id = context()->get_type_mgr()->GetId(unsigned_type);
auto conversion_id = TakeNextId();
auto* conversion = InsertInst(
before_inst, (sign_extend ? SpvOpSConvert : SpvOpUConvert), type_id,
conversion_id, {{SPV_OPERAND_TYPE_ID, {value->result_id()}}});
before_inst, (sign_extend ? spv::Op::OpSConvert : spv::Op::OpUConvert),
type_id, conversion_id, {{SPV_OPERAND_TYPE_ID, {value->result_id()}}});
return conversion;
}
@@ -628,7 +629,7 @@ Instruction* GraphicsRobustAccessPass::MakeUMinInst(
(void)xwidth;
(void)ywidth;
auto* smin_inst = InsertInst(
where, SpvOpExtInst, x->type_id(), smin_id,
where, spv::Op::OpExtInst, x->type_id(), smin_id,
{
{SPV_OPERAND_TYPE_ID, {glsl_insts_id}},
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {GLSLstd450UMin}},
@@ -655,7 +656,7 @@ Instruction* GraphicsRobustAccessPass::MakeSClampInst(
(void)minwidth;
(void)maxwidth;
auto* clamp_inst = InsertInst(
where, SpvOpExtInst, x->type_id(), clamp_id,
where, spv::Op::OpExtInst, x->type_id(), clamp_id,
{
{SPV_OPERAND_TYPE_ID, {glsl_insts_id}},
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {GLSLstd450SClamp}},
@@ -689,13 +690,13 @@ Instruction* GraphicsRobustAccessPass::MakeRuntimeArrayLengthInst(
Instruction* pointer_to_containing_struct = nullptr;
while (steps_remaining > 0) {
switch (current_access_chain->opcode()) {
case SpvOpCopyObject:
case spv::Op::OpCopyObject:
// Whoops. Walk right through this one.
current_access_chain =
GetDef(current_access_chain->GetSingleWordInOperand(0));
break;
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain: {
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain: {
const int first_index_operand = 3;
// How many indices in this access chain contribute to getting us
// to an element in the runtime array?
@@ -793,7 +794,8 @@ Instruction* GraphicsRobustAccessPass::MakeRuntimeArrayLengthInst(
analysis::Integer uint_type_for_query(32, false);
auto* uint_type = type_mgr->GetRegisteredType(&uint_type_for_query);
auto* array_len = InsertInst(
access_chain, SpvOpArrayLength, type_mgr->GetId(uint_type), array_len_id,
access_chain, spv::Op::OpArrayLength, type_mgr->GetId(uint_type),
array_len_id,
{{SPV_OPERAND_TYPE_ID, {pointer_to_containing_struct->result_id()}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index_of_runtime_array}}});
return array_len;
@@ -839,11 +841,11 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
// Declare the ImageQuery capability if the module doesn't already have it.
auto* feature_mgr = context()->get_feature_mgr();
if (!feature_mgr->HasCapability(SpvCapabilityImageQuery)) {
if (!feature_mgr->HasCapability(spv::Capability::ImageQuery)) {
auto cap = MakeUnique<Instruction>(
context(), SpvOpCapability, 0, 0,
context(), spv::Op::OpCapability, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityImageQuery}}});
{SPV_OPERAND_TYPE_CAPABILITY, {spv::Capability::ImageQuery}}});
def_use_mgr->AnalyzeInstDefUse(cap.get());
context()->AddCapability(std::move(cap));
feature_mgr->Analyze(context()->module());
@@ -890,21 +892,21 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
const int arrayness_bonus = arrayed ? 1 : 0;
int num_coords = 0;
switch (dim) {
case SpvDimBuffer:
case spv::Dim::Buffer:
case SpvDim1D:
num_coords = 1;
break;
case SpvDimCube:
case spv::Dim::Cube:
// For cube, we need bounds for x, y, but not face.
case SpvDimRect:
case spv::Dim::Rect:
case SpvDim2D:
num_coords = 2;
break;
case SpvDim3D:
num_coords = 3;
break;
case SpvDimSubpassData:
case SpvDimMax:
case spv::Dim::SubpassData:
case spv::Dim::Max:
return Fail() << "Invalid image dimension for OpImageTexelPointer: "
<< int(dim);
break;
@@ -941,12 +943,12 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
const uint32_t image_id = TakeNextId();
auto* image =
InsertInst(image_texel_pointer, SpvOpLoad, image_type_id, image_id,
InsertInst(image_texel_pointer, spv::Op::OpLoad, image_type_id, image_id,
{{SPV_OPERAND_TYPE_ID, {image_ptr->result_id()}}});
const uint32_t query_size_id = TakeNextId();
auto* query_size =
InsertInst(image_texel_pointer, SpvOpImageQuerySize,
InsertInst(image_texel_pointer, spv::Op::OpImageQuerySize,
type_mgr->GetTypeInstruction(query_size_type), query_size_id,
{{SPV_OPERAND_TYPE_ID, {image->result_id()}}});
@@ -962,7 +964,7 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
// in the face index ranging from 0 through 5. The inclusive upper bound
// on the third coordinate therefore is multiplied by 6.
auto* query_size_including_faces = query_size;
if (arrayed && (dim == SpvDimCube)) {
if (arrayed && (dim == spv::Dim::Cube)) {
// Multiply the last coordinate by 6.
auto* component_6 = constant_mgr->GetConstant(coord_component_type, {6});
const uint32_t component_6_id =
@@ -974,7 +976,7 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
constant_mgr->GetDefiningInstruction(multiplicand);
const auto query_size_including_faces_id = TakeNextId();
query_size_including_faces = InsertInst(
image_texel_pointer, SpvOpIMul,
image_texel_pointer, spv::Op::OpIMul,
type_mgr->GetTypeInstruction(query_size_type),
query_size_including_faces_id,
{{SPV_OPERAND_TYPE_ID, {query_size_including_faces->result_id()}},
@@ -998,7 +1000,7 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
const uint32_t query_max_including_faces_id = TakeNextId();
auto* query_max_including_faces = InsertInst(
image_texel_pointer, SpvOpISub,
image_texel_pointer, spv::Op::OpISub,
type_mgr->GetTypeInstruction(query_size_type),
query_max_including_faces_id,
{{SPV_OPERAND_TYPE_ID, {query_size_including_faces->result_id()}},
@@ -1016,12 +1018,12 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
// Get the sample count via OpImageQuerySamples
const auto query_samples_id = TakeNextId();
auto* query_samples = InsertInst(
image_texel_pointer, SpvOpImageQuerySamples,
image_texel_pointer, spv::Op::OpImageQuerySamples,
constant_mgr->GetDefiningInstruction(component_0)->type_id(),
query_samples_id, {{SPV_OPERAND_TYPE_ID, {image->result_id()}}});
const auto max_samples_id = TakeNextId();
auto* max_samples = InsertInst(image_texel_pointer, SpvOpImageQuerySamples,
auto* max_samples = InsertInst(image_texel_pointer, spv::Op::OpImageQuerySamples,
query_samples->type_id(), max_samples_id,
{{SPV_OPERAND_TYPE_ID, {query_samples_id}},
{SPV_OPERAND_TYPE_ID, {component_1_id}}});
@@ -1043,7 +1045,7 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer(
}
opt::Instruction* GraphicsRobustAccessPass::InsertInst(
opt::Instruction* where_inst, SpvOp opcode, uint32_t type_id,
opt::Instruction* where_inst, spv::Op opcode, uint32_t type_id,
uint32_t result_id, const Instruction::OperandList& operands) {
module_status_.modified = true;
auto* result = where_inst->InsertBefore(

View File

@@ -133,7 +133,7 @@ class GraphicsRobustAccessPass : public Pass {
// Returns a new instruction inserted before |where_inst|, and created from
// the remaining arguments. Registers the definitions and uses of the new
// instruction and also records its block.
opt::Instruction* InsertInst(opt::Instruction* where_inst, SpvOp opcode,
opt::Instruction* InsertInst(opt::Instruction* where_inst, spv::Op opcode,
uint32_t type_id, uint32_t result_id,
const Instruction::OperandList& operands);

View File

@@ -23,7 +23,7 @@ namespace spvtools {
namespace opt {
Pass::Status IfConversion::Process() {
if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) {
if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader)) {
return Status::SuccessWithoutChange;
}
@@ -40,7 +40,7 @@ Pass::Status IfConversion::Process() {
// Get an insertion point.
auto iter = block.begin();
while (iter != block.end() && iter->opcode() == SpvOpPhi) {
while (iter != block.end() && iter->opcode() == spv::Op::OpPhi) {
++iter;
}
@@ -171,23 +171,26 @@ bool IfConversion::CheckBlock(BasicBlock* block, DominatorAnalysis* dominators,
*common = dominators->CommonDominator(inc0, inc1);
if (!*common || cfg()->IsPseudoEntryBlock(*common)) return false;
Instruction* branch = (*common)->terminator();
if (branch->opcode() != SpvOpBranchConditional) return false;
if (branch->opcode() != spv::Op::OpBranchConditional) return false;
auto merge = (*common)->GetMergeInst();
if (!merge || merge->opcode() != SpvOpSelectionMerge) return false;
if (merge->GetSingleWordInOperand(1) == SpvSelectionControlDontFlattenMask)
if (!merge || merge->opcode() != spv::Op::OpSelectionMerge) return false;
if (spv::SelectionControlMask(merge->GetSingleWordInOperand(1)) ==
spv::SelectionControlMask::DontFlatten) {
return false;
}
if ((*common)->MergeBlockIdIfAny() != block->id()) return false;
return true;
}
bool IfConversion::CheckPhiUsers(Instruction* phi, BasicBlock* block) {
return get_def_use_mgr()->WhileEachUser(phi, [block,
this](Instruction* user) {
if (user->opcode() == SpvOpPhi && context()->get_instr_block(user) == block)
return false;
return true;
});
return get_def_use_mgr()->WhileEachUser(
phi, [block, this](Instruction* user) {
if (user->opcode() == spv::Op::OpPhi &&
context()->get_instr_block(user) == block)
return false;
return true;
});
}
uint32_t IfConversion::SplatCondition(analysis::Vector* vec_data_ty,
@@ -207,9 +210,9 @@ uint32_t IfConversion::SplatCondition(analysis::Vector* vec_data_ty,
bool IfConversion::CheckType(uint32_t id) {
Instruction* type = get_def_use_mgr()->GetDef(id);
SpvOp op = type->opcode();
if (spvOpcodeIsScalarType(op) || op == SpvOpTypePointer ||
op == SpvOpTypeVector)
spv::Op op = type->opcode();
if (spvOpcodeIsScalarType(op) || op == spv::Op::OpTypePointer ||
op == spv::Op::OpTypeVector)
return true;
return false;
}
@@ -255,7 +258,7 @@ void IfConversion::HoistInstruction(Instruction* inst, BasicBlock* target_block,
});
Instruction* insertion_pos = target_block->terminator();
if ((insertion_pos)->PreviousNode()->opcode() == SpvOpSelectionMerge) {
if ((insertion_pos)->PreviousNode()->opcode() == spv::Op::OpSelectionMerge) {
insertion_pos = insertion_pos->PreviousNode();
}
inst->RemoveFromList();

View File

@@ -21,26 +21,24 @@
namespace spvtools {
namespace opt {
namespace {
const uint32_t kTypePointerTypeIdInIdx = 1;
} // anonymous namespace
constexpr uint32_t kTypePointerTypeIdInIdx = 1;
} // namespace
bool InlineOpaquePass::IsOpaqueType(uint32_t typeId) {
const Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
switch (typeInst->opcode()) {
case SpvOpTypeSampler:
case SpvOpTypeImage:
case SpvOpTypeSampledImage:
case spv::Op::OpTypeSampler:
case spv::Op::OpTypeImage:
case spv::Op::OpTypeSampledImage:
return true;
case SpvOpTypePointer:
case spv::Op::OpTypePointer:
return IsOpaqueType(
typeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx));
default:
break;
}
// TODO(greg-lunarg): Handle arrays containing opaque type
if (typeInst->opcode() != SpvOpTypeStruct) return false;
if (typeInst->opcode() != spv::Op::OpTypeStruct) return false;
// Return true if any member is opaque
return !typeInst->WhileEachInId([this](const uint32_t* tid) {
if (IsOpaqueType(*tid)) return false;

View File

@@ -23,24 +23,24 @@
#include "source/opt/reflect.h"
#include "source/util/make_unique.h"
// Indices of operands in SPIR-V instructions
static const int kSpvFunctionCallFunctionId = 2;
static const int kSpvFunctionCallArgumentId = 3;
static const int kSpvReturnValueId = 0;
namespace spvtools {
namespace opt {
namespace {
// Indices of operands in SPIR-V instructions
constexpr int kSpvFunctionCallFunctionId = 2;
constexpr int kSpvFunctionCallArgumentId = 3;
constexpr int kSpvReturnValueId = 0;
} // namespace
uint32_t InlinePass::AddPointerToType(uint32_t type_id,
SpvStorageClass storage_class) {
spv::StorageClass storage_class) {
uint32_t resultId = context()->TakeNextId();
if (resultId == 0) {
return resultId;
}
std::unique_ptr<Instruction> type_inst(
new Instruction(context(), SpvOpTypePointer, 0, resultId,
new Instruction(context(), spv::Op::OpTypePointer, 0, resultId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
{uint32_t(storage_class)}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {type_id}}}));
@@ -48,8 +48,8 @@ uint32_t InlinePass::AddPointerToType(uint32_t type_id,
analysis::Type* pointeeTy;
std::unique_ptr<analysis::Pointer> pointerTy;
std::tie(pointeeTy, pointerTy) =
context()->get_type_mgr()->GetTypeAndPointerType(type_id,
SpvStorageClassFunction);
context()->get_type_mgr()->GetTypeAndPointerType(
type_id, spv::StorageClass::Function);
context()->get_type_mgr()->RegisterType(resultId, *pointerTy);
return resultId;
}
@@ -57,7 +57,7 @@ uint32_t InlinePass::AddPointerToType(uint32_t type_id,
void InlinePass::AddBranch(uint32_t label_id,
std::unique_ptr<BasicBlock>* block_ptr) {
std::unique_ptr<Instruction> newBranch(
new Instruction(context(), SpvOpBranch, 0, 0,
new Instruction(context(), spv::Op::OpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
(*block_ptr)->AddInstruction(std::move(newBranch));
}
@@ -66,7 +66,7 @@ void InlinePass::AddBranchCond(uint32_t cond_id, uint32_t true_id,
uint32_t false_id,
std::unique_ptr<BasicBlock>* block_ptr) {
std::unique_ptr<Instruction> newBranch(
new Instruction(context(), SpvOpBranchConditional, 0, 0,
new Instruction(context(), spv::Op::OpBranchConditional, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}}));
@@ -76,7 +76,7 @@ void InlinePass::AddBranchCond(uint32_t cond_id, uint32_t true_id,
void InlinePass::AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
std::unique_ptr<BasicBlock>* block_ptr) {
std::unique_ptr<Instruction> newLoopMerge(new Instruction(
context(), SpvOpLoopMerge, 0, 0,
context(), spv::Op::OpLoopMerge, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {0}}}));
@@ -88,7 +88,7 @@ void InlinePass::AddStore(uint32_t ptr_id, uint32_t val_id,
const Instruction* line_inst,
const DebugScope& dbg_scope) {
std::unique_ptr<Instruction> newStore(
new Instruction(context(), SpvOpStore, 0, 0,
new Instruction(context(), spv::Op::OpStore, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {val_id}}}));
if (line_inst != nullptr) {
@@ -103,7 +103,7 @@ void InlinePass::AddLoad(uint32_t type_id, uint32_t resultId, uint32_t ptr_id,
const Instruction* line_inst,
const DebugScope& dbg_scope) {
std::unique_ptr<Instruction> newLoad(
new Instruction(context(), SpvOpLoad, type_id, resultId,
new Instruction(context(), spv::Op::OpLoad, type_id, resultId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}}}));
if (line_inst != nullptr) {
newLoad->AddDebugLine(line_inst);
@@ -114,27 +114,27 @@ void InlinePass::AddLoad(uint32_t type_id, uint32_t resultId, uint32_t ptr_id,
std::unique_ptr<Instruction> InlinePass::NewLabel(uint32_t label_id) {
std::unique_ptr<Instruction> newLabel(
new Instruction(context(), SpvOpLabel, 0, label_id, {}));
new Instruction(context(), spv::Op::OpLabel, 0, label_id, {}));
return newLabel;
}
uint32_t InlinePass::GetFalseId() {
if (false_id_ != 0) return false_id_;
false_id_ = get_module()->GetGlobalValue(SpvOpConstantFalse);
false_id_ = get_module()->GetGlobalValue(spv::Op::OpConstantFalse);
if (false_id_ != 0) return false_id_;
uint32_t boolId = get_module()->GetGlobalValue(SpvOpTypeBool);
uint32_t boolId = get_module()->GetGlobalValue(spv::Op::OpTypeBool);
if (boolId == 0) {
boolId = context()->TakeNextId();
if (boolId == 0) {
return 0;
}
get_module()->AddGlobalValue(SpvOpTypeBool, boolId, 0);
get_module()->AddGlobalValue(spv::Op::OpTypeBool, boolId, 0);
}
false_id_ = context()->TakeNextId();
if (false_id_ == 0) {
return 0;
}
get_module()->AddGlobalValue(SpvOpConstantFalse, false_id_, boolId);
get_module()->AddGlobalValue(spv::Op::OpConstantFalse, false_id_, boolId);
return false_id_;
}
@@ -157,10 +157,10 @@ bool InlinePass::CloneAndMapLocals(
analysis::DebugInlinedAtContext* inlined_at_ctx) {
auto callee_block_itr = calleeFn->begin();
auto callee_var_itr = callee_block_itr->begin();
while (callee_var_itr->opcode() == SpvOp::SpvOpVariable ||
while (callee_var_itr->opcode() == spv::Op::OpVariable ||
callee_var_itr->GetCommonDebugOpcode() ==
CommonDebugInfoDebugDeclare) {
if (callee_var_itr->opcode() != SpvOp::SpvOpVariable) {
if (callee_var_itr->opcode() != spv::Op::OpVariable) {
++callee_var_itr;
continue;
}
@@ -191,10 +191,11 @@ uint32_t InlinePass::CreateReturnVar(
"Cannot create a return variable of type void.");
// Find or create ptr to callee return type.
uint32_t returnVarTypeId =
type_mgr->FindPointerToType(calleeTypeId, SpvStorageClassFunction);
type_mgr->FindPointerToType(calleeTypeId, spv::StorageClass::Function);
if (returnVarTypeId == 0) {
returnVarTypeId = AddPointerToType(calleeTypeId, SpvStorageClassFunction);
returnVarTypeId =
AddPointerToType(calleeTypeId, spv::StorageClass::Function);
if (returnVarTypeId == 0) {
return 0;
}
@@ -206,17 +207,18 @@ uint32_t InlinePass::CreateReturnVar(
return 0;
}
std::unique_ptr<Instruction> var_inst(
new Instruction(context(), SpvOpVariable, returnVarTypeId, returnVarId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
{SpvStorageClassFunction}}}));
std::unique_ptr<Instruction> var_inst(new Instruction(
context(), spv::Op::OpVariable, returnVarTypeId, returnVarId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
{(uint32_t)spv::StorageClass::Function}}}));
new_vars->push_back(std::move(var_inst));
get_decoration_mgr()->CloneDecorations(calleeFn->result_id(), returnVarId);
return returnVarId;
}
bool InlinePass::IsSameBlockOp(const Instruction* inst) const {
return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
return inst->opcode() == spv::Op::OpSampledImage ||
inst->opcode() == spv::Op::OpImage;
}
bool InlinePass::CloneSameBlockOps(
@@ -299,9 +301,9 @@ InstructionList::iterator InlinePass::AddStoresForVariableInitializers(
std::unique_ptr<BasicBlock>* new_blk_ptr,
UptrVectorIterator<BasicBlock> callee_first_block_itr) {
auto callee_itr = callee_first_block_itr->begin();
while (callee_itr->opcode() == SpvOp::SpvOpVariable ||
while (callee_itr->opcode() == spv::Op::OpVariable ||
callee_itr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) {
if (callee_itr->opcode() == SpvOp::SpvOpVariable &&
if (callee_itr->opcode() == spv::Op::OpVariable &&
callee_itr->NumInOperands() == 2) {
assert(callee2caller.count(callee_itr->result_id()) &&
"Expected the variable to have already been mapped.");
@@ -330,7 +332,8 @@ bool InlinePass::InlineSingleInstruction(
BasicBlock* new_blk_ptr, const Instruction* inst, uint32_t dbg_inlined_at) {
// If we have return, it must be at the end of the callee. We will handle
// it at the end.
if (inst->opcode() == SpvOpReturnValue || inst->opcode() == SpvOpReturn)
if (inst->opcode() == spv::Op::OpReturnValue ||
inst->opcode() == spv::Op::OpReturn)
return true;
// Copy callee instruction and remap all input Ids.
@@ -366,7 +369,7 @@ std::unique_ptr<BasicBlock> InlinePass::InlineReturn(
analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn,
const Instruction* inst, uint32_t returnVarId) {
// Store return value to return variable.
if (inst->opcode() == SpvOpReturnValue) {
if (inst->opcode() == spv::Op::OpReturnValue) {
assert(returnVarId != 0);
uint32_t valId = inst->GetInOperand(kSpvReturnValueId).words[0];
const auto mapItr = callee2caller.find(valId);
@@ -388,7 +391,8 @@ std::unique_ptr<BasicBlock> InlinePass::InlineReturn(
}
if (returnLabelId == 0) return new_blk_ptr;
if (inst->opcode() == SpvOpReturn || inst->opcode() == SpvOpReturnValue)
if (inst->opcode() == spv::Op::OpReturn ||
inst->opcode() == spv::Op::OpReturnValue)
AddBranch(returnLabelId, &new_blk_ptr);
new_blocks->push_back(std::move(new_blk_ptr));
return MakeUnique<BasicBlock>(NewLabel(returnLabelId));
@@ -499,7 +503,7 @@ void InlinePass::MoveLoopMergeInstToFirstBlock(
// Insert a modified copy of the loop merge into the first block.
auto loop_merge_itr = last->tail();
--loop_merge_itr;
assert(loop_merge_itr->opcode() == SpvOpLoopMerge);
assert(loop_merge_itr->opcode() == spv::Op::OpLoopMerge);
std::unique_ptr<Instruction> cp_inst(loop_merge_itr->Clone(context()));
first->tail().InsertBefore(std::move(cp_inst));
@@ -696,7 +700,7 @@ bool InlinePass::GenInlineCode(
}
bool InlinePass::IsInlinableFunctionCall(const Instruction* inst) {
if (inst->opcode() != SpvOp::SpvOpFunctionCall) return false;
if (inst->opcode() != spv::Op::OpFunctionCall) return false;
const uint32_t calleeFnId =
inst->GetSingleWordOperand(kSpvFunctionCallFunctionId);
const auto ci = inlinable_.find(calleeFnId);
@@ -738,7 +742,7 @@ void InlinePass::UpdateSucceedingPhis(
bool InlinePass::HasNoReturnInLoop(Function* func) {
// If control not structured, do not do loop/return analysis
// TODO: Analyze returns in non-structured control flow
if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
return false;
const auto structured_analysis = context()->GetStructuredCFGAnalysis();
// Search for returns in structured construct.
@@ -776,7 +780,7 @@ bool InlinePass::IsInlinableFunction(Function* func) {
if (func->cbegin() == func->cend()) return false;
// Do not inline functions with DontInline flag.
if (func->control_mask() & SpvFunctionControlDontInlineMask) {
if (func->control_mask() & uint32_t(spv::FunctionControlMask::DontInline)) {
return false;
}
@@ -811,7 +815,7 @@ bool InlinePass::IsInlinableFunction(Function* func) {
bool InlinePass::ContainsAbortOtherThanUnreachable(Function* func) const {
return !func->WhileEachInst([](Instruction* inst) {
return inst->opcode() == SpvOpUnreachable ||
return inst->opcode() == spv::Op::OpUnreachable ||
!spvOpcodeIsAbort(inst->opcode());
});
}

View File

@@ -44,7 +44,7 @@ class InlinePass : public Pass {
// Add pointer to type to module and return resultId. Returns 0 if the type
// could not be created.
uint32_t AddPointerToType(uint32_t type_id, SpvStorageClass storage_class);
uint32_t AddPointerToType(uint32_t type_id, spv::StorageClass storage_class);
// Add unconditional branch to labelId to end of block block_ptr.
void AddBranch(uint32_t labelId, std::unique_ptr<BasicBlock>* block_ptr);

View File

@@ -16,31 +16,29 @@
#include "inst_bindless_check_pass.h"
namespace {
// Input Operand Indices
static const int kSpvImageSampleImageIdInIdx = 0;
static const int kSpvSampledImageImageIdInIdx = 0;
static const int kSpvSampledImageSamplerIdInIdx = 1;
static const int kSpvImageSampledImageIdInIdx = 0;
static const int kSpvCopyObjectOperandIdInIdx = 0;
static const int kSpvLoadPtrIdInIdx = 0;
static const int kSpvAccessChainBaseIdInIdx = 0;
static const int kSpvAccessChainIndex0IdInIdx = 1;
static const int kSpvTypeArrayTypeIdInIdx = 0;
static const int kSpvTypeArrayLengthIdInIdx = 1;
static const int kSpvConstantValueInIdx = 0;
static const int kSpvVariableStorageClassInIdx = 0;
static const int kSpvTypePtrTypeIdInIdx = 1;
static const int kSpvTypeImageDim = 1;
static const int kSpvTypeImageDepth = 2;
static const int kSpvTypeImageArrayed = 3;
static const int kSpvTypeImageMS = 4;
static const int kSpvTypeImageSampled = 5;
} // anonymous namespace
namespace spvtools {
namespace opt {
namespace {
// Input Operand Indices
constexpr int kSpvImageSampleImageIdInIdx = 0;
constexpr int kSpvSampledImageImageIdInIdx = 0;
constexpr int kSpvSampledImageSamplerIdInIdx = 1;
constexpr int kSpvImageSampledImageIdInIdx = 0;
constexpr int kSpvCopyObjectOperandIdInIdx = 0;
constexpr int kSpvLoadPtrIdInIdx = 0;
constexpr int kSpvAccessChainBaseIdInIdx = 0;
constexpr int kSpvAccessChainIndex0IdInIdx = 1;
constexpr int kSpvTypeArrayTypeIdInIdx = 0;
constexpr int kSpvTypeArrayLengthIdInIdx = 1;
constexpr int kSpvConstantValueInIdx = 0;
constexpr int kSpvVariableStorageClassInIdx = 0;
constexpr int kSpvTypePtrTypeIdInIdx = 1;
constexpr int kSpvTypeImageDim = 1;
constexpr int kSpvTypeImageDepth = 2;
constexpr int kSpvTypeImageArrayed = 3;
constexpr int kSpvTypeImageMS = 4;
constexpr int kSpvTypeImageSampled = 5;
} // namespace
uint32_t InstBindlessCheckPass::GenDebugReadLength(
uint32_t var_id, InstructionBuilder* builder) {
@@ -79,25 +77,25 @@ uint32_t InstBindlessCheckPass::CloneOriginalImage(
uint32_t old_image_id, InstructionBuilder* builder) {
Instruction* new_image_inst;
Instruction* old_image_inst = get_def_use_mgr()->GetDef(old_image_id);
if (old_image_inst->opcode() == SpvOpLoad) {
if (old_image_inst->opcode() == spv::Op::OpLoad) {
new_image_inst = builder->AddLoad(
old_image_inst->type_id(),
old_image_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
} else if (old_image_inst->opcode() == SpvOp::SpvOpSampledImage) {
} else if (old_image_inst->opcode() == spv::Op::OpSampledImage) {
uint32_t clone_id = CloneOriginalImage(
old_image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx),
builder);
new_image_inst = builder->AddBinaryOp(
old_image_inst->type_id(), SpvOpSampledImage, clone_id,
old_image_inst->type_id(), spv::Op::OpSampledImage, clone_id,
old_image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
} else if (old_image_inst->opcode() == SpvOp::SpvOpImage) {
} else if (old_image_inst->opcode() == spv::Op::OpImage) {
uint32_t clone_id = CloneOriginalImage(
old_image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx),
builder);
new_image_inst =
builder->AddUnaryOp(old_image_inst->type_id(), SpvOpImage, clone_id);
new_image_inst = builder->AddUnaryOp(old_image_inst->type_id(),
spv::Op::OpImage, clone_id);
} else {
assert(old_image_inst->opcode() == SpvOp::SpvOpCopyObject &&
assert(old_image_inst->opcode() == spv::Op::OpCopyObject &&
"expecting OpCopyObject");
uint32_t clone_id = CloneOriginalImage(
old_image_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx),
@@ -143,38 +141,38 @@ uint32_t InstBindlessCheckPass::CloneOriginalReference(
uint32_t InstBindlessCheckPass::GetImageId(Instruction* inst) {
switch (inst->opcode()) {
case SpvOp::SpvOpImageSampleImplicitLod:
case SpvOp::SpvOpImageSampleExplicitLod:
case SpvOp::SpvOpImageSampleDrefImplicitLod:
case SpvOp::SpvOpImageSampleDrefExplicitLod:
case SpvOp::SpvOpImageSampleProjImplicitLod:
case SpvOp::SpvOpImageSampleProjExplicitLod:
case SpvOp::SpvOpImageSampleProjDrefImplicitLod:
case SpvOp::SpvOpImageSampleProjDrefExplicitLod:
case SpvOp::SpvOpImageGather:
case SpvOp::SpvOpImageDrefGather:
case SpvOp::SpvOpImageQueryLod:
case SpvOp::SpvOpImageSparseSampleImplicitLod:
case SpvOp::SpvOpImageSparseSampleExplicitLod:
case SpvOp::SpvOpImageSparseSampleDrefImplicitLod:
case SpvOp::SpvOpImageSparseSampleDrefExplicitLod:
case SpvOp::SpvOpImageSparseSampleProjImplicitLod:
case SpvOp::SpvOpImageSparseSampleProjExplicitLod:
case SpvOp::SpvOpImageSparseSampleProjDrefImplicitLod:
case SpvOp::SpvOpImageSparseSampleProjDrefExplicitLod:
case SpvOp::SpvOpImageSparseGather:
case SpvOp::SpvOpImageSparseDrefGather:
case SpvOp::SpvOpImageFetch:
case SpvOp::SpvOpImageRead:
case SpvOp::SpvOpImageQueryFormat:
case SpvOp::SpvOpImageQueryOrder:
case SpvOp::SpvOpImageQuerySizeLod:
case SpvOp::SpvOpImageQuerySize:
case SpvOp::SpvOpImageQueryLevels:
case SpvOp::SpvOpImageQuerySamples:
case SpvOp::SpvOpImageSparseFetch:
case SpvOp::SpvOpImageSparseRead:
case SpvOp::SpvOpImageWrite:
case spv::Op::OpImageSampleImplicitLod:
case spv::Op::OpImageSampleExplicitLod:
case spv::Op::OpImageSampleDrefImplicitLod:
case spv::Op::OpImageSampleDrefExplicitLod:
case spv::Op::OpImageSampleProjImplicitLod:
case spv::Op::OpImageSampleProjExplicitLod:
case spv::Op::OpImageSampleProjDrefImplicitLod:
case spv::Op::OpImageSampleProjDrefExplicitLod:
case spv::Op::OpImageGather:
case spv::Op::OpImageDrefGather:
case spv::Op::OpImageQueryLod:
case spv::Op::OpImageSparseSampleImplicitLod:
case spv::Op::OpImageSparseSampleExplicitLod:
case spv::Op::OpImageSparseSampleDrefImplicitLod:
case spv::Op::OpImageSparseSampleDrefExplicitLod:
case spv::Op::OpImageSparseSampleProjImplicitLod:
case spv::Op::OpImageSparseSampleProjExplicitLod:
case spv::Op::OpImageSparseSampleProjDrefImplicitLod:
case spv::Op::OpImageSparseSampleProjDrefExplicitLod:
case spv::Op::OpImageSparseGather:
case spv::Op::OpImageSparseDrefGather:
case spv::Op::OpImageFetch:
case spv::Op::OpImageRead:
case spv::Op::OpImageQueryFormat:
case spv::Op::OpImageQueryOrder:
case spv::Op::OpImageQuerySizeLod:
case spv::Op::OpImageQuerySize:
case spv::Op::OpImageQueryLevels:
case spv::Op::OpImageQuerySamples:
case spv::Op::OpImageSparseFetch:
case spv::Op::OpImageSparseRead:
case spv::Op::OpImageWrite:
return inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx);
default:
break;
@@ -190,56 +188,58 @@ Instruction* InstBindlessCheckPass::GetPointeeTypeInst(Instruction* ptr_inst) {
bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
RefAnalysis* ref) {
ref->ref_inst = ref_inst;
if (ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) {
if (ref_inst->opcode() == spv::Op::OpLoad ||
ref_inst->opcode() == spv::Op::OpStore) {
ref->desc_load_id = 0;
ref->ptr_id = ref_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx);
Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return false;
if (ptr_inst->opcode() != spv::Op::OpAccessChain) return false;
ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx);
Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id);
if (var_inst->opcode() != SpvOp::SpvOpVariable) return false;
uint32_t storage_class =
var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx);
if (var_inst->opcode() != spv::Op::OpVariable) return false;
spv::StorageClass storage_class = spv::StorageClass(
var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx));
switch (storage_class) {
case SpvStorageClassUniform:
case SpvStorageClassStorageBuffer:
case spv::StorageClass::Uniform:
case spv::StorageClass::StorageBuffer:
break;
default:
return false;
break;
}
// Check for deprecated storage block form
if (storage_class == SpvStorageClassUniform) {
if (storage_class == spv::StorageClass::Uniform) {
uint32_t var_ty_id = var_inst->type_id();
Instruction* var_ty_inst = get_def_use_mgr()->GetDef(var_ty_id);
uint32_t ptr_ty_id =
var_ty_inst->GetSingleWordInOperand(kSpvTypePtrTypeIdInIdx);
Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id);
SpvOp ptr_ty_op = ptr_ty_inst->opcode();
spv::Op ptr_ty_op = ptr_ty_inst->opcode();
uint32_t block_ty_id =
(ptr_ty_op == SpvOpTypeArray || ptr_ty_op == SpvOpTypeRuntimeArray)
(ptr_ty_op == spv::Op::OpTypeArray ||
ptr_ty_op == spv::Op::OpTypeRuntimeArray)
? ptr_ty_inst->GetSingleWordInOperand(kSpvTypeArrayTypeIdInIdx)
: ptr_ty_id;
assert(get_def_use_mgr()->GetDef(block_ty_id)->opcode() ==
SpvOpTypeStruct &&
spv::Op::OpTypeStruct &&
"unexpected block type");
bool block_found = get_decoration_mgr()->FindDecoration(
block_ty_id, SpvDecorationBlock,
block_ty_id, uint32_t(spv::Decoration::Block),
[](const Instruction&) { return true; });
if (!block_found) {
// If block decoration not found, verify deprecated form of SSBO
bool buffer_block_found = get_decoration_mgr()->FindDecoration(
block_ty_id, SpvDecorationBufferBlock,
block_ty_id, uint32_t(spv::Decoration::BufferBlock),
[](const Instruction&) { return true; });
USE_ASSERT(buffer_block_found && "block decoration not found");
storage_class = SpvStorageClassStorageBuffer;
storage_class = spv::StorageClass::StorageBuffer;
}
}
ref->strg_class = storage_class;
ref->strg_class = uint32_t(storage_class);
Instruction* desc_type_inst = GetPointeeTypeInst(var_inst);
switch (desc_type_inst->opcode()) {
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
// A load through a descriptor array will have at least 3 operands. We
// do not want to instrument loads of descriptors here which are part of
// an image-based reference.
@@ -261,29 +261,29 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
Instruction* desc_load_inst;
for (;;) {
desc_load_inst = get_def_use_mgr()->GetDef(desc_load_id);
if (desc_load_inst->opcode() == SpvOp::SpvOpSampledImage)
if (desc_load_inst->opcode() == spv::Op::OpSampledImage)
desc_load_id =
desc_load_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
else if (desc_load_inst->opcode() == SpvOp::SpvOpImage)
else if (desc_load_inst->opcode() == spv::Op::OpImage)
desc_load_id =
desc_load_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
else if (desc_load_inst->opcode() == SpvOp::SpvOpCopyObject)
else if (desc_load_inst->opcode() == spv::Op::OpCopyObject)
desc_load_id =
desc_load_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx);
else
break;
}
if (desc_load_inst->opcode() != SpvOp::SpvOpLoad) {
if (desc_load_inst->opcode() != spv::Op::OpLoad) {
// TODO(greg-lunarg): Handle additional possibilities?
return false;
}
ref->desc_load_id = desc_load_id;
ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx);
Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
if (ptr_inst->opcode() == SpvOp::SpvOpVariable) {
if (ptr_inst->opcode() == spv::Op::OpVariable) {
ref->desc_idx_id = 0;
ref->var_id = ref->ptr_id;
} else if (ptr_inst->opcode() == SpvOp::SpvOpAccessChain) {
} else if (ptr_inst->opcode() == spv::Op::OpAccessChain) {
if (ptr_inst->NumInOperands() != 2) {
assert(false && "unexpected bindless index number");
return false;
@@ -292,7 +292,7 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx);
ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx);
Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id);
if (var_inst->opcode() != SpvOpVariable) {
if (var_inst->opcode() != spv::Op::OpVariable) {
assert(false && "unexpected bindless base");
return false;
}
@@ -369,13 +369,13 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
uint32_t buff_ty_id;
uint32_t ac_in_idx = 1;
switch (desc_ty_inst->opcode()) {
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
buff_ty_id = desc_ty_inst->GetSingleWordInOperand(0);
++ac_in_idx;
break;
default:
assert(desc_ty_inst->opcode() == SpvOpTypeStruct &&
assert(desc_ty_inst->opcode() == spv::Op::OpTypeStruct &&
"unexpected descriptor type");
buff_ty_id = desc_ty_inst->result_id();
break;
@@ -393,19 +393,20 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
Instruction* curr_ty_inst = get_def_use_mgr()->GetDef(curr_ty_id);
uint32_t curr_offset_id = 0;
switch (curr_ty_inst->opcode()) {
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray: {
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray: {
// Get array stride and multiply by current index
uint32_t arr_stride = FindStride(curr_ty_id, SpvDecorationArrayStride);
uint32_t arr_stride =
FindStride(curr_ty_id, uint32_t(spv::Decoration::ArrayStride));
uint32_t arr_stride_id = builder->GetUintConstantId(arr_stride);
uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder);
Instruction* curr_offset_inst = builder->AddBinaryOp(
GetUintId(), SpvOpIMul, arr_stride_id, curr_idx_32b_id);
GetUintId(), spv::Op::OpIMul, arr_stride_id, curr_idx_32b_id);
curr_offset_id = curr_offset_inst->result_id();
// Get element type for next step
curr_ty_id = curr_ty_inst->GetSingleWordInOperand(0);
} break;
case SpvOpTypeMatrix: {
case spv::Op::OpTypeMatrix: {
assert(matrix_stride != 0 && "missing matrix stride");
matrix_stride_id = builder->GetUintConstantId(matrix_stride);
uint32_t vec_ty_id = curr_ty_inst->GetSingleWordInOperand(0);
@@ -423,40 +424,40 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
}
uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder);
Instruction* curr_offset_inst = builder->AddBinaryOp(
GetUintId(), SpvOpIMul, col_stride_id, curr_idx_32b_id);
GetUintId(), spv::Op::OpIMul, col_stride_id, curr_idx_32b_id);
curr_offset_id = curr_offset_inst->result_id();
// Get element type for next step
curr_ty_id = vec_ty_id;
in_matrix = true;
} break;
case SpvOpTypeVector: {
case spv::Op::OpTypeVector: {
// If inside a row major matrix type, multiply index by matrix stride,
// else multiply by component size
uint32_t comp_ty_id = curr_ty_inst->GetSingleWordInOperand(0u);
uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder);
if (in_matrix && !col_major) {
Instruction* curr_offset_inst = builder->AddBinaryOp(
GetUintId(), SpvOpIMul, matrix_stride_id, curr_idx_32b_id);
GetUintId(), spv::Op::OpIMul, matrix_stride_id, curr_idx_32b_id);
curr_offset_id = curr_offset_inst->result_id();
} else {
uint32_t comp_ty_sz = ByteSize(comp_ty_id, 0u, false, false);
uint32_t comp_ty_sz_id = builder->GetUintConstantId(comp_ty_sz);
Instruction* curr_offset_inst = builder->AddBinaryOp(
GetUintId(), SpvOpIMul, comp_ty_sz_id, curr_idx_32b_id);
GetUintId(), spv::Op::OpIMul, comp_ty_sz_id, curr_idx_32b_id);
curr_offset_id = curr_offset_inst->result_id();
}
// Get element type for next step
curr_ty_id = comp_ty_id;
} break;
case SpvOpTypeStruct: {
case spv::Op::OpTypeStruct: {
// Get buffer byte offset for the referenced member
Instruction* curr_idx_inst = get_def_use_mgr()->GetDef(curr_idx_id);
assert(curr_idx_inst->opcode() == SpvOpConstant &&
assert(curr_idx_inst->opcode() == spv::Op::OpConstant &&
"unexpected struct index");
uint32_t member_idx = curr_idx_inst->GetSingleWordInOperand(0);
uint32_t member_offset = 0xdeadbeef;
bool found = get_decoration_mgr()->FindDecoration(
curr_ty_id, SpvDecorationOffset,
curr_ty_id, uint32_t(spv::Decoration::Offset),
[&member_idx, &member_offset](const Instruction& deco_inst) {
if (deco_inst.GetSingleWordInOperand(1u) != member_idx)
return false;
@@ -470,7 +471,7 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
// enclosing struct type at the member index. If none found, reset
// stride to 0.
found = get_decoration_mgr()->FindDecoration(
curr_ty_id, SpvDecorationMatrixStride,
curr_ty_id, uint32_t(spv::Decoration::MatrixStride),
[&member_idx, &matrix_stride](const Instruction& deco_inst) {
if (deco_inst.GetSingleWordInOperand(1u) != member_idx)
return false;
@@ -480,7 +481,7 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
if (!found) matrix_stride = 0;
// Look for column major decoration
found = get_decoration_mgr()->FindDecoration(
curr_ty_id, SpvDecorationColMajor,
curr_ty_id, uint32_t(spv::Decoration::ColMajor),
[&member_idx, &col_major](const Instruction& deco_inst) {
if (deco_inst.GetSingleWordInOperand(1u) != member_idx)
return false;
@@ -496,8 +497,8 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
if (sum_id == 0)
sum_id = curr_offset_id;
else {
Instruction* sum_inst =
builder->AddBinaryOp(GetUintId(), SpvOpIAdd, sum_id, curr_offset_id);
Instruction* sum_inst = builder->AddBinaryOp(GetUintId(), spv::Op::OpIAdd,
sum_id, curr_offset_id);
sum_id = sum_inst->result_id();
}
++ac_in_idx;
@@ -507,7 +508,7 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
uint32_t last = bsize - 1;
uint32_t last_id = builder->GetUintConstantId(last);
Instruction* sum_inst =
builder->AddBinaryOp(GetUintId(), SpvOpIAdd, sum_id, last_id);
builder->AddBinaryOp(GetUintId(), spv::Op::OpIAdd, sum_id, last_id);
return sum_inst->result_id();
}
@@ -527,8 +528,9 @@ void InstBindlessCheckPass::GenCheckCode(
std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
std::unique_ptr<Instruction> valid_label(NewLabel(valid_blk_id));
std::unique_ptr<Instruction> invalid_label(NewLabel(invalid_blk_id));
(void)builder.AddConditionalBranch(check_id, valid_blk_id, invalid_blk_id,
merge_blk_id, SpvSelectionControlMaskNone);
(void)builder.AddConditionalBranch(
check_id, valid_blk_id, invalid_blk_id, merge_blk_id,
uint32_t(spv::SelectionControlMask::MaskNone));
// Gen valid bounds branch
std::unique_ptr<BasicBlock> new_blk_ptr(
new BasicBlock(std::move(valid_label)));
@@ -593,24 +595,24 @@ void InstBindlessCheckPass::GenDescIdxCheckCode(
RefAnalysis ref;
if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id);
if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return;
if (ptr_inst->opcode() != spv::Op::OpAccessChain) return;
// If index and bound both compile-time constants and index < bound,
// return without changing
Instruction* var_inst = get_def_use_mgr()->GetDef(ref.var_id);
Instruction* desc_type_inst = GetPointeeTypeInst(var_inst);
uint32_t length_id = 0;
if (desc_type_inst->opcode() == SpvOpTypeArray) {
if (desc_type_inst->opcode() == spv::Op::OpTypeArray) {
length_id =
desc_type_inst->GetSingleWordInOperand(kSpvTypeArrayLengthIdInIdx);
Instruction* index_inst = get_def_use_mgr()->GetDef(ref.desc_idx_id);
Instruction* length_inst = get_def_use_mgr()->GetDef(length_id);
if (index_inst->opcode() == SpvOpConstant &&
length_inst->opcode() == SpvOpConstant &&
if (index_inst->opcode() == spv::Op::OpConstant &&
length_inst->opcode() == spv::Op::OpConstant &&
index_inst->GetSingleWordInOperand(kSpvConstantValueInIdx) <
length_inst->GetSingleWordInOperand(kSpvConstantValueInIdx))
return;
} else if (!desc_idx_enabled_ ||
desc_type_inst->opcode() != SpvOpTypeRuntimeArray) {
desc_type_inst->opcode() != spv::Op::OpTypeRuntimeArray) {
return;
}
// Move original block's preceding instructions into first new block
@@ -624,7 +626,7 @@ void InstBindlessCheckPass::GenDescIdxCheckCode(
// If length id not yet set, descriptor array is runtime size so
// generate load of length from stage's debug input buffer.
if (length_id == 0) {
assert(desc_type_inst->opcode() == SpvOpTypeRuntimeArray &&
assert(desc_type_inst->opcode() == spv::Op::OpTypeRuntimeArray &&
"unexpected bindless type");
length_id = GenDebugReadLength(ref.var_id, &builder);
}
@@ -633,7 +635,7 @@ void InstBindlessCheckPass::GenDescIdxCheckCode(
// for the referenced value.
uint32_t desc_idx_32b_id = Gen32BitCvtCode(ref.desc_idx_id, &builder);
uint32_t length_32b_id = Gen32BitCvtCode(length_id, &builder);
Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan,
Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan,
desc_idx_32b_id, length_32b_id);
ref.desc_idx_id = desc_idx_32b_id;
GenCheckCode(ult_inst->result_id(), error_id, 0u, length_id, stage_idx, &ref,
@@ -661,9 +663,10 @@ void InstBindlessCheckPass::GenDescInitCheckCode(
// TODO(greg-lunarg): Do bounds check for aggregate loads and stores
Instruction* ref_ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id);
Instruction* pte_type_inst = GetPointeeTypeInst(ref_ptr_inst);
uint32_t pte_type_op = pte_type_inst->opcode();
if (pte_type_op == SpvOpTypeArray || pte_type_op == SpvOpTypeRuntimeArray ||
pte_type_op == SpvOpTypeStruct)
spv::Op pte_type_op = pte_type_inst->opcode();
if (pte_type_op == spv::Op::OpTypeArray ||
pte_type_op == spv::Op::OpTypeRuntimeArray ||
pte_type_op == spv::Op::OpTypeStruct)
init_check = true;
}
// If initialization check and not enabled, return
@@ -687,11 +690,13 @@ void InstBindlessCheckPass::GenDescInitCheckCode(
// being full reference and false branch being debug output and zero
// for the referenced value.
Instruction* ult_inst =
builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, ref_id, init_id);
uint32_t error = init_check ? kInstErrorBindlessUninit
: (ref.strg_class == SpvStorageClassUniform
? kInstErrorBuffOOBUniform
: kInstErrorBuffOOBStorage);
builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan, ref_id, init_id);
uint32_t error =
init_check
? kInstErrorBindlessUninit
: (spv::StorageClass(ref.strg_class) == spv::StorageClass::Uniform
? kInstErrorBuffOOBUniform
: kInstErrorBuffOOBStorage);
uint32_t error_id = builder.GetUintConstantId(error);
GenCheckCode(ult_inst->result_id(), error_id, init_check ? 0 : ref_id,
init_check ? builder.GetUintConstantId(0u) : init_id, stage_idx,
@@ -708,11 +713,11 @@ void InstBindlessCheckPass::GenTexBuffCheckCode(
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
// Only process OpImageRead and OpImageWrite with no optional operands
Instruction* ref_inst = &*ref_inst_itr;
SpvOp op = ref_inst->opcode();
spv::Op op = ref_inst->opcode();
uint32_t num_in_oprnds = ref_inst->NumInOperands();
if (!((op == SpvOpImageRead && num_in_oprnds == 2) ||
(op == SpvOpImageFetch && num_in_oprnds == 2) ||
(op == SpvOpImageWrite && num_in_oprnds == 3)))
if (!((op == spv::Op::OpImageRead && num_in_oprnds == 2) ||
(op == spv::Op::OpImageFetch && num_in_oprnds == 2) ||
(op == spv::Op::OpImageWrite && num_in_oprnds == 3)))
return;
// Pull components from descriptor reference
RefAnalysis ref;
@@ -721,17 +726,20 @@ void InstBindlessCheckPass::GenTexBuffCheckCode(
Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id);
uint32_t image_ty_id = image_inst->type_id();
Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id);
if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim) != SpvDimBuffer)
if (spv::Dim(image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim)) !=
spv::Dim::Buffer) {
return;
}
if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) != 0) return;
if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) != 0) return;
if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) != 0) return;
// Enable ImageQuery Capability if not yet enabled
if (!get_feature_mgr()->HasCapability(SpvCapabilityImageQuery)) {
std::unique_ptr<Instruction> cap_image_query_inst(new Instruction(
context(), SpvOpCapability, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityImageQuery}}}));
if (!get_feature_mgr()->HasCapability(spv::Capability::ImageQuery)) {
std::unique_ptr<Instruction> cap_image_query_inst(
new Instruction(context(), spv::Op::OpCapability, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_CAPABILITY,
{uint32_t(spv::Capability::ImageQuery)}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*cap_image_query_inst);
context()->AddCapability(std::move(cap_image_query_inst));
}
@@ -750,13 +758,13 @@ void InstBindlessCheckPass::GenTexBuffCheckCode(
if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u);
// Get texel buffer size.
Instruction* size_inst =
builder.AddUnaryOp(GetUintId(), SpvOpImageQuerySize, ref.image_id);
builder.AddUnaryOp(GetUintId(), spv::Op::OpImageQuerySize, ref.image_id);
uint32_t size_id = size_inst->result_id();
// Generate runtime initialization/bounds test code with true branch
// being full reference and false branch being debug output and zero
// for the referenced value.
Instruction* ult_inst =
builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id);
builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan, coord_id, size_id);
uint32_t error =
(image_ty_inst->GetSingleWordInOperand(kSpvTypeImageSampled) == 2)
? kInstErrorBuffOOBStorageTexel
@@ -778,13 +786,16 @@ void InstBindlessCheckPass::InitializeInstBindlessCheck() {
// init check is enabled.
if (desc_idx_enabled_ || buffer_bounds_enabled_ || texel_buffer_enabled_)
for (auto& anno : get_module()->annotations())
if (anno.opcode() == SpvOpDecorate) {
if (anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet)
if (anno.opcode() == spv::Op::OpDecorate) {
if (spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
spv::Decoration::DescriptorSet) {
var2desc_set_[anno.GetSingleWordInOperand(0u)] =
anno.GetSingleWordInOperand(2u);
else if (anno.GetSingleWordInOperand(1u) == SpvDecorationBinding)
} else if (spv::Decoration(anno.GetSingleWordInOperand(1u)) ==
spv::Decoration::Binding) {
var2binding_[anno.GetSingleWordInOperand(0u)] =
anno.GetSingleWordInOperand(2u);
}
}
}

View File

@@ -22,9 +22,9 @@ namespace opt {
uint32_t InstBuffAddrCheckPass::CloneOriginalReference(
Instruction* ref_inst, InstructionBuilder* builder) {
// Clone original ref with new result id (if load)
assert(
(ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) &&
"unexpected ref");
assert((ref_inst->opcode() == spv::Op::OpLoad ||
ref_inst->opcode() == spv::Op::OpStore) &&
"unexpected ref");
std::unique_ptr<Instruction> new_ref_inst(ref_inst->Clone(context()));
uint32_t ref_result_id = ref_inst->result_id();
uint32_t new_ref_id = 0;
@@ -41,16 +41,17 @@ uint32_t InstBuffAddrCheckPass::CloneOriginalReference(
}
bool InstBuffAddrCheckPass::IsPhysicalBuffAddrReference(Instruction* ref_inst) {
if (ref_inst->opcode() != SpvOpLoad && ref_inst->opcode() != SpvOpStore)
if (ref_inst->opcode() != spv::Op::OpLoad &&
ref_inst->opcode() != spv::Op::OpStore)
return false;
uint32_t ptr_id = ref_inst->GetSingleWordInOperand(0);
analysis::DefUseManager* du_mgr = get_def_use_mgr();
Instruction* ptr_inst = du_mgr->GetDef(ptr_id);
if (ptr_inst->opcode() != SpvOpAccessChain) return false;
if (ptr_inst->opcode() != spv::Op::OpAccessChain) return false;
uint32_t ptr_ty_id = ptr_inst->type_id();
Instruction* ptr_ty_inst = du_mgr->GetDef(ptr_ty_id);
if (ptr_ty_inst->GetSingleWordInOperand(0) !=
SpvStorageClassPhysicalStorageBufferEXT)
if (spv::StorageClass(ptr_ty_inst->GetSingleWordInOperand(0)) !=
spv::StorageClass::PhysicalStorageBufferEXT)
return false;
return true;
}
@@ -72,8 +73,9 @@ void InstBuffAddrCheckPass::GenCheckCode(
std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
std::unique_ptr<Instruction> valid_label(NewLabel(valid_blk_id));
std::unique_ptr<Instruction> invalid_label(NewLabel(invalid_blk_id));
(void)builder.AddConditionalBranch(check_id, valid_blk_id, invalid_blk_id,
merge_blk_id, SpvSelectionControlMaskNone);
(void)builder.AddConditionalBranch(
check_id, valid_blk_id, invalid_blk_id, merge_blk_id,
uint32_t(spv::SelectionControlMask::MaskNone));
// Gen valid branch
std::unique_ptr<BasicBlock> new_blk_ptr(
new BasicBlock(std::move(valid_label)));
@@ -86,12 +88,12 @@ void InstBuffAddrCheckPass::GenCheckCode(
builder.SetInsertPoint(&*new_blk_ptr);
// Convert uptr from uint64 to 2 uint32
Instruction* lo_uptr_inst =
builder.AddUnaryOp(GetUintId(), SpvOpUConvert, ref_uptr_id);
builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, ref_uptr_id);
Instruction* rshift_uptr_inst =
builder.AddBinaryOp(GetUint64Id(), SpvOpShiftRightLogical, ref_uptr_id,
builder.GetUintConstantId(32));
Instruction* hi_uptr_inst = builder.AddUnaryOp(GetUintId(), SpvOpUConvert,
rshift_uptr_inst->result_id());
builder.AddBinaryOp(GetUint64Id(), spv::Op::OpShiftRightLogical,
ref_uptr_id, builder.GetUintConstantId(32));
Instruction* hi_uptr_inst = builder.AddUnaryOp(
GetUintId(), spv::Op::OpUConvert, rshift_uptr_inst->result_id());
GenDebugStreamWrite(
uid2offset_[ref_inst->unique_id()], stage_idx,
{error_id, lo_uptr_inst->result_id(), hi_uptr_inst->result_id()},
@@ -105,8 +107,8 @@ void InstBuffAddrCheckPass::GenCheckCode(
analysis::Type* ref_type = type_mgr->GetType(ref_type_id);
if (ref_type->AsPointer() != nullptr) {
uint32_t null_u64_id = GetNullId(GetUint64Id());
Instruction* null_ptr_inst =
builder.AddUnaryOp(ref_type_id, SpvOpConvertUToPtr, null_u64_id);
Instruction* null_ptr_inst = builder.AddUnaryOp(
ref_type_id, spv::Op::OpConvertUToPtr, null_u64_id);
null_id = null_ptr_inst->result_id();
} else {
null_id = GetNullId(ref_type_id);
@@ -133,16 +135,16 @@ void InstBuffAddrCheckPass::GenCheckCode(
uint32_t InstBuffAddrCheckPass::GetTypeAlignment(uint32_t type_id) {
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
switch (type_inst->opcode()) {
case SpvOpTypeFloat:
case SpvOpTypeInt:
case SpvOpTypeVector:
case spv::Op::OpTypeFloat:
case spv::Op::OpTypeInt:
case spv::Op::OpTypeVector:
return GetTypeLength(type_id);
case SpvOpTypeMatrix:
case spv::Op::OpTypeMatrix:
return GetTypeAlignment(type_inst->GetSingleWordInOperand(0));
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
case spv::Op::OpTypeArray:
case spv::Op::OpTypeRuntimeArray:
return GetTypeAlignment(type_inst->GetSingleWordInOperand(0));
case SpvOpTypeStruct: {
case spv::Op::OpTypeStruct: {
uint32_t max = 0;
type_inst->ForEachInId([&max, this](const uint32_t* iid) {
uint32_t alignment = GetTypeAlignment(*iid);
@@ -150,9 +152,9 @@ uint32_t InstBuffAddrCheckPass::GetTypeAlignment(uint32_t type_id) {
});
return max;
}
case SpvOpTypePointer:
assert(type_inst->GetSingleWordInOperand(0) ==
SpvStorageClassPhysicalStorageBufferEXT &&
case spv::Op::OpTypePointer:
assert(spv::StorageClass(type_inst->GetSingleWordInOperand(0)) ==
spv::StorageClass::PhysicalStorageBufferEXT &&
"unexpected pointer type");
return 8u;
default:
@@ -164,29 +166,29 @@ uint32_t InstBuffAddrCheckPass::GetTypeAlignment(uint32_t type_id) {
uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) {
Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
switch (type_inst->opcode()) {
case SpvOpTypeFloat:
case SpvOpTypeInt:
case spv::Op::OpTypeFloat:
case spv::Op::OpTypeInt:
return type_inst->GetSingleWordInOperand(0) / 8u;
case SpvOpTypeVector: {
case spv::Op::OpTypeVector: {
uint32_t raw_cnt = type_inst->GetSingleWordInOperand(1);
uint32_t adj_cnt = (raw_cnt == 3u) ? 4u : raw_cnt;
return adj_cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0));
}
case SpvOpTypeMatrix:
case spv::Op::OpTypeMatrix:
return type_inst->GetSingleWordInOperand(1) *
GetTypeLength(type_inst->GetSingleWordInOperand(0));
case SpvOpTypePointer:
assert(type_inst->GetSingleWordInOperand(0) ==
SpvStorageClassPhysicalStorageBufferEXT &&
case spv::Op::OpTypePointer:
assert(spv::StorageClass(type_inst->GetSingleWordInOperand(0)) ==
spv::StorageClass::PhysicalStorageBufferEXT &&
"unexpected pointer type");
return 8u;
case SpvOpTypeArray: {
case spv::Op::OpTypeArray: {
uint32_t const_id = type_inst->GetSingleWordInOperand(1);
Instruction* const_inst = get_def_use_mgr()->GetDef(const_id);
uint32_t cnt = const_inst->GetSingleWordInOperand(0);
return cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0));
}
case SpvOpTypeStruct: {
case spv::Op::OpTypeStruct: {
uint32_t len = 0;
type_inst->ForEachInId([&len, this](const uint32_t* iid) {
// Align struct length
@@ -200,7 +202,7 @@ uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) {
});
return len;
}
case SpvOpTypeRuntimeArray:
case spv::Op::OpTypeRuntimeArray:
default:
assert(false && "unexpected type");
return 0;
@@ -213,7 +215,7 @@ void InstBuffAddrCheckPass::AddParam(uint32_t type_id,
uint32_t pid = TakeNextId();
param_vec->push_back(pid);
std::unique_ptr<Instruction> param_inst(new Instruction(
get_module()->context(), SpvOpFunctionParameter, type_id, pid, {}));
get_module()->context(), spv::Op::OpFunctionParameter, type_id, pid, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
(*input_func)->AddParameter(std::move(param_inst));
}
@@ -231,10 +233,10 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() {
analysis::Function func_ty(type_mgr->GetType(GetBoolId()), param_types);
analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
std::unique_ptr<Instruction> func_inst(
new Instruction(get_module()->context(), SpvOpFunction, GetBoolId(),
search_test_func_id_,
new Instruction(get_module()->context(), spv::Op::OpFunction,
GetBoolId(), search_test_func_id_,
{{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
{SpvFunctionControlMaskNone}},
{uint32_t(spv::FunctionControlMask::MaskNone)}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
{type_mgr->GetTypeInstruction(reg_func_ty)}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
@@ -256,7 +258,7 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() {
// Branch to search loop header
std::unique_ptr<Instruction> hdr_blk_label(NewLabel(hdr_blk_id));
(void)builder.AddInstruction(MakeUnique<Instruction>(
context(), SpvOpBranch, 0, 0,
context(), spv::Op::OpBranch, 0, 0,
std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {hdr_blk_id}}}));
input_func->AddBasicBlock(std::move(first_blk_ptr));
// Linear search loop header block
@@ -273,12 +275,12 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() {
uint32_t idx_phi_id = TakeNextId();
uint32_t idx_inc_id = TakeNextId();
std::unique_ptr<Instruction> idx_inc_inst(new Instruction(
context(), SpvOpIAdd, GetUintId(), idx_inc_id,
context(), spv::Op::OpIAdd, GetUintId(), idx_inc_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {idx_phi_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
{builder.GetUintConstantId(1u)}}}));
std::unique_ptr<Instruction> idx_phi_inst(new Instruction(
context(), SpvOpPhi, GetUintId(), idx_phi_id,
context(), spv::Op::OpPhi, GetUintId(), idx_phi_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
{builder.GetUintConstantId(1u)}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {first_blk_id}},
@@ -292,14 +294,15 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() {
std::unique_ptr<Instruction> bound_test_blk_label(
NewLabel(bound_test_blk_id));
(void)builder.AddInstruction(MakeUnique<Instruction>(
context(), SpvOpLoopMerge, 0, 0,
context(), spv::Op::OpLoopMerge, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {bound_test_blk_id}},
{SPV_OPERAND_TYPE_ID, {cont_blk_id}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {SpvLoopControlMaskNone}}}));
{SPV_OPERAND_TYPE_LITERAL_INTEGER,
{uint32_t(spv::LoopControlMask::MaskNone)}}}));
// Branch to continue/work block
(void)builder.AddInstruction(MakeUnique<Instruction>(
context(), SpvOpBranch, 0, 0,
context(), spv::Op::OpBranch, 0, 0,
std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {cont_blk_id}}}));
input_func->AddBasicBlock(std::move(hdr_blk_ptr));
// Continue/Work Block. Read next buffer pointer and break if greater
@@ -313,19 +316,19 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() {
uint32_t ibuf_id = GetInputBufferId();
uint32_t ibuf_ptr_id = GetInputBufferPtrId();
Instruction* uptr_ac_inst = builder.AddTernaryOp(
ibuf_ptr_id, SpvOpAccessChain, ibuf_id,
ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id,
builder.GetUintConstantId(kDebugInputDataOffset), idx_inc_id);
uint32_t ibuf_type_id = GetInputBufferTypeId();
Instruction* uptr_load_inst =
builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, uptr_ac_inst->result_id());
Instruction* uptr_load_inst = builder.AddUnaryOp(
ibuf_type_id, spv::Op::OpLoad, uptr_ac_inst->result_id());
// If loaded address greater than ref_ptr arg, break, else branch back to
// loop header
Instruction* uptr_test_inst =
builder.AddBinaryOp(GetBoolId(), SpvOpUGreaterThan,
builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThan,
uptr_load_inst->result_id(), param_vec[0]);
(void)builder.AddConditionalBranch(uptr_test_inst->result_id(),
bound_test_blk_id, hdr_blk_id,
kInvalidId, SpvSelectionControlMaskNone);
(void)builder.AddConditionalBranch(
uptr_test_inst->result_id(), bound_test_blk_id, hdr_blk_id, kInvalidId,
uint32_t(spv::SelectionControlMask::MaskNone));
input_func->AddBasicBlock(std::move(cont_blk_ptr));
// Bounds test block. Read length of selected buffer and test that
// all len arg bytes are in buffer.
@@ -333,63 +336,65 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() {
MakeUnique<BasicBlock>(std::move(bound_test_blk_label));
builder.SetInsertPoint(&*bound_test_blk_ptr);
// Decrement index to point to previous/candidate buffer address
Instruction* cand_idx_inst = builder.AddBinaryOp(
GetUintId(), SpvOpISub, idx_inc_id, builder.GetUintConstantId(1u));
Instruction* cand_idx_inst =
builder.AddBinaryOp(GetUintId(), spv::Op::OpISub, idx_inc_id,
builder.GetUintConstantId(1u));
// Load candidate buffer address
Instruction* cand_ac_inst =
builder.AddTernaryOp(ibuf_ptr_id, SpvOpAccessChain, ibuf_id,
builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id,
builder.GetUintConstantId(kDebugInputDataOffset),
cand_idx_inst->result_id());
Instruction* cand_load_inst =
builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, cand_ac_inst->result_id());
Instruction* cand_load_inst = builder.AddUnaryOp(
ibuf_type_id, spv::Op::OpLoad, cand_ac_inst->result_id());
// Compute offset of ref_ptr from candidate buffer address
Instruction* offset_inst = builder.AddBinaryOp(
ibuf_type_id, SpvOpISub, param_vec[0], cand_load_inst->result_id());
Instruction* offset_inst =
builder.AddBinaryOp(ibuf_type_id, spv::Op::OpISub, param_vec[0],
cand_load_inst->result_id());
// Convert ref length to uint64
Instruction* ref_len_64_inst =
builder.AddUnaryOp(ibuf_type_id, SpvOpUConvert, param_vec[1]);
builder.AddUnaryOp(ibuf_type_id, spv::Op::OpUConvert, param_vec[1]);
// Add ref length to ref offset to compute end of reference
Instruction* ref_end_inst =
builder.AddBinaryOp(ibuf_type_id, SpvOpIAdd, offset_inst->result_id(),
ref_len_64_inst->result_id());
Instruction* ref_end_inst = builder.AddBinaryOp(
ibuf_type_id, spv::Op::OpIAdd, offset_inst->result_id(),
ref_len_64_inst->result_id());
// Load starting index of lengths in input buffer and convert to uint32
Instruction* len_start_ac_inst =
builder.AddTernaryOp(ibuf_ptr_id, SpvOpAccessChain, ibuf_id,
builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id,
builder.GetUintConstantId(kDebugInputDataOffset),
builder.GetUintConstantId(0u));
Instruction* len_start_load_inst = builder.AddUnaryOp(
ibuf_type_id, SpvOpLoad, len_start_ac_inst->result_id());
ibuf_type_id, spv::Op::OpLoad, len_start_ac_inst->result_id());
Instruction* len_start_32_inst = builder.AddUnaryOp(
GetUintId(), SpvOpUConvert, len_start_load_inst->result_id());
GetUintId(), spv::Op::OpUConvert, len_start_load_inst->result_id());
// Decrement search index to get candidate buffer length index
Instruction* cand_len_idx_inst =
builder.AddBinaryOp(GetUintId(), SpvOpISub, cand_idx_inst->result_id(),
builder.GetUintConstantId(1u));
Instruction* cand_len_idx_inst = builder.AddBinaryOp(
GetUintId(), spv::Op::OpISub, cand_idx_inst->result_id(),
builder.GetUintConstantId(1u));
// Add candidate length index to start index
Instruction* len_idx_inst = builder.AddBinaryOp(
GetUintId(), SpvOpIAdd, cand_len_idx_inst->result_id(),
GetUintId(), spv::Op::OpIAdd, cand_len_idx_inst->result_id(),
len_start_32_inst->result_id());
// Load candidate buffer length
Instruction* len_ac_inst =
builder.AddTernaryOp(ibuf_ptr_id, SpvOpAccessChain, ibuf_id,
builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id,
builder.GetUintConstantId(kDebugInputDataOffset),
len_idx_inst->result_id());
Instruction* len_load_inst =
builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, len_ac_inst->result_id());
Instruction* len_load_inst = builder.AddUnaryOp(
ibuf_type_id, spv::Op::OpLoad, len_ac_inst->result_id());
// Test if reference end within candidate buffer length
Instruction* len_test_inst = builder.AddBinaryOp(
GetBoolId(), SpvOpULessThanEqual, ref_end_inst->result_id(),
GetBoolId(), spv::Op::OpULessThanEqual, ref_end_inst->result_id(),
len_load_inst->result_id());
// Return test result
(void)builder.AddInstruction(MakeUnique<Instruction>(
context(), SpvOpReturnValue, 0, 0,
context(), spv::Op::OpReturnValue, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {len_test_inst->result_id()}}}));
// Close block
input_func->AddBasicBlock(std::move(bound_test_blk_ptr));
// Close function and add function to module
std::unique_ptr<Instruction> func_end_inst(
new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
std::unique_ptr<Instruction> func_end_inst(new Instruction(
get_module()->context(), spv::Op::OpFunctionEnd, 0, 0, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
input_func->SetFunctionEnd(std::move(func_end_inst));
context()->AddFunction(std::move(input_func));
@@ -403,18 +408,18 @@ uint32_t InstBuffAddrCheckPass::GenSearchAndTest(Instruction* ref_inst,
InstructionBuilder* builder,
uint32_t* ref_uptr_id) {
// Enable Int64 if necessary
if (!get_feature_mgr()->HasCapability(SpvCapabilityInt64)) {
if (!get_feature_mgr()->HasCapability(spv::Capability::Int64)) {
std::unique_ptr<Instruction> cap_int64_inst(new Instruction(
context(), SpvOpCapability, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityInt64}}}));
context(), spv::Op::OpCapability, 0, 0,
std::initializer_list<Operand>{{SPV_OPERAND_TYPE_CAPABILITY,
{uint32_t(spv::Capability::Int64)}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*cap_int64_inst);
context()->AddCapability(std::move(cap_int64_inst));
}
// Convert reference pointer to uint64
uint32_t ref_ptr_id = ref_inst->GetSingleWordInOperand(0);
Instruction* ref_uptr_inst =
builder->AddUnaryOp(GetUint64Id(), SpvOpConvertPtrToU, ref_ptr_id);
builder->AddUnaryOp(GetUint64Id(), spv::Op::OpConvertPtrToU, ref_ptr_id);
*ref_uptr_id = ref_uptr_inst->result_id();
// Compute reference length in bytes
analysis::DefUseManager* du_mgr = get_def_use_mgr();
@@ -427,7 +432,7 @@ uint32_t InstBuffAddrCheckPass::GenSearchAndTest(Instruction* ref_inst,
const std::vector<uint32_t> args = {GetSearchAndTestFuncId(), *ref_uptr_id,
ref_len_id};
Instruction* call_inst =
builder->AddNaryOp(GetBoolId(), SpvOpFunctionCall, args);
builder->AddNaryOp(GetBoolId(), spv::Op::OpFunctionCall, args);
uint32_t retval = call_inst->result_id();
return retval;
}
@@ -485,7 +490,7 @@ Pass::Status InstBuffAddrCheckPass::ProcessImpl() {
Pass::Status InstBuffAddrCheckPass::Process() {
if (!get_feature_mgr()->HasCapability(
SpvCapabilityPhysicalStorageBufferAddressesEXT))
spv::Capability::PhysicalStorageBufferAddressesEXT))
return Status::SuccessWithoutChange;
InitInstBuffAddrCheck();
return ProcessImpl();

View File

@@ -35,7 +35,7 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst,
uint32_t c_ty_id = type_mgr->GetId(c_ty);
for (uint32_t c = 0; c < v_ty->element_count(); ++c) {
Instruction* c_inst = builder->AddIdLiteralOp(
c_ty_id, SpvOpCompositeExtract, val_inst->result_id(), c);
c_ty_id, spv::Op::OpCompositeExtract, val_inst->result_id(), c);
GenOutputValues(c_inst, val_ids, builder);
}
return;
@@ -44,8 +44,9 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst,
// Select between uint32 zero or one
uint32_t zero_id = builder->GetUintConstantId(0);
uint32_t one_id = builder->GetUintConstantId(1);
Instruction* sel_inst = builder->AddTernaryOp(
GetUintId(), SpvOpSelect, val_inst->result_id(), one_id, zero_id);
Instruction* sel_inst =
builder->AddTernaryOp(GetUintId(), spv::Op::OpSelect,
val_inst->result_id(), one_id, zero_id);
val_ids->push_back(sel_inst->result_id());
return;
}
@@ -55,21 +56,21 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst,
case 16: {
// Convert float16 to float32 and recurse
Instruction* f32_inst = builder->AddUnaryOp(
GetFloatId(), SpvOpFConvert, val_inst->result_id());
GetFloatId(), spv::Op::OpFConvert, val_inst->result_id());
GenOutputValues(f32_inst, val_ids, builder);
return;
}
case 64: {
// Bitcast float64 to uint64 and recurse
Instruction* ui64_inst = builder->AddUnaryOp(
GetUint64Id(), SpvOpBitcast, val_inst->result_id());
GetUint64Id(), spv::Op::OpBitcast, val_inst->result_id());
GenOutputValues(ui64_inst, val_ids, builder);
return;
}
case 32: {
// Bitcase float32 to uint32
Instruction* bc_inst = builder->AddUnaryOp(GetUintId(), SpvOpBitcast,
val_inst->result_id());
Instruction* bc_inst = builder->AddUnaryOp(
GetUintId(), spv::Op::OpBitcast, val_inst->result_id());
val_ids->push_back(bc_inst->result_id());
return;
}
@@ -85,17 +86,17 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst,
Instruction* ui64_inst = val_inst;
if (i_ty->IsSigned()) {
// Bitcast sint64 to uint64
ui64_inst = builder->AddUnaryOp(GetUint64Id(), SpvOpBitcast,
ui64_inst = builder->AddUnaryOp(GetUint64Id(), spv::Op::OpBitcast,
val_inst->result_id());
}
// Break uint64 into 2x uint32
Instruction* lo_ui64_inst = builder->AddUnaryOp(
GetUintId(), SpvOpUConvert, ui64_inst->result_id());
GetUintId(), spv::Op::OpUConvert, ui64_inst->result_id());
Instruction* rshift_ui64_inst = builder->AddBinaryOp(
GetUint64Id(), SpvOpShiftRightLogical, ui64_inst->result_id(),
builder->GetUintConstantId(32));
GetUint64Id(), spv::Op::OpShiftRightLogical,
ui64_inst->result_id(), builder->GetUintConstantId(32));
Instruction* hi_ui64_inst = builder->AddUnaryOp(
GetUintId(), SpvOpUConvert, rshift_ui64_inst->result_id());
GetUintId(), spv::Op::OpUConvert, rshift_ui64_inst->result_id());
val_ids->push_back(lo_ui64_inst->result_id());
val_ids->push_back(hi_ui64_inst->result_id());
return;
@@ -104,12 +105,12 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst,
Instruction* ui8_inst = val_inst;
if (i_ty->IsSigned()) {
// Bitcast sint8 to uint8
ui8_inst = builder->AddUnaryOp(GetUint8Id(), SpvOpBitcast,
ui8_inst = builder->AddUnaryOp(GetUint8Id(), spv::Op::OpBitcast,
val_inst->result_id());
}
// Convert uint8 to uint32
Instruction* ui32_inst = builder->AddUnaryOp(
GetUintId(), SpvOpUConvert, ui8_inst->result_id());
GetUintId(), spv::Op::OpUConvert, ui8_inst->result_id());
val_ids->push_back(ui32_inst->result_id());
return;
}
@@ -117,7 +118,7 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst,
Instruction* ui32_inst = val_inst;
if (i_ty->IsSigned()) {
// Bitcast sint32 to uint32
ui32_inst = builder->AddUnaryOp(GetUintId(), SpvOpBitcast,
ui32_inst = builder->AddUnaryOp(GetUintId(), spv::Op::OpBitcast,
val_inst->result_id());
}
// uint32 needs no further processing
@@ -158,7 +159,7 @@ void InstDebugPrintfPass::GenOutputCode(
return;
}
Instruction* opnd_inst = get_def_use_mgr()->GetDef(*iid);
if (opnd_inst->opcode() == SpvOpString) {
if (opnd_inst->opcode() == spv::Op::OpString) {
uint32_t string_id_id = builder.GetUintConstantId(*iid);
val_ids.push_back(string_id_id);
} else {
@@ -176,7 +177,7 @@ void InstDebugPrintfPass::GenDebugPrintfCode(
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
// If not DebugPrintf OpExtInst, return.
Instruction* printf_inst = &*ref_inst_itr;
if (printf_inst->opcode() != SpvOpExtInst) return;
if (printf_inst->opcode() != spv::Op::OpExtInst) return;
if (printf_inst->GetSingleWordInOperand(0) != ext_inst_printf_id_) return;
if (printf_inst->GetSingleWordInOperand(1) !=
NonSemanticDebugPrintfDebugPrintf)

View File

@@ -24,38 +24,37 @@
namespace spvtools {
namespace opt {
namespace {
// Indices used to get particular operands out of instructions using InOperand.
const uint32_t kTypeImageDimIndex = 1;
const uint32_t kLoadBaseIndex = 0;
const uint32_t kPointerTypeStorageClassIndex = 0;
const uint32_t kVariableStorageClassIndex = 0;
const uint32_t kTypeImageSampledIndex = 5;
constexpr uint32_t kTypeImageDimIndex = 1;
constexpr uint32_t kLoadBaseIndex = 0;
constexpr uint32_t kPointerTypeStorageClassIndex = 0;
constexpr uint32_t kVariableStorageClassIndex = 0;
constexpr uint32_t kTypeImageSampledIndex = 5;
// Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100
// extension instructions.
const uint32_t kExtInstSetIdInIdx = 0;
const uint32_t kExtInstInstructionInIdx = 1;
const uint32_t kDebugScopeNumWords = 7;
const uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6;
const uint32_t kDebugNoScopeNumWords = 5;
constexpr uint32_t kExtInstSetIdInIdx = 0;
constexpr uint32_t kExtInstInstructionInIdx = 1;
constexpr uint32_t kDebugScopeNumWords = 7;
constexpr uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6;
constexpr uint32_t kDebugNoScopeNumWords = 5;
// Number of operands of an OpBranchConditional instruction
// with weights.
const uint32_t kOpBranchConditionalWithWeightsNumOperands = 5;
constexpr uint32_t kOpBranchConditionalWithWeightsNumOperands = 5;
} // namespace
Instruction::Instruction(IRContext* c)
: utils::IntrusiveNodeBase<Instruction>(),
context_(c),
opcode_(SpvOpNop),
opcode_(spv::Op::OpNop),
has_type_id_(false),
has_result_id_(false),
unique_id_(c->TakeNextUniqueId()),
dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
Instruction::Instruction(IRContext* c, SpvOp op)
Instruction::Instruction(IRContext* c, spv::Op op)
: utils::IntrusiveNodeBase<Instruction>(),
context_(c),
opcode_(op),
@@ -68,12 +67,13 @@ Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
std::vector<Instruction>&& dbg_line)
: utils::IntrusiveNodeBase<Instruction>(),
context_(c),
opcode_(static_cast<SpvOp>(inst.opcode)),
opcode_(static_cast<spv::Op>(inst.opcode)),
has_type_id_(inst.type_id != 0),
has_result_id_(inst.result_id != 0),
unique_id_(c->TakeNextUniqueId()),
dbg_line_insts_(std::move(dbg_line)),
dbg_scope_(kNoDebugScope, kNoInlinedAt) {
operands_.reserve(inst.num_operands);
for (uint32_t i = 0; i < inst.num_operands; ++i) {
const auto& current_payload = inst.operands[i];
operands_.emplace_back(
@@ -88,11 +88,12 @@ Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
const DebugScope& dbg_scope)
: utils::IntrusiveNodeBase<Instruction>(),
context_(c),
opcode_(static_cast<SpvOp>(inst.opcode)),
opcode_(static_cast<spv::Op>(inst.opcode)),
has_type_id_(inst.type_id != 0),
has_result_id_(inst.result_id != 0),
unique_id_(c->TakeNextUniqueId()),
dbg_scope_(dbg_scope) {
operands_.reserve(inst.num_operands);
for (uint32_t i = 0; i < inst.num_operands; ++i) {
const auto& current_payload = inst.operands[i];
operands_.emplace_back(
@@ -101,7 +102,7 @@ Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
}
}
Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id,
Instruction::Instruction(IRContext* c, spv::Op op, uint32_t ty_id,
uint32_t res_id, const OperandList& in_operands)
: utils::IntrusiveNodeBase<Instruction>(),
context_(c),
@@ -111,6 +112,14 @@ Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id,
unique_id_(c->TakeNextUniqueId()),
operands_(),
dbg_scope_(kNoDebugScope, kNoInlinedAt) {
size_t operands_size = in_operands.size();
if (has_type_id_) {
operands_size++;
}
if (has_result_id_) {
operands_size++;
}
operands_.reserve(operands_size);
if (has_type_id_) {
operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID,
std::initializer_list<uint32_t>{ty_id});
@@ -179,7 +188,7 @@ uint32_t Instruction::NumInOperandWords() const {
}
bool Instruction::HasBranchWeights() const {
if (opcode_ == SpvOpBranchConditional &&
if (opcode_ == spv::Op::OpBranchConditional &&
NumOperands() == kOpBranchConditionalWithWeightsNumOperands) {
return true;
}
@@ -208,13 +217,13 @@ bool Instruction::IsReadOnlyLoad() const {
return false;
}
if (address_def->opcode() == SpvOpVariable) {
if (address_def->opcode() == spv::Op::OpVariable) {
if (address_def->IsReadOnlyPointer()) {
return true;
}
}
if (address_def->opcode() == SpvOpLoad) {
if (address_def->opcode() == spv::Op::OpLoad) {
const analysis::Type* address_type =
context()->get_type_mgr()->GetType(address_def->type_id());
if (address_type->AsSampledImage() != nullptr) {
@@ -235,12 +244,12 @@ Instruction* Instruction::GetBaseAddress() const {
bool done = false;
while (!done) {
switch (base_inst->opcode()) {
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpPtrAccessChain:
case SpvOpInBoundsPtrAccessChain:
case SpvOpImageTexelPointer:
case SpvOpCopyObject:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
case spv::Op::OpImageTexelPointer:
case spv::Op::OpCopyObject:
// All of these instructions have the base pointer use a base pointer
// in in-operand 0.
base = base_inst->GetSingleWordInOperand(0);
@@ -255,20 +264,20 @@ Instruction* Instruction::GetBaseAddress() const {
}
bool Instruction::IsReadOnlyPointer() const {
if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
if (context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
return IsReadOnlyPointerShaders();
else
return IsReadOnlyPointerKernel();
}
bool Instruction::IsVulkanStorageImage() const {
if (opcode() != SpvOpTypePointer) {
if (opcode() != spv::Op::OpTypePointer) {
return false;
}
uint32_t storage_class =
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
if (storage_class != SpvStorageClassUniformConstant) {
spv::StorageClass storage_class =
spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
if (storage_class != spv::StorageClass::UniformConstant) {
return false;
}
@@ -276,17 +285,18 @@ bool Instruction::IsVulkanStorageImage() const {
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
// Unpack the optional layer of arraying.
if (base_type->opcode() == SpvOpTypeArray ||
base_type->opcode() == SpvOpTypeRuntimeArray) {
if (base_type->opcode() == spv::Op::OpTypeArray ||
base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
base_type = context()->get_def_use_mgr()->GetDef(
base_type->GetSingleWordInOperand(0));
}
if (base_type->opcode() != SpvOpTypeImage) {
if (base_type->opcode() != spv::Op::OpTypeImage) {
return false;
}
if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) ==
spv::Dim::Buffer) {
return false;
}
@@ -296,13 +306,13 @@ bool Instruction::IsVulkanStorageImage() const {
}
bool Instruction::IsVulkanSampledImage() const {
if (opcode() != SpvOpTypePointer) {
if (opcode() != spv::Op::OpTypePointer) {
return false;
}
uint32_t storage_class =
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
if (storage_class != SpvStorageClassUniformConstant) {
spv::StorageClass storage_class =
spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
if (storage_class != spv::StorageClass::UniformConstant) {
return false;
}
@@ -310,17 +320,18 @@ bool Instruction::IsVulkanSampledImage() const {
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
// Unpack the optional layer of arraying.
if (base_type->opcode() == SpvOpTypeArray ||
base_type->opcode() == SpvOpTypeRuntimeArray) {
if (base_type->opcode() == spv::Op::OpTypeArray ||
base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
base_type = context()->get_def_use_mgr()->GetDef(
base_type->GetSingleWordInOperand(0));
}
if (base_type->opcode() != SpvOpTypeImage) {
if (base_type->opcode() != spv::Op::OpTypeImage) {
return false;
}
if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) ==
spv::Dim::Buffer) {
return false;
}
@@ -330,13 +341,13 @@ bool Instruction::IsVulkanSampledImage() const {
}
bool Instruction::IsVulkanStorageTexelBuffer() const {
if (opcode() != SpvOpTypePointer) {
if (opcode() != spv::Op::OpTypePointer) {
return false;
}
uint32_t storage_class =
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
if (storage_class != SpvStorageClassUniformConstant) {
spv::StorageClass storage_class =
spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
if (storage_class != spv::StorageClass::UniformConstant) {
return false;
}
@@ -344,17 +355,18 @@ bool Instruction::IsVulkanStorageTexelBuffer() const {
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
// Unpack the optional layer of arraying.
if (base_type->opcode() == SpvOpTypeArray ||
base_type->opcode() == SpvOpTypeRuntimeArray) {
if (base_type->opcode() == spv::Op::OpTypeArray ||
base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
base_type = context()->get_def_use_mgr()->GetDef(
base_type->GetSingleWordInOperand(0));
}
if (base_type->opcode() != SpvOpTypeImage) {
if (base_type->opcode() != spv::Op::OpTypeImage) {
return false;
}
if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) != SpvDimBuffer) {
if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) !=
spv::Dim::Buffer) {
return false;
}
@@ -366,7 +378,7 @@ bool Instruction::IsVulkanStorageTexelBuffer() const {
bool Instruction::IsVulkanStorageBuffer() const {
// Is there a difference between a "Storage buffer" and a "dynamic storage
// buffer" in SPIR-V and do we care about the difference?
if (opcode() != SpvOpTypePointer) {
if (opcode() != spv::Op::OpTypePointer) {
return false;
}
@@ -374,28 +386,28 @@ bool Instruction::IsVulkanStorageBuffer() const {
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
// Unpack the optional layer of arraying.
if (base_type->opcode() == SpvOpTypeArray ||
base_type->opcode() == SpvOpTypeRuntimeArray) {
if (base_type->opcode() == spv::Op::OpTypeArray ||
base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
base_type = context()->get_def_use_mgr()->GetDef(
base_type->GetSingleWordInOperand(0));
}
if (base_type->opcode() != SpvOpTypeStruct) {
if (base_type->opcode() != spv::Op::OpTypeStruct) {
return false;
}
uint32_t storage_class =
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
if (storage_class == SpvStorageClassUniform) {
spv::StorageClass storage_class =
spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
if (storage_class == spv::StorageClass::Uniform) {
bool is_buffer_block = false;
context()->get_decoration_mgr()->ForEachDecoration(
base_type->result_id(), SpvDecorationBufferBlock,
base_type->result_id(), uint32_t(spv::Decoration::BufferBlock),
[&is_buffer_block](const Instruction&) { is_buffer_block = true; });
return is_buffer_block;
} else if (storage_class == SpvStorageClassStorageBuffer) {
} else if (storage_class == spv::StorageClass::StorageBuffer) {
bool is_block = false;
context()->get_decoration_mgr()->ForEachDecoration(
base_type->result_id(), SpvDecorationBlock,
base_type->result_id(), uint32_t(spv::Decoration::Block),
[&is_block](const Instruction&) { is_block = true; });
return is_block;
}
@@ -403,13 +415,14 @@ bool Instruction::IsVulkanStorageBuffer() const {
}
bool Instruction::IsVulkanStorageBufferVariable() const {
if (opcode() != SpvOpVariable) {
if (opcode() != spv::Op::OpVariable) {
return false;
}
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
if (storage_class == SpvStorageClassStorageBuffer ||
storage_class == SpvStorageClassUniform) {
spv::StorageClass storage_class =
spv::StorageClass(GetSingleWordInOperand(kVariableStorageClassIndex));
if (storage_class == spv::StorageClass::StorageBuffer ||
storage_class == spv::StorageClass::Uniform) {
Instruction* var_type = context()->get_def_use_mgr()->GetDef(type_id());
return var_type != nullptr && var_type->IsVulkanStorageBuffer();
}
@@ -418,13 +431,13 @@ bool Instruction::IsVulkanStorageBufferVariable() const {
}
bool Instruction::IsVulkanUniformBuffer() const {
if (opcode() != SpvOpTypePointer) {
if (opcode() != spv::Op::OpTypePointer) {
return false;
}
uint32_t storage_class =
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
if (storage_class != SpvStorageClassUniform) {
spv::StorageClass storage_class =
spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
if (storage_class != spv::StorageClass::Uniform) {
return false;
}
@@ -432,19 +445,19 @@ bool Instruction::IsVulkanUniformBuffer() const {
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
// Unpack the optional layer of arraying.
if (base_type->opcode() == SpvOpTypeArray ||
base_type->opcode() == SpvOpTypeRuntimeArray) {
if (base_type->opcode() == spv::Op::OpTypeArray ||
base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
base_type = context()->get_def_use_mgr()->GetDef(
base_type->GetSingleWordInOperand(0));
}
if (base_type->opcode() != SpvOpTypeStruct) {
if (base_type->opcode() != spv::Op::OpTypeStruct) {
return false;
}
bool is_block = false;
context()->get_decoration_mgr()->ForEachDecoration(
base_type->result_id(), SpvDecorationBlock,
base_type->result_id(), uint32_t(spv::Decoration::Block),
[&is_block](const Instruction&) { is_block = true; });
return is_block;
}
@@ -455,27 +468,27 @@ bool Instruction::IsReadOnlyPointerShaders() const {
}
Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
if (type_def->opcode() != SpvOpTypePointer) {
if (type_def->opcode() != spv::Op::OpTypePointer) {
return false;
}
uint32_t storage_class =
type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
spv::StorageClass storage_class = spv::StorageClass(
type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex));
switch (storage_class) {
case SpvStorageClassUniformConstant:
case spv::StorageClass::UniformConstant:
if (!type_def->IsVulkanStorageImage() &&
!type_def->IsVulkanStorageTexelBuffer()) {
return true;
}
break;
case SpvStorageClassUniform:
case spv::StorageClass::Uniform:
if (!type_def->IsVulkanStorageBuffer()) {
return true;
}
break;
case SpvStorageClassPushConstant:
case SpvStorageClassInput:
case spv::StorageClass::PushConstant:
case spv::StorageClass::Input:
return true;
default:
break;
@@ -483,7 +496,7 @@ bool Instruction::IsReadOnlyPointerShaders() const {
bool is_nonwritable = false;
context()->get_decoration_mgr()->ForEachDecoration(
result_id(), SpvDecorationNonWritable,
result_id(), uint32_t(spv::Decoration::NonWritable),
[&is_nonwritable](const Instruction&) { is_nonwritable = true; });
return is_nonwritable;
}
@@ -494,14 +507,14 @@ bool Instruction::IsReadOnlyPointerKernel() const {
}
Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
if (type_def->opcode() != SpvOpTypePointer) {
if (type_def->opcode() != spv::Op::OpTypePointer) {
return false;
}
uint32_t storage_class =
type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
spv::StorageClass storage_class = spv::StorageClass(
type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex));
return storage_class == SpvStorageClassUniformConstant;
return storage_class == spv::StorageClass::UniformConstant;
}
void Instruction::UpdateLexicalScope(uint32_t scope) {
@@ -564,13 +577,13 @@ bool Instruction::IsDebugLineInst() const {
bool Instruction::IsLineInst() const { return IsLine() || IsNoLine(); }
bool Instruction::IsLine() const {
if (opcode() == SpvOpLine) return true;
if (opcode() == spv::Op::OpLine) return true;
NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
return ext_opt == NonSemanticShaderDebugInfo100DebugLine;
}
bool Instruction::IsNoLine() const {
if (opcode() == SpvOpNoLine) return true;
if (opcode() == spv::Op::OpNoLine) return true;
NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
return ext_opt == NonSemanticShaderDebugInfo100DebugNoLine;
}
@@ -597,33 +610,35 @@ bool Instruction::IsValidBasePointer() const {
}
Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
if (type->opcode() != SpvOpTypePointer) {
if (type->opcode() != spv::Op::OpTypePointer) {
return false;
}
auto feature_mgr = context()->get_feature_mgr();
if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
if (feature_mgr->HasCapability(spv::Capability::Addresses)) {
// TODO: The rules here could be more restrictive.
return true;
}
if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
if (opcode() == spv::Op::OpVariable ||
opcode() == spv::Op::OpFunctionParameter) {
return true;
}
// With variable pointers, there are more valid base pointer objects.
// Variable pointers implicitly declares Variable pointers storage buffer.
SpvStorageClass storage_class =
static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
storage_class == SpvStorageClassStorageBuffer) ||
(feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
storage_class == SpvStorageClassWorkgroup)) {
spv::StorageClass storage_class =
static_cast<spv::StorageClass>(type->GetSingleWordInOperand(0));
if ((feature_mgr->HasCapability(
spv::Capability::VariablePointersStorageBuffer) &&
storage_class == spv::StorageClass::StorageBuffer) ||
(feature_mgr->HasCapability(spv::Capability::VariablePointers) &&
storage_class == spv::StorageClass::Workgroup)) {
switch (opcode()) {
case SpvOpPhi:
case SpvOpSelect:
case SpvOpFunctionCall:
case SpvOpConstantNull:
case spv::Op::OpPhi:
case spv::Op::OpSelect:
case spv::Op::OpFunctionCall:
case spv::Op::OpConstantNull:
return true;
default:
break;
@@ -641,7 +656,7 @@ bool Instruction::IsValidBasePointer() const {
}
OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
if (opcode() != SpvOpExtInst) {
if (opcode() != spv::Op::OpExtInst) {
return OpenCLDebugInfo100InstructionsMax;
}
@@ -660,7 +675,7 @@ OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
NonSemanticShaderDebugInfo100Instructions Instruction::GetShader100DebugOpcode()
const {
if (opcode() != SpvOpExtInst) {
if (opcode() != spv::Op::OpExtInst) {
return NonSemanticShaderDebugInfo100InstructionsMax;
}
@@ -682,7 +697,7 @@ NonSemanticShaderDebugInfo100Instructions Instruction::GetShader100DebugOpcode()
}
CommonDebugInfoInstructions Instruction::GetCommonDebugOpcode() const {
if (opcode() != SpvOpExtInst) {
if (opcode() != spv::Op::OpExtInst) {
return CommonDebugInfoInstructionsMax;
}
@@ -712,25 +727,25 @@ bool Instruction::IsValidBaseImage() const {
}
Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
return (type->opcode() == SpvOpTypeImage ||
type->opcode() == SpvOpTypeSampledImage);
return (type->opcode() == spv::Op::OpTypeImage ||
type->opcode() == spv::Op::OpTypeSampledImage);
}
bool Instruction::IsOpaqueType() const {
if (opcode() == SpvOpTypeStruct) {
if (opcode() == spv::Op::OpTypeStruct) {
bool is_opaque = false;
ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
is_opaque |= type_inst->IsOpaqueType();
});
return is_opaque;
} else if (opcode() == SpvOpTypeArray) {
} else if (opcode() == spv::Op::OpTypeArray) {
uint32_t sub_type_id = GetSingleWordInOperand(0);
Instruction* sub_type_inst =
context()->get_def_use_mgr()->GetDef(sub_type_id);
return sub_type_inst->IsOpaqueType();
} else {
return opcode() == SpvOpTypeRuntimeArray ||
return opcode() == spv::Op::OpTypeRuntimeArray ||
spvOpcodeIsBaseOpaqueType(opcode());
}
}
@@ -765,22 +780,23 @@ bool Instruction::IsFoldableByFoldScalar() const {
bool Instruction::IsFloatingPointFoldingAllowed() const {
// TODO: Add the rules for kernels. For now it will be pessimistic.
// For now, do not support capabilities introduced by SPV_KHR_float_controls.
if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) ||
context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) ||
if (!context_->get_feature_mgr()->HasCapability(spv::Capability::Shader) ||
context_->get_feature_mgr()->HasCapability(
SpvCapabilityDenormFlushToZero) ||
spv::Capability::DenormPreserve) ||
context_->get_feature_mgr()->HasCapability(
SpvCapabilitySignedZeroInfNanPreserve) ||
spv::Capability::DenormFlushToZero) ||
context_->get_feature_mgr()->HasCapability(
SpvCapabilityRoundingModeRTZ) ||
spv::Capability::SignedZeroInfNanPreserve) ||
context_->get_feature_mgr()->HasCapability(
SpvCapabilityRoundingModeRTE)) {
spv::Capability::RoundingModeRTZ) ||
context_->get_feature_mgr()->HasCapability(
spv::Capability::RoundingModeRTE)) {
return false;
}
bool is_nocontract = false;
context_->get_decoration_mgr()->WhileEachDecoration(
result_id(), SpvDecorationNoContraction,
result_id(), uint32_t(spv::Decoration::NoContraction),
[&is_nocontract](const Instruction&) {
is_nocontract = true;
return false;
@@ -816,101 +832,101 @@ void Instruction::Dump() const {
bool Instruction::IsOpcodeCodeMotionSafe() const {
switch (opcode_) {
case SpvOpNop:
case SpvOpUndef:
case SpvOpLoad:
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpArrayLength:
case SpvOpVectorExtractDynamic:
case SpvOpVectorInsertDynamic:
case SpvOpVectorShuffle:
case SpvOpCompositeConstruct:
case SpvOpCompositeExtract:
case SpvOpCompositeInsert:
case SpvOpCopyObject:
case SpvOpTranspose:
case SpvOpConvertFToU:
case SpvOpConvertFToS:
case SpvOpConvertSToF:
case SpvOpConvertUToF:
case SpvOpUConvert:
case SpvOpSConvert:
case SpvOpFConvert:
case SpvOpQuantizeToF16:
case SpvOpBitcast:
case SpvOpSNegate:
case SpvOpFNegate:
case SpvOpIAdd:
case SpvOpFAdd:
case SpvOpISub:
case SpvOpFSub:
case SpvOpIMul:
case SpvOpFMul:
case SpvOpUDiv:
case SpvOpSDiv:
case SpvOpFDiv:
case SpvOpUMod:
case SpvOpSRem:
case SpvOpSMod:
case SpvOpFRem:
case SpvOpFMod:
case SpvOpVectorTimesScalar:
case SpvOpMatrixTimesScalar:
case SpvOpVectorTimesMatrix:
case SpvOpMatrixTimesVector:
case SpvOpMatrixTimesMatrix:
case SpvOpOuterProduct:
case SpvOpDot:
case SpvOpIAddCarry:
case SpvOpISubBorrow:
case SpvOpUMulExtended:
case SpvOpSMulExtended:
case SpvOpAny:
case SpvOpAll:
case SpvOpIsNan:
case SpvOpIsInf:
case SpvOpLogicalEqual:
case SpvOpLogicalNotEqual:
case SpvOpLogicalOr:
case SpvOpLogicalAnd:
case SpvOpLogicalNot:
case SpvOpSelect:
case SpvOpIEqual:
case SpvOpINotEqual:
case SpvOpUGreaterThan:
case SpvOpSGreaterThan:
case SpvOpUGreaterThanEqual:
case SpvOpSGreaterThanEqual:
case SpvOpULessThan:
case SpvOpSLessThan:
case SpvOpULessThanEqual:
case SpvOpSLessThanEqual:
case SpvOpFOrdEqual:
case SpvOpFUnordEqual:
case SpvOpFOrdNotEqual:
case SpvOpFUnordNotEqual:
case SpvOpFOrdLessThan:
case SpvOpFUnordLessThan:
case SpvOpFOrdGreaterThan:
case SpvOpFUnordGreaterThan:
case SpvOpFOrdLessThanEqual:
case SpvOpFUnordLessThanEqual:
case SpvOpFOrdGreaterThanEqual:
case SpvOpFUnordGreaterThanEqual:
case SpvOpShiftRightLogical:
case SpvOpShiftRightArithmetic:
case SpvOpShiftLeftLogical:
case SpvOpBitwiseOr:
case SpvOpBitwiseXor:
case SpvOpBitwiseAnd:
case SpvOpNot:
case SpvOpBitFieldInsert:
case SpvOpBitFieldSExtract:
case SpvOpBitFieldUExtract:
case SpvOpBitReverse:
case SpvOpBitCount:
case SpvOpSizeOf:
case spv::Op::OpNop:
case spv::Op::OpUndef:
case spv::Op::OpLoad:
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
case spv::Op::OpArrayLength:
case spv::Op::OpVectorExtractDynamic:
case spv::Op::OpVectorInsertDynamic:
case spv::Op::OpVectorShuffle:
case spv::Op::OpCompositeConstruct:
case spv::Op::OpCompositeExtract:
case spv::Op::OpCompositeInsert:
case spv::Op::OpCopyObject:
case spv::Op::OpTranspose:
case spv::Op::OpConvertFToU:
case spv::Op::OpConvertFToS:
case spv::Op::OpConvertSToF:
case spv::Op::OpConvertUToF:
case spv::Op::OpUConvert:
case spv::Op::OpSConvert:
case spv::Op::OpFConvert:
case spv::Op::OpQuantizeToF16:
case spv::Op::OpBitcast:
case spv::Op::OpSNegate:
case spv::Op::OpFNegate:
case spv::Op::OpIAdd:
case spv::Op::OpFAdd:
case spv::Op::OpISub:
case spv::Op::OpFSub:
case spv::Op::OpIMul:
case spv::Op::OpFMul:
case spv::Op::OpUDiv:
case spv::Op::OpSDiv:
case spv::Op::OpFDiv:
case spv::Op::OpUMod:
case spv::Op::OpSRem:
case spv::Op::OpSMod:
case spv::Op::OpFRem:
case spv::Op::OpFMod:
case spv::Op::OpVectorTimesScalar:
case spv::Op::OpMatrixTimesScalar:
case spv::Op::OpVectorTimesMatrix:
case spv::Op::OpMatrixTimesVector:
case spv::Op::OpMatrixTimesMatrix:
case spv::Op::OpOuterProduct:
case spv::Op::OpDot:
case spv::Op::OpIAddCarry:
case spv::Op::OpISubBorrow:
case spv::Op::OpUMulExtended:
case spv::Op::OpSMulExtended:
case spv::Op::OpAny:
case spv::Op::OpAll:
case spv::Op::OpIsNan:
case spv::Op::OpIsInf:
case spv::Op::OpLogicalEqual:
case spv::Op::OpLogicalNotEqual:
case spv::Op::OpLogicalOr:
case spv::Op::OpLogicalAnd:
case spv::Op::OpLogicalNot:
case spv::Op::OpSelect:
case spv::Op::OpIEqual:
case spv::Op::OpINotEqual:
case spv::Op::OpUGreaterThan:
case spv::Op::OpSGreaterThan:
case spv::Op::OpUGreaterThanEqual:
case spv::Op::OpSGreaterThanEqual:
case spv::Op::OpULessThan:
case spv::Op::OpSLessThan:
case spv::Op::OpULessThanEqual:
case spv::Op::OpSLessThanEqual:
case spv::Op::OpFOrdEqual:
case spv::Op::OpFUnordEqual:
case spv::Op::OpFOrdNotEqual:
case spv::Op::OpFUnordNotEqual:
case spv::Op::OpFOrdLessThan:
case spv::Op::OpFUnordLessThan:
case spv::Op::OpFOrdGreaterThan:
case spv::Op::OpFUnordGreaterThan:
case spv::Op::OpFOrdLessThanEqual:
case spv::Op::OpFUnordLessThanEqual:
case spv::Op::OpFOrdGreaterThanEqual:
case spv::Op::OpFUnordGreaterThanEqual:
case spv::Op::OpShiftRightLogical:
case spv::Op::OpShiftRightArithmetic:
case spv::Op::OpShiftLeftLogical:
case spv::Op::OpBitwiseOr:
case spv::Op::OpBitwiseXor:
case spv::Op::OpBitwiseAnd:
case spv::Op::OpNot:
case spv::Op::OpBitFieldInsert:
case spv::Op::OpBitFieldSExtract:
case spv::Op::OpBitFieldUExtract:
case spv::Op::OpBitReverse:
case spv::Op::OpBitCount:
case spv::Op::OpSizeOf:
return true;
default:
return false;
@@ -922,7 +938,7 @@ bool Instruction::IsScalarizable() const {
return true;
}
if (opcode() == SpvOpExtInst) {
if (opcode() == spv::Op::OpExtInst) {
uint32_t instSetId =
context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
@@ -997,16 +1013,16 @@ bool Instruction::IsOpcodeSafeToDelete() const {
}
switch (opcode()) {
case SpvOpDPdx:
case SpvOpDPdy:
case SpvOpFwidth:
case SpvOpDPdxFine:
case SpvOpDPdyFine:
case SpvOpFwidthFine:
case SpvOpDPdxCoarse:
case SpvOpDPdyCoarse:
case SpvOpFwidthCoarse:
case SpvOpImageQueryLod:
case spv::Op::OpDPdx:
case spv::Op::OpDPdy:
case spv::Op::OpFwidth:
case spv::Op::OpDPdxFine:
case spv::Op::OpDPdyFine:
case spv::Op::OpFwidthFine:
case spv::Op::OpDPdxCoarse:
case spv::Op::OpDPdyCoarse:
case spv::Op::OpFwidthCoarse:
case spv::Op::OpImageQueryLod:
return true;
default:
return false;
@@ -1015,7 +1031,7 @@ bool Instruction::IsOpcodeSafeToDelete() const {
bool Instruction::IsNonSemanticInstruction() const {
if (!HasResultId()) return false;
if (opcode() != SpvOpExtInst) return false;
if (opcode() != spv::Op::OpExtInst) return false;
auto import_inst =
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(0));
@@ -1035,7 +1051,7 @@ void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
num_words = kDebugScopeNumWordsWithoutInlinedAt;
}
std::vector<uint32_t> operands = {
(num_words << 16) | static_cast<uint16_t>(SpvOpExtInst),
(num_words << 16) | static_cast<uint16_t>(spv::Op::OpExtInst),
type_id,
result_id,
ext_set,

View File

@@ -36,8 +36,8 @@
#include "source/util/string_utils.h"
#include "spirv-tools/libspirv.h"
const uint32_t kNoDebugScope = 0;
const uint32_t kNoInlinedAt = 0;
constexpr uint32_t kNoDebugScope = 0;
constexpr uint32_t kNoInlinedAt = 0;
namespace spvtools {
namespace opt {
@@ -190,7 +190,7 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
Instruction()
: utils::IntrusiveNodeBase<Instruction>(),
context_(nullptr),
opcode_(SpvOpNop),
opcode_(spv::Op::OpNop),
has_type_id_(false),
has_result_id_(false),
unique_id_(0),
@@ -200,7 +200,7 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
Instruction(IRContext*);
// Creates an instruction with the given opcode |op| and no additional logical
// operands.
Instruction(IRContext*, SpvOp);
Instruction(IRContext*, spv::Op);
// Creates an instruction using the given spv_parsed_instruction_t |inst|. All
// the data inside |inst| will be copied and owned in this instance. And keep
// record of line-related debug instructions |dbg_line| ahead of this
@@ -213,7 +213,7 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
// Creates an instruction with the given opcode |op|, type id: |ty_id|,
// result id: |res_id| and input operands: |in_operands|.
Instruction(IRContext* c, SpvOp op, uint32_t ty_id, uint32_t res_id,
Instruction(IRContext* c, spv::Op op, uint32_t ty_id, uint32_t res_id,
const OperandList& in_operands);
// TODO: I will want to remove these, but will first have to remove the use of
@@ -235,12 +235,12 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
IRContext* context() const { return context_; }
SpvOp opcode() const { return opcode_; }
spv::Op opcode() const { return opcode_; }
// Sets the opcode of this instruction to a specific opcode. Note this may
// invalidate the instruction.
// TODO(qining): Remove this function when instruction building and insertion
// is well implemented.
void SetOpcode(SpvOp op) { opcode_ = op; }
void SetOpcode(spv::Op op) { opcode_ = op; }
uint32_t type_id() const {
return has_type_id_ ? GetSingleWordOperand(0) : 0;
}
@@ -625,7 +625,7 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
bool IsValidBaseImage() const;
IRContext* context_; // IR Context
SpvOp opcode_; // Opcode
spv::Op opcode_; // Opcode
bool has_type_id_; // True if the instruction has a type id
bool has_result_id_; // True if the instruction has a result id
uint32_t unique_id_; // Unique instruction id
@@ -732,12 +732,12 @@ inline void Instruction::SetResultType(uint32_t ty_id) {
}
inline bool Instruction::IsNop() const {
return opcode_ == SpvOpNop && !has_type_id_ && !has_result_id_ &&
return opcode_ == spv::Op::OpNop && !has_type_id_ && !has_result_id_ &&
operands_.empty();
}
inline void Instruction::ToNop() {
opcode_ = SpvOpNop;
opcode_ = spv::Op::OpNop;
has_type_id_ = false;
has_result_id_ = false;
operands_.clear();
@@ -879,12 +879,12 @@ inline void Instruction::ForEachInOperand(
inline bool Instruction::HasLabels() const {
switch (opcode_) {
case SpvOpSelectionMerge:
case SpvOpBranch:
case SpvOpLoopMerge:
case SpvOpBranchConditional:
case SpvOpSwitch:
case SpvOpPhi:
case spv::Op::OpSelectionMerge:
case spv::Op::OpBranch:
case spv::Op::OpLoopMerge:
case spv::Op::OpBranchConditional:
case spv::Op::OpSwitch:
case spv::Op::OpPhi:
return true;
break;
default:

View File

@@ -19,20 +19,15 @@
#include "source/cfa.h"
#include "source/spirv_constant.h"
namespace {
// Common Parameter Positions
static const int kInstCommonParamInstIdx = 0;
static const int kInstCommonParamCnt = 1;
// Indices of operands in SPIR-V instructions
static const int kEntryPointExecutionModelInIdx = 0;
static const int kEntryPointFunctionIdInIdx = 1;
} // anonymous namespace
namespace spvtools {
namespace opt {
namespace {
// Common Parameter Positions
constexpr int kInstCommonParamInstIdx = 0;
constexpr int kInstCommonParamCnt = 1;
// Indices of operands in SPIR-V instructions
constexpr int kEntryPointFunctionIdInIdx = 1;
} // namespace
void InstrumentPass::MovePreludeCode(
BasicBlock::iterator ref_inst_itr,
@@ -83,7 +78,7 @@ void InstrumentPass::MovePostludeCode(
std::unique_ptr<Instruction> InstrumentPass::NewLabel(uint32_t label_id) {
std::unique_ptr<Instruction> newLabel(
new Instruction(context(), SpvOpLabel, 0, label_id, {}));
new Instruction(context(), spv::Op::OpLabel, 0, label_id, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*newLabel);
return newLabel;
}
@@ -91,7 +86,7 @@ std::unique_ptr<Instruction> InstrumentPass::NewLabel(uint32_t label_id) {
std::unique_ptr<Instruction> InstrumentPass::NewName(
uint32_t id, const std::string& name_str) {
std::unique_ptr<Instruction> new_name(new Instruction(
context(), SpvOpName, 0, 0,
context(), spv::Op::OpName, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {id}},
{SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}));
@@ -124,7 +119,7 @@ std::unique_ptr<Instruction> InstrumentPass::NewGlobalName(
std::unique_ptr<Instruction> InstrumentPass::NewMemberName(
uint32_t id, uint32_t member_index, const std::string& name_str) {
std::unique_ptr<Instruction> new_name(new Instruction(
context(), SpvOpMemberName, 0, 0,
context(), spv::Op::OpMemberName, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {id}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}},
@@ -145,10 +140,10 @@ uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id,
analysis::Type* val_32b_reg_ty = type_mgr->GetRegisteredType(&val_32b_ty);
uint32_t val_32b_reg_ty_id = type_mgr->GetId(val_32b_reg_ty);
if (is_signed)
return builder->AddUnaryOp(val_32b_reg_ty_id, SpvOpSConvert, val_id)
return builder->AddUnaryOp(val_32b_reg_ty_id, spv::Op::OpSConvert, val_id)
->result_id();
else
return builder->AddUnaryOp(val_32b_reg_ty_id, SpvOpUConvert, val_id)
return builder->AddUnaryOp(val_32b_reg_ty_id, spv::Op::OpUConvert, val_id)
->result_id();
}
@@ -161,7 +156,7 @@ uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id,
uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_32b_id)->type_id();
analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
if (!val_ty->IsSigned()) return val_32b_id;
return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_32b_id)
return builder->AddUnaryOp(GetUintId(), spv::Op::OpBitcast, val_32b_id)
->result_id();
}
@@ -173,15 +168,16 @@ void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
uint32_t val_id = GenUintCastCode(field_value_id, builder);
// Store value
Instruction* data_idx_inst =
builder->AddBinaryOp(GetUintId(), SpvOpIAdd, base_offset_id,
builder->AddBinaryOp(GetUintId(), spv::Op::OpIAdd, base_offset_id,
builder->GetUintConstantId(field_offset));
uint32_t buf_id = GetOutputBufferId();
uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
Instruction* achain_inst =
builder->AddTernaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
builder->AddTernaryOp(buf_uint_ptr_id, spv::Op::OpAccessChain, buf_id,
builder->GetUintConstantId(kDebugOutputDataOffset),
data_idx_inst->result_id());
(void)builder->AddBinaryOp(0, SpvOpStore, achain_inst->result_id(), val_id);
(void)builder->AddBinaryOp(0, spv::Op::OpStore, achain_inst->result_id(),
val_id);
}
void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz,
@@ -207,7 +203,7 @@ void InstrumentPass::GenFragCoordEltDebugOutputCode(
uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element,
InstructionBuilder* builder) {
Instruction* element_val_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, uint_frag_coord_id, element);
GetUintId(), spv::Op::OpCompositeExtract, uint_frag_coord_id, element);
GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element,
element_val_inst->result_id(), builder);
}
@@ -216,7 +212,8 @@ uint32_t InstrumentPass::GenVarLoad(uint32_t var_id,
InstructionBuilder* builder) {
Instruction* var_inst = get_def_use_mgr()->GetDef(var_id);
uint32_t type_id = GetPointeeTypeId(var_inst);
Instruction* load_inst = builder->AddUnaryOp(type_id, SpvOpLoad, var_id);
Instruction* load_inst =
builder->AddUnaryOp(type_id, spv::Op::OpLoad, var_id);
return load_inst->result_id();
}
@@ -233,31 +230,31 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
uint32_t base_offset_id,
InstructionBuilder* builder) {
// TODO(greg-lunarg): Add support for all stages
switch (stage_idx) {
case SpvExecutionModelVertex: {
switch (spv::ExecutionModel(stage_idx)) {
case spv::ExecutionModel::Vertex: {
// Load and store VertexId and InstanceId
GenBuiltinOutputCode(
context()->GetBuiltinInputVarId(SpvBuiltInVertexIndex),
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::VertexIndex)),
kInstVertOutVertexIndex, base_offset_id, builder);
GenBuiltinOutputCode(
context()->GetBuiltinInputVarId(SpvBuiltInInstanceIndex),
kInstVertOutInstanceIndex, base_offset_id, builder);
GenBuiltinOutputCode(context()->GetBuiltinInputVarId(
uint32_t(spv::BuiltIn::InstanceIndex)),
kInstVertOutInstanceIndex, base_offset_id, builder);
} break;
case SpvExecutionModelGLCompute:
case SpvExecutionModelTaskNV:
case SpvExecutionModelMeshNV:
case SpvExecutionModelTaskEXT:
case SpvExecutionModelMeshEXT: {
case spv::ExecutionModel::GLCompute:
case spv::ExecutionModel::TaskNV:
case spv::ExecutionModel::MeshNV:
case spv::ExecutionModel::TaskEXT:
case spv::ExecutionModel::MeshEXT: {
// Load and store GlobalInvocationId.
uint32_t load_id = GenVarLoad(
context()->GetBuiltinInputVarId(SpvBuiltInGlobalInvocationId),
builder);
uint32_t load_id = GenVarLoad(context()->GetBuiltinInputVarId(uint32_t(
spv::BuiltIn::GlobalInvocationId)),
builder);
Instruction* x_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, load_id, 0);
GetUintId(), spv::Op::OpCompositeExtract, load_id, 0);
Instruction* y_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, load_id, 1);
GetUintId(), spv::Op::OpCompositeExtract, load_id, 1);
Instruction* z_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, load_id, 2);
GetUintId(), spv::Op::OpCompositeExtract, load_id, 2);
GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX,
x_inst->result_id(), builder);
GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY,
@@ -265,69 +262,71 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ,
z_inst->result_id(), builder);
} break;
case SpvExecutionModelGeometry: {
case spv::ExecutionModel::Geometry: {
// Load and store PrimitiveId and InvocationId.
GenBuiltinOutputCode(
context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
kInstGeomOutPrimitiveId, base_offset_id, builder);
GenBuiltinOutputCode(
context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)),
kInstGeomOutInvocationId, base_offset_id, builder);
} break;
case SpvExecutionModelTessellationControl: {
case spv::ExecutionModel::TessellationControl: {
// Load and store InvocationId and PrimitiveId
GenBuiltinOutputCode(
context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)),
kInstTessCtlOutInvocationId, base_offset_id, builder);
GenBuiltinOutputCode(
context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
kInstTessCtlOutPrimitiveId, base_offset_id, builder);
} break;
case SpvExecutionModelTessellationEvaluation: {
case spv::ExecutionModel::TessellationEvaluation: {
// Load and store PrimitiveId and TessCoord.uv
GenBuiltinOutputCode(
context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
kInstTessEvalOutPrimitiveId, base_offset_id, builder);
uint32_t load_id = GenVarLoad(
context()->GetBuiltinInputVarId(SpvBuiltInTessCoord), builder);
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::TessCoord)),
builder);
Instruction* uvec3_cast_inst =
builder->AddUnaryOp(GetVec3UintId(), SpvOpBitcast, load_id);
builder->AddUnaryOp(GetVec3UintId(), spv::Op::OpBitcast, load_id);
uint32_t uvec3_cast_id = uvec3_cast_inst->result_id();
Instruction* u_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 0);
GetUintId(), spv::Op::OpCompositeExtract, uvec3_cast_id, 0);
Instruction* v_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 1);
GetUintId(), spv::Op::OpCompositeExtract, uvec3_cast_id, 1);
GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU,
u_inst->result_id(), builder);
GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV,
v_inst->result_id(), builder);
} break;
case SpvExecutionModelFragment: {
case spv::ExecutionModel::Fragment: {
// Load FragCoord and convert to Uint
Instruction* frag_coord_inst = builder->AddUnaryOp(
GetVec4FloatId(), SpvOpLoad,
context()->GetBuiltinInputVarId(SpvBuiltInFragCoord));
GetVec4FloatId(), spv::Op::OpLoad,
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::FragCoord)));
Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
GetVec4UintId(), SpvOpBitcast, frag_coord_inst->result_id());
GetVec4UintId(), spv::Op::OpBitcast, frag_coord_inst->result_id());
for (uint32_t u = 0; u < 2u; ++u)
GenFragCoordEltDebugOutputCode(
base_offset_id, uint_frag_coord_inst->result_id(), u, builder);
} break;
case SpvExecutionModelRayGenerationNV:
case SpvExecutionModelIntersectionNV:
case SpvExecutionModelAnyHitNV:
case SpvExecutionModelClosestHitNV:
case SpvExecutionModelMissNV:
case SpvExecutionModelCallableNV: {
case spv::ExecutionModel::RayGenerationNV:
case spv::ExecutionModel::IntersectionNV:
case spv::ExecutionModel::AnyHitNV:
case spv::ExecutionModel::ClosestHitNV:
case spv::ExecutionModel::MissNV:
case spv::ExecutionModel::CallableNV: {
// Load and store LaunchIdNV.
uint32_t launch_id = GenVarLoad(
context()->GetBuiltinInputVarId(SpvBuiltInLaunchIdNV), builder);
context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::LaunchIdNV)),
builder);
Instruction* x_launch_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, launch_id, 0);
GetUintId(), spv::Op::OpCompositeExtract, launch_id, 0);
Instruction* y_launch_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, launch_id, 1);
GetUintId(), spv::Op::OpCompositeExtract, launch_id, 1);
Instruction* z_launch_inst = builder->AddIdLiteralOp(
GetUintId(), SpvOpCompositeExtract, launch_id, 2);
GetUintId(), spv::Op::OpCompositeExtract, launch_id, 2);
GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX,
x_launch_inst->result_id(), builder);
GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY,
@@ -349,7 +348,7 @@ void InstrumentPass::GenDebugStreamWrite(
std::vector<uint32_t> args = {output_func_id,
builder->GetUintConstantId(instruction_idx)};
(void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
(void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, args);
(void)builder->AddNaryOp(GetVoidId(), spv::Op::OpFunctionCall, args);
}
bool InstrumentPass::AllConstant(const std::vector<uint32_t>& ids) {
@@ -385,13 +384,15 @@ uint32_t InstrumentPass::GenDebugDirectRead(
builder.SetInsertPoint(insert_before);
}
uint32_t res_id =
builder.AddNaryOp(GetUintId(), SpvOpFunctionCall, args)->result_id();
builder.AddNaryOp(GetUintId(), spv::Op::OpFunctionCall, args)
->result_id();
if (insert_in_first_block) call2id_[args] = res_id;
return res_id;
}
bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const {
return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
return inst->opcode() == spv::Op::OpSampledImage ||
inst->opcode() == spv::Op::OpImage;
}
void InstrumentPass::CloneSameBlockOps(
@@ -457,7 +458,7 @@ void InstrumentPass::UpdateSucceedingPhis(
uint32_t InstrumentPass::GetOutputBufferPtrId() {
if (output_buffer_ptr_id_ == 0) {
output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
GetUintId(), SpvStorageClassStorageBuffer);
GetUintId(), spv::StorageClass::StorageBuffer);
}
return output_buffer_ptr_id_;
}
@@ -470,7 +471,7 @@ uint32_t InstrumentPass::GetInputBufferTypeId() {
uint32_t InstrumentPass::GetInputBufferPtrId() {
if (input_buffer_ptr_id_ == 0) {
input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
GetInputBufferTypeId(), SpvStorageClassStorageBuffer);
GetInputBufferTypeId(), spv::StorageClass::StorageBuffer);
}
return input_buffer_ptr_id_;
}
@@ -519,8 +520,8 @@ analysis::Type* InstrumentPass::GetUintXRuntimeArrayType(
// invalidated after this pass.
assert(context()->get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 &&
"used RuntimeArray type returned");
deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride,
width / 8u);
deco_mgr->AddDecorationVal(
uint_arr_ty_id, uint32_t(spv::Decoration::ArrayStride), width / 8u);
}
return *rarr_ty;
}
@@ -548,7 +549,7 @@ uint32_t InstrumentPass::GetOutputBufferId() {
analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
analysis::Integer uint_ty(32, false);
analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
analysis::Struct buf_ty({reg_uint_ty, reg_uint_rarr_ty});
analysis::Struct buf_ty({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty});
analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
// By the Vulkan spec, a pre-existing struct containing a RuntimeArray
@@ -559,26 +560,30 @@ uint32_t InstrumentPass::GetOutputBufferId() {
// invalidated after this pass.
assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
"used struct type returned");
deco_mgr->AddDecoration(obufTyId, SpvDecorationBlock);
deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block));
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset,
uint32_t(spv::Decoration::Offset), 0);
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
SpvDecorationOffset, 0);
uint32_t(spv::Decoration::Offset), 4);
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
SpvDecorationOffset, 4);
uint32_t(spv::Decoration::Offset), 8);
uint32_t obufTyPtrId_ =
type_mgr->FindPointerToType(obufTyId, SpvStorageClassStorageBuffer);
type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer);
output_buffer_id_ = TakeNextId();
std::unique_ptr<Instruction> newVarOp(new Instruction(
context(), SpvOpVariable, obufTyPtrId_, output_buffer_id_,
context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_,
{{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
{SpvStorageClassStorageBuffer}}}));
{uint32_t(spv::StorageClass::StorageBuffer)}}}));
context()->AddGlobalValue(std::move(newVarOp));
context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "written_count"));
context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "data"));
context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags"));
context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count"));
context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data"));
context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationDescriptorSet,
desc_set_);
deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationBinding,
deco_mgr->AddDecorationVal(
output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
deco_mgr->AddDecorationVal(output_buffer_id_,
uint32_t(spv::Decoration::Binding),
GetOutputBufferBinding());
AddStorageBufferExt();
if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
@@ -610,22 +615,24 @@ uint32_t InstrumentPass::GetInputBufferId() {
// invalidated after this pass.
assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 &&
"used struct type returned");
deco_mgr->AddDecoration(ibufTyId, SpvDecorationBlock);
deco_mgr->AddMemberDecoration(ibufTyId, 0, SpvDecorationOffset, 0);
deco_mgr->AddDecoration(ibufTyId, uint32_t(spv::Decoration::Block));
deco_mgr->AddMemberDecoration(ibufTyId, 0,
uint32_t(spv::Decoration::Offset), 0);
uint32_t ibufTyPtrId_ =
type_mgr->FindPointerToType(ibufTyId, SpvStorageClassStorageBuffer);
type_mgr->FindPointerToType(ibufTyId, spv::StorageClass::StorageBuffer);
input_buffer_id_ = TakeNextId();
std::unique_ptr<Instruction> newVarOp(new Instruction(
context(), SpvOpVariable, ibufTyPtrId_, input_buffer_id_,
context(), spv::Op::OpVariable, ibufTyPtrId_, input_buffer_id_,
{{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
{SpvStorageClassStorageBuffer}}}));
{uint32_t(spv::StorageClass::StorageBuffer)}}}));
context()->AddGlobalValue(std::move(newVarOp));
context()->AddDebug2Inst(NewGlobalName(ibufTyId, "InputBuffer"));
context()->AddDebug2Inst(NewMemberName(ibufTyId, 0, "data"));
context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer"));
deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationDescriptorSet,
desc_set_);
deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationBinding,
deco_mgr->AddDecorationVal(
input_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
deco_mgr->AddDecorationVal(input_buffer_id_,
uint32_t(spv::Decoration::Binding),
GetInputBufferBinding());
AddStorageBufferExt();
if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
@@ -746,10 +753,10 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
std::unique_ptr<Instruction> func_inst(
new Instruction(get_module()->context(), SpvOpFunction, GetVoidId(),
param2output_func_id_[param_cnt],
new Instruction(get_module()->context(), spv::Op::OpFunction,
GetVoidId(), param2output_func_id_[param_cnt],
{{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
{SpvFunctionControlMaskNone}},
{uint32_t(spv::FunctionControlMask::MaskNone)}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
{type_mgr->GetTypeInstruction(reg_func_ty)}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
@@ -761,7 +768,7 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
uint32_t pid = TakeNextId();
param_vec.push_back(pid);
std::unique_ptr<Instruction> param_inst(
new Instruction(get_module()->context(), SpvOpFunctionParameter,
new Instruction(get_module()->context(), spv::Op::OpFunctionParameter,
GetUintId(), pid, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
output_func->AddParameter(std::move(param_inst));
@@ -780,37 +787,39 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
uint32_t buf_id = GetOutputBufferId();
uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
Instruction* obuf_curr_sz_ac_inst =
builder.AddBinaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
builder.AddBinaryOp(buf_uint_ptr_id, spv::Op::OpAccessChain, buf_id,
builder.GetUintConstantId(kDebugOutputSizeOffset));
// Fetch the current debug buffer written size atomically, adding the
// size of the record to be written.
uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
uint32_t mask_none_id = builder.GetUintConstantId(SpvMemoryAccessMaskNone);
uint32_t scope_invok_id = builder.GetUintConstantId(SpvScopeInvocation);
uint32_t mask_none_id =
builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone));
uint32_t scope_invok_id =
builder.GetUintConstantId(uint32_t(spv::Scope::Invocation));
Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
GetUintId(), SpvOpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
scope_invok_id, mask_none_id, obuf_record_sz_id);
uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
// Compute new written size
Instruction* obuf_new_sz_inst =
builder.AddBinaryOp(GetUintId(), SpvOpIAdd, obuf_curr_sz_id,
builder.AddBinaryOp(GetUintId(), spv::Op::OpIAdd, obuf_curr_sz_id,
builder.GetUintConstantId(obuf_record_sz));
// Fetch the data bound
Instruction* obuf_bnd_inst =
builder.AddIdLiteralOp(GetUintId(), SpvOpArrayLength,
builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength,
GetOutputBufferId(), kDebugOutputDataOffset);
// Test that new written size is less than or equal to debug output
// data bound
Instruction* obuf_safe_inst = builder.AddBinaryOp(
GetBoolId(), SpvOpULessThanEqual, obuf_new_sz_inst->result_id(),
GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(),
obuf_bnd_inst->result_id());
uint32_t merge_blk_id = TakeNextId();
uint32_t write_blk_id = TakeNextId();
std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
(void)builder.AddConditionalBranch(obuf_safe_inst->result_id(),
write_blk_id, merge_blk_id, merge_blk_id,
SpvSelectionControlMaskNone);
(void)builder.AddConditionalBranch(
obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id,
uint32_t(spv::SelectionControlMask::MaskNone));
// Close safety test block and gen write block
output_func->AddBasicBlock(std::move(new_blk_ptr));
new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
@@ -830,10 +839,10 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
builder.SetInsertPoint(&*new_blk_ptr);
// Close merge block and function and add function to module
(void)builder.AddNullaryOp(0, SpvOpReturn);
(void)builder.AddNullaryOp(0, spv::Op::OpReturn);
output_func->AddBasicBlock(std::move(new_blk_ptr));
std::unique_ptr<Instruction> func_end_inst(
new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
std::unique_ptr<Instruction> func_end_inst(new Instruction(
get_module()->context(), spv::Op::OpFunctionEnd, 0, 0, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
output_func->SetFunctionEnd(std::move(func_end_inst));
context()->AddFunction(std::move(output_func));
@@ -860,9 +869,9 @@ uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
analysis::Function func_ty(type_mgr->GetType(ibuf_type_id), param_types);
analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
std::unique_ptr<Instruction> func_inst(new Instruction(
get_module()->context(), SpvOpFunction, ibuf_type_id, func_id,
get_module()->context(), spv::Op::OpFunction, ibuf_type_id, func_id,
{{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
{SpvFunctionControlMaskNone}},
{uint32_t(spv::FunctionControlMask::MaskNone)}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
{type_mgr->GetTypeInstruction(reg_func_ty)}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
@@ -873,8 +882,9 @@ uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
for (uint32_t c = 0; c < param_cnt; ++c) {
uint32_t pid = TakeNextId();
param_vec.push_back(pid);
std::unique_ptr<Instruction> param_inst(new Instruction(
get_module()->context(), SpvOpFunctionParameter, GetUintId(), pid, {}));
std::unique_ptr<Instruction> param_inst(
new Instruction(get_module()->context(), spv::Op::OpFunctionParameter,
GetUintId(), pid, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
input_func->AddParameter(std::move(param_inst));
}
@@ -899,27 +909,27 @@ uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
} else {
if (ibuf_type_id != GetUintId()) {
Instruction* ucvt_inst =
builder.AddUnaryOp(GetUintId(), SpvOpUConvert, last_value_id);
builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, last_value_id);
last_value_id = ucvt_inst->result_id();
}
Instruction* offset_inst = builder.AddBinaryOp(
GetUintId(), SpvOpIAdd, last_value_id, param_vec[p]);
GetUintId(), spv::Op::OpIAdd, last_value_id, param_vec[p]);
offset_id = offset_inst->result_id();
}
Instruction* ac_inst = builder.AddTernaryOp(
buf_ptr_id, SpvOpAccessChain, buf_id,
buf_ptr_id, spv::Op::OpAccessChain, buf_id,
builder.GetUintConstantId(kDebugInputDataOffset), offset_id);
Instruction* load_inst =
builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, ac_inst->result_id());
builder.AddUnaryOp(ibuf_type_id, spv::Op::OpLoad, ac_inst->result_id());
last_value_id = load_inst->result_id();
}
(void)builder.AddInstruction(MakeUnique<Instruction>(
context(), SpvOpReturnValue, 0, 0,
context(), spv::Op::OpReturnValue, 0, 0,
std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {last_value_id}}}));
// Close block and function and add function to module
input_func->AddBasicBlock(std::move(new_blk_ptr));
std::unique_ptr<Instruction> func_end_inst(
new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
std::unique_ptr<Instruction> func_end_inst(new Instruction(
get_module()->context(), spv::Op::OpFunctionEnd, 0, 0, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
input_func->SetFunctionEnd(std::move(func_end_inst));
context()->AddFunction(std::move(input_func));
@@ -970,7 +980,7 @@ bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx,
// block. This will allow function calls to be inserted into the first
// block without interfering with the instrumentation algorithm.
if (opt_direct_reads_ && !first_block_split) {
if (ii->opcode() != SpvOpVariable) {
if (ii->opcode() != spv::Op::OpVariable) {
SplitBlock(ii, bi, &new_blks);
first_block_split = true;
}
@@ -1001,7 +1011,9 @@ bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx,
// Restart instrumenting at beginning of last new block,
// but skip over any new phi or copy instruction.
ii = bi->begin();
if (ii->opcode() == SpvOpPhi || ii->opcode() == SpvOpCopyObject) ++ii;
if (ii->opcode() == spv::Op::OpPhi ||
ii->opcode() == spv::Op::OpCopyObject)
++ii;
new_blks.clear();
}
}
@@ -1039,35 +1051,24 @@ bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
// one model per module. In such cases we will need
// to clone any functions which are in the call trees of entrypoints
// with differing execution models.
uint32_t ecnt = 0;
uint32_t stage = SpvExecutionModelMax;
for (auto& e : get_module()->entry_points()) {
if (ecnt == 0)
stage = e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx);
else if (e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) !=
stage) {
if (consumer()) {
std::string message = "Mixed stage shader module not supported";
consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
}
return false;
}
++ecnt;
}
spv::ExecutionModel stage = context()->GetStage();
// Check for supported stages
if (stage != SpvExecutionModelVertex && stage != SpvExecutionModelFragment &&
stage != SpvExecutionModelGeometry &&
stage != SpvExecutionModelGLCompute &&
stage != SpvExecutionModelTessellationControl &&
stage != SpvExecutionModelTessellationEvaluation &&
stage != SpvExecutionModelTaskNV && stage != SpvExecutionModelMeshNV &&
stage != SpvExecutionModelRayGenerationNV &&
stage != SpvExecutionModelIntersectionNV &&
stage != SpvExecutionModelAnyHitNV &&
stage != SpvExecutionModelClosestHitNV &&
stage != SpvExecutionModelMissNV &&
stage != SpvExecutionModelCallableNV &&
stage != SpvExecutionModelTaskEXT && stage != SpvExecutionModelMeshEXT) {
if (stage != spv::ExecutionModel::Vertex &&
stage != spv::ExecutionModel::Fragment &&
stage != spv::ExecutionModel::Geometry &&
stage != spv::ExecutionModel::GLCompute &&
stage != spv::ExecutionModel::TessellationControl &&
stage != spv::ExecutionModel::TessellationEvaluation &&
stage != spv::ExecutionModel::TaskNV &&
stage != spv::ExecutionModel::MeshNV &&
stage != spv::ExecutionModel::RayGenerationNV &&
stage != spv::ExecutionModel::IntersectionNV &&
stage != spv::ExecutionModel::AnyHitNV &&
stage != spv::ExecutionModel::ClosestHitNV &&
stage != spv::ExecutionModel::MissNV &&
stage != spv::ExecutionModel::CallableNV &&
stage != spv::ExecutionModel::TaskEXT &&
stage != spv::ExecutionModel::MeshEXT) {
if (consumer()) {
std::string message = "Stage not supported by instrumentation";
consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
@@ -1079,7 +1080,7 @@ bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
for (auto& e : get_module()->entry_points()) {
roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
}
bool modified = InstProcessCallTreeFromRoots(pfn, &roots, stage);
bool modified = InstProcessCallTreeFromRoots(pfn, &roots, uint32_t(stage));
return modified;
}

View File

@@ -55,13 +55,14 @@
namespace spvtools {
namespace opt {
namespace {
// Validation Ids
// These are used to identify the general validation being done and map to
// its output buffers.
static const uint32_t kInstValidationIdBindless = 0;
static const uint32_t kInstValidationIdBuffAddr = 1;
static const uint32_t kInstValidationIdDebugPrintf = 2;
constexpr uint32_t kInstValidationIdBindless = 0;
constexpr uint32_t kInstValidationIdBuffAddr = 1;
constexpr uint32_t kInstValidationIdDebugPrintf = 2;
} // namespace
class InstrumentPass : public Pass {
using cbb_ptr = const BasicBlock*;

View File

@@ -23,29 +23,28 @@
#include "source/opt/type_manager.h"
#include "source/util/make_unique.h"
const static uint32_t kOpDecorateDecorationInOperandIndex = 1;
const static uint32_t kOpDecorateLiteralInOperandIndex = 2;
const static uint32_t kOpEntryPointInOperandInterface = 3;
const static uint32_t kOpVariableStorageClassInOperandIndex = 0;
const static uint32_t kOpTypeArrayElemTypeInOperandIndex = 0;
const static uint32_t kOpTypeArrayLengthInOperandIndex = 1;
const static uint32_t kOpTypeMatrixColCountInOperandIndex = 1;
const static uint32_t kOpTypeMatrixColTypeInOperandIndex = 0;
const static uint32_t kOpTypePtrTypeInOperandIndex = 1;
const static uint32_t kOpConstantValueInOperandIndex = 0;
namespace spvtools {
namespace opt {
namespace {
constexpr uint32_t kOpDecorateDecorationInOperandIndex = 1;
constexpr uint32_t kOpDecorateLiteralInOperandIndex = 2;
constexpr uint32_t kOpEntryPointInOperandInterface = 3;
constexpr uint32_t kOpVariableStorageClassInOperandIndex = 0;
constexpr uint32_t kOpTypeArrayElemTypeInOperandIndex = 0;
constexpr uint32_t kOpTypeArrayLengthInOperandIndex = 1;
constexpr uint32_t kOpTypeMatrixColCountInOperandIndex = 1;
constexpr uint32_t kOpTypeMatrixColTypeInOperandIndex = 0;
constexpr uint32_t kOpTypePtrTypeInOperandIndex = 1;
constexpr uint32_t kOpConstantValueInOperandIndex = 0;
// Get the length of the OpTypeArray |array_type|.
uint32_t GetArrayLength(analysis::DefUseManager* def_use_mgr,
Instruction* array_type) {
assert(array_type->opcode() == SpvOpTypeArray);
assert(array_type->opcode() == spv::Op::OpTypeArray);
uint32_t const_int_id =
array_type->GetSingleWordInOperand(kOpTypeArrayLengthInOperandIndex);
Instruction* array_length_inst = def_use_mgr->GetDef(const_int_id);
assert(array_length_inst->opcode() == SpvOpConstant);
assert(array_length_inst->opcode() == spv::Op::OpConstant);
return array_length_inst->GetSingleWordInOperand(
kOpConstantValueInOperandIndex);
}
@@ -53,7 +52,7 @@ uint32_t GetArrayLength(analysis::DefUseManager* def_use_mgr,
// Get the element type instruction of the OpTypeArray |array_type|.
Instruction* GetArrayElementType(analysis::DefUseManager* def_use_mgr,
Instruction* array_type) {
assert(array_type->opcode() == SpvOpTypeArray);
assert(array_type->opcode() == spv::Op::OpTypeArray);
uint32_t elem_type_id =
array_type->GetSingleWordInOperand(kOpTypeArrayElemTypeInOperandIndex);
return def_use_mgr->GetDef(elem_type_id);
@@ -62,7 +61,7 @@ Instruction* GetArrayElementType(analysis::DefUseManager* def_use_mgr,
// Get the column type instruction of the OpTypeMatrix |matrix_type|.
Instruction* GetMatrixColumnType(analysis::DefUseManager* def_use_mgr,
Instruction* matrix_type) {
assert(matrix_type->opcode() == SpvOpTypeMatrix);
assert(matrix_type->opcode() == spv::Op::OpTypeMatrix);
uint32_t column_type_id =
matrix_type->GetSingleWordInOperand(kOpTypeMatrixColTypeInOperandIndex);
return def_use_mgr->GetDef(column_type_id);
@@ -77,14 +76,14 @@ uint32_t GetComponentTypeOfArrayMatrix(analysis::DefUseManager* def_use_mgr,
if (depth_to_component == 0) return type_id;
Instruction* type_inst = def_use_mgr->GetDef(type_id);
if (type_inst->opcode() == SpvOpTypeArray) {
if (type_inst->opcode() == spv::Op::OpTypeArray) {
uint32_t elem_type_id =
type_inst->GetSingleWordInOperand(kOpTypeArrayElemTypeInOperandIndex);
return GetComponentTypeOfArrayMatrix(def_use_mgr, elem_type_id,
depth_to_component - 1);
}
assert(type_inst->opcode() == SpvOpTypeMatrix);
assert(type_inst->opcode() == spv::Op::OpTypeMatrix);
uint32_t column_type_id =
type_inst->GetSingleWordInOperand(kOpTypeMatrixColTypeInOperandIndex);
return GetComponentTypeOfArrayMatrix(def_use_mgr, column_type_id,
@@ -94,7 +93,7 @@ uint32_t GetComponentTypeOfArrayMatrix(analysis::DefUseManager* def_use_mgr,
// Creates an OpDecorate instruction whose Target is |var_id| and Decoration is
// |decoration|. Adds |literal| as an extra operand of the instruction.
void CreateDecoration(analysis::DecorationManager* decoration_mgr,
uint32_t var_id, SpvDecoration decoration,
uint32_t var_id, spv::Decoration decoration,
uint32_t literal) {
std::vector<Operand> operands({
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {var_id}},
@@ -102,7 +101,7 @@ void CreateDecoration(analysis::DecorationManager* decoration_mgr,
{static_cast<uint32_t>(decoration)}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {literal}},
});
decoration_mgr->AddDecoration(SpvOpDecorate, std::move(operands));
decoration_mgr->AddDecoration(spv::Op::OpDecorate, std::move(operands));
}
// Replaces load instructions with composite construct instructions in all the
@@ -128,8 +127,8 @@ void ReplaceLoadWithCompositeConstruct(
}
// Returns the storage class of the instruction |var|.
SpvStorageClass GetStorageClass(Instruction* var) {
return static_cast<SpvStorageClass>(
spv::StorageClass GetStorageClass(Instruction* var) {
return static_cast<spv::StorageClass>(
var->GetSingleWordInOperand(kOpVariableStorageClassInOperandIndex));
}
@@ -137,16 +136,17 @@ SpvStorageClass GetStorageClass(Instruction* var) {
bool InterfaceVariableScalarReplacement::HasExtraArrayness(
Instruction& entry_point, Instruction* var) {
SpvExecutionModel execution_model =
static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
if (execution_model != SpvExecutionModelTessellationEvaluation &&
execution_model != SpvExecutionModelTessellationControl) {
spv::ExecutionModel execution_model =
static_cast<spv::ExecutionModel>(entry_point.GetSingleWordInOperand(0));
if (execution_model != spv::ExecutionModel::TessellationEvaluation &&
execution_model != spv::ExecutionModel::TessellationControl) {
return false;
}
if (!context()->get_decoration_mgr()->HasDecoration(var->result_id(),
SpvDecorationPatch)) {
if (execution_model == SpvExecutionModelTessellationControl) return true;
return GetStorageClass(var) != SpvStorageClassOutput;
if (!context()->get_decoration_mgr()->HasDecoration(
var->result_id(), uint32_t(spv::Decoration::Patch))) {
if (execution_model == spv::ExecutionModel::TessellationControl)
return true;
return GetStorageClass(var) != spv::StorageClass::Output;
}
return false;
}
@@ -163,7 +163,7 @@ bool InterfaceVariableScalarReplacement::
bool InterfaceVariableScalarReplacement::GetVariableLocation(
Instruction* var, uint32_t* location) {
return !context()->get_decoration_mgr()->WhileEachDecoration(
var->result_id(), SpvDecorationLocation,
var->result_id(), uint32_t(spv::Decoration::Location),
[location](const Instruction& inst) {
*location =
inst.GetSingleWordInOperand(kOpDecorateLiteralInOperandIndex);
@@ -174,7 +174,7 @@ bool InterfaceVariableScalarReplacement::GetVariableLocation(
bool InterfaceVariableScalarReplacement::GetVariableComponent(
Instruction* var, uint32_t* component) {
return !context()->get_decoration_mgr()->WhileEachDecoration(
var->result_id(), SpvDecorationComponent,
var->result_id(), uint32_t(spv::Decoration::Component),
[component](const Instruction& inst) {
*component =
inst.GetSingleWordInOperand(kOpDecorateLiteralInOperandIndex);
@@ -190,11 +190,11 @@ InterfaceVariableScalarReplacement::CollectInterfaceVariables(
i < entry_point.NumInOperands(); ++i) {
Instruction* interface_var = context()->get_def_use_mgr()->GetDef(
entry_point.GetSingleWordInOperand(i));
assert(interface_var->opcode() == SpvOpVariable);
assert(interface_var->opcode() == spv::Op::OpVariable);
SpvStorageClass storage_class = GetStorageClass(interface_var);
if (storage_class != SpvStorageClassInput &&
storage_class != SpvStorageClassOutput) {
spv::StorageClass storage_class = GetStorageClass(interface_var);
if (storage_class != spv::StorageClass::Input &&
storage_class != spv::StorageClass::Output) {
continue;
}
@@ -205,10 +205,10 @@ InterfaceVariableScalarReplacement::CollectInterfaceVariables(
void InterfaceVariableScalarReplacement::KillInstructionAndUsers(
Instruction* inst) {
if (inst->opcode() == SpvOpEntryPoint) {
if (inst->opcode() == spv::Op::OpEntryPoint) {
return;
}
if (inst->opcode() != SpvOpAccessChain) {
if (inst->opcode() != spv::Op::OpAccessChain) {
context()->KillInst(inst);
return;
}
@@ -232,10 +232,10 @@ void InterfaceVariableScalarReplacement::KillLocationAndComponentDecorations(
uint32_t var_id) {
context()->get_decoration_mgr()->RemoveDecorationsFrom(
var_id, [](const Instruction& inst) {
uint32_t decoration =
inst.GetSingleWordInOperand(kOpDecorateDecorationInOperandIndex);
return decoration == SpvDecorationLocation ||
decoration == SpvDecorationComponent;
spv::Decoration decoration = spv::Decoration(
inst.GetSingleWordInOperand(kOpDecorateDecorationInOperandIndex));
return decoration == spv::Decoration::Location ||
decoration == spv::Decoration::Component;
});
}
@@ -307,9 +307,9 @@ void InterfaceVariableScalarReplacement::AddLocationAndComponentDecorations(
if (!vars.HasMultipleComponents()) {
uint32_t var_id = vars.GetComponentVariable()->result_id();
CreateDecoration(context()->get_decoration_mgr(), var_id,
SpvDecorationLocation, *location);
spv::Decoration::Location, *location);
CreateDecoration(context()->get_decoration_mgr(), var_id,
SpvDecorationComponent, component);
spv::Decoration::Component, component);
++(*location);
return;
}
@@ -389,15 +389,15 @@ bool InterfaceVariableScalarReplacement::ReplaceComponentOfInterfaceVarWith(
std::unordered_map<Instruction*, Instruction*>* loads_to_component_values,
std::unordered_map<Instruction*, Instruction*>*
loads_for_access_chain_to_component_values) {
SpvOp opcode = interface_var_user->opcode();
if (opcode == SpvOpStore) {
spv::Op opcode = interface_var_user->opcode();
if (opcode == spv::Op::OpStore) {
uint32_t value_id = interface_var_user->GetSingleWordInOperand(1);
StoreComponentOfValueToScalarVar(value_id, interface_var_component_indices,
scalar_var, extra_array_index,
interface_var_user);
return true;
}
if (opcode == SpvOpLoad) {
if (opcode == spv::Op::OpLoad) {
Instruction* scalar_load =
LoadScalarVar(scalar_var, extra_array_index, interface_var_user);
loads_to_component_values->insert({interface_var_user, scalar_load});
@@ -408,25 +408,25 @@ bool InterfaceVariableScalarReplacement::ReplaceComponentOfInterfaceVarWith(
// them only for the first element of the extra array.
if (extra_array_index && *extra_array_index != 0) return true;
if (opcode == SpvOpDecorateId || opcode == SpvOpDecorateString ||
opcode == SpvOpDecorate) {
if (opcode == spv::Op::OpDecorateId || opcode == spv::Op::OpDecorateString ||
opcode == spv::Op::OpDecorate) {
CloneAnnotationForVariable(interface_var_user, scalar_var->result_id());
return true;
}
if (opcode == SpvOpName) {
if (opcode == spv::Op::OpName) {
std::unique_ptr<Instruction> new_inst(interface_var_user->Clone(context()));
new_inst->SetInOperand(0, {scalar_var->result_id()});
context()->AddDebug2Inst(std::move(new_inst));
return true;
}
if (opcode == SpvOpEntryPoint) {
if (opcode == spv::Op::OpEntryPoint) {
return ReplaceInterfaceVarInEntryPoint(interface_var, interface_var_user,
scalar_var->result_id());
}
if (opcode == SpvOpAccessChain) {
if (opcode == spv::Op::OpAccessChain) {
ReplaceAccessChainWith(interface_var_user, interface_var_component_indices,
scalar_var,
loads_for_access_chain_to_component_values);
@@ -445,8 +445,8 @@ bool InterfaceVariableScalarReplacement::ReplaceComponentOfInterfaceVarWith(
void InterfaceVariableScalarReplacement::UseBaseAccessChainForAccessChain(
Instruction* access_chain, Instruction* base_access_chain) {
assert(base_access_chain->opcode() == SpvOpAccessChain &&
access_chain->opcode() == SpvOpAccessChain &&
assert(base_access_chain->opcode() == spv::Op::OpAccessChain &&
access_chain->opcode() == spv::Op::OpAccessChain &&
access_chain->GetSingleWordInOperand(0) ==
base_access_chain->result_id());
Instruction::OperandList new_operands;
@@ -470,10 +470,10 @@ Instruction* InterfaceVariableScalarReplacement::CreateAccessChainToVar(
uint32_t ptr_type_id =
GetPointerType(*component_type_id, GetStorageClass(var));
std::unique_ptr<Instruction> new_access_chain(
new Instruction(context(), SpvOpAccessChain, ptr_type_id, TakeNextId(),
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {var->result_id()}}}));
std::unique_ptr<Instruction> new_access_chain(new Instruction(
context(), spv::Op::OpAccessChain, ptr_type_id, TakeNextId(),
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {var->result_id()}}}));
for (uint32_t index_id : index_ids) {
new_access_chain->AddOperand({SPV_OPERAND_TYPE_ID, {index_id}});
}
@@ -489,13 +489,13 @@ Instruction* InterfaceVariableScalarReplacement::CreateAccessChainWithIndex(
Instruction* insert_before) {
uint32_t ptr_type_id =
GetPointerType(component_type_id, GetStorageClass(var));
uint32_t index_id = context()->get_constant_mgr()->GetUIntConst(index);
std::unique_ptr<Instruction> new_access_chain(
new Instruction(context(), SpvOpAccessChain, ptr_type_id, TakeNextId(),
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {var->result_id()}},
{SPV_OPERAND_TYPE_ID, {index_id}},
}));
uint32_t index_id = context()->get_constant_mgr()->GetUIntConstId(index);
std::unique_ptr<Instruction> new_access_chain(new Instruction(
context(), spv::Op::OpAccessChain, ptr_type_id, TakeNextId(),
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {var->result_id()}},
{SPV_OPERAND_TYPE_ID, {index_id}},
}));
Instruction* inst = new_access_chain.get();
context()->get_def_use_mgr()->AnalyzeInstDefUse(inst);
insert_before->InsertBefore(std::move(new_access_chain));
@@ -519,20 +519,20 @@ void InterfaceVariableScalarReplacement::ReplaceAccessChainWith(
[this, access_chain, &indexes, &interface_var_component_indices,
scalar_var, loads_to_component_values](Instruction* user) {
switch (user->opcode()) {
case SpvOpAccessChain: {
case spv::Op::OpAccessChain: {
UseBaseAccessChainForAccessChain(user, access_chain);
ReplaceAccessChainWith(user, interface_var_component_indices,
scalar_var, loads_to_component_values);
return;
}
case SpvOpStore: {
case spv::Op::OpStore: {
uint32_t value_id = user->GetSingleWordInOperand(1);
StoreComponentOfValueToAccessChainToScalarVar(
value_id, interface_var_component_indices, scalar_var, indexes,
user);
return;
}
case SpvOpLoad: {
case spv::Op::OpLoad: {
Instruction* value =
LoadAccessChainToVar(scalar_var, indexes, user);
loads_to_component_values->insert({user, value});
@@ -546,9 +546,9 @@ void InterfaceVariableScalarReplacement::ReplaceAccessChainWith(
void InterfaceVariableScalarReplacement::CloneAnnotationForVariable(
Instruction* annotation_inst, uint32_t var_id) {
assert(annotation_inst->opcode() == SpvOpDecorate ||
annotation_inst->opcode() == SpvOpDecorateId ||
annotation_inst->opcode() == SpvOpDecorateString);
assert(annotation_inst->opcode() == spv::Op::OpDecorate ||
annotation_inst->opcode() == spv::Op::OpDecorateId ||
annotation_inst->opcode() == spv::Op::OpDecorateString);
std::unique_ptr<Instruction> new_inst(annotation_inst->Clone(context()));
new_inst->SetInOperand(0, {var_id});
context()->AddAnnotationInst(std::move(new_inst));
@@ -593,13 +593,13 @@ bool InterfaceVariableScalarReplacement::ReplaceInterfaceVarInEntryPoint(
uint32_t InterfaceVariableScalarReplacement::GetPointeeTypeIdOfVar(
Instruction* var) {
assert(var->opcode() == SpvOpVariable);
assert(var->opcode() == spv::Op::OpVariable);
uint32_t ptr_type_id = var->type_id();
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
Instruction* ptr_type_inst = def_use_mgr->GetDef(ptr_type_id);
assert(ptr_type_inst->opcode() == SpvOpTypePointer &&
assert(ptr_type_inst->opcode() == spv::Op::OpTypePointer &&
"Variable must have a pointer type.");
return ptr_type_inst->GetSingleWordInOperand(kOpTypePtrTypeInOperandIndex);
}
@@ -643,7 +643,7 @@ Instruction* InterfaceVariableScalarReplacement::LoadScalarVar(
Instruction* InterfaceVariableScalarReplacement::CreateLoad(
uint32_t type_id, Instruction* ptr, Instruction* insert_before) {
std::unique_ptr<Instruction> load(
new Instruction(context(), SpvOpLoad, type_id, TakeNextId(),
new Instruction(context(), spv::Op::OpLoad, type_id, TakeNextId(),
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_ID, {ptr->result_id()}}}));
Instruction* load_inst = load.get();
@@ -660,7 +660,7 @@ void InterfaceVariableScalarReplacement::StoreComponentOfValueTo(
component_type_id, value_id, component_indices, extra_array_index));
std::unique_ptr<Instruction> new_store(
new Instruction(context(), SpvOpStore));
new Instruction(context(), spv::Op::OpStore));
new_store->AddOperand({SPV_OPERAND_TYPE_ID, {ptr->result_id()}});
new_store->AddOperand(
{SPV_OPERAND_TYPE_ID, {composite_extract->result_id()}});
@@ -678,7 +678,7 @@ Instruction* InterfaceVariableScalarReplacement::CreateCompositeExtract(
const std::vector<uint32_t>& indexes, const uint32_t* extra_first_index) {
uint32_t component_id = TakeNextId();
Instruction* composite_extract = new Instruction(
context(), SpvOpCompositeExtract, type_id, component_id,
context(), spv::Op::OpCompositeExtract, type_id, component_id,
std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {composite_id}}});
if (extra_first_index) {
composite_extract->AddOperand(
@@ -731,8 +731,8 @@ InterfaceVariableScalarReplacement::CreateCompositeConstructForComponentOfLoad(
depth_to_component);
}
uint32_t new_id = context()->TakeNextId();
std::unique_ptr<Instruction> new_composite_construct(
new Instruction(context(), SpvOpCompositeConstruct, type_id, new_id, {}));
std::unique_ptr<Instruction> new_composite_construct(new Instruction(
context(), spv::Op::OpCompositeConstruct, type_id, new_id, {}));
Instruction* composite_construct = new_composite_construct.get();
def_use_mgr->AnalyzeInstDefUse(composite_construct);
@@ -781,7 +781,7 @@ uint32_t InterfaceVariableScalarReplacement::GetArrayType(
uint32_t elem_type_id, uint32_t array_length) {
analysis::Type* elem_type = context()->get_type_mgr()->GetType(elem_type_id);
uint32_t array_length_id =
context()->get_constant_mgr()->GetUIntConst(array_length);
context()->get_constant_mgr()->GetUIntConstId(array_length);
analysis::Array array_type(
elem_type,
analysis::Array::LengthInfo{array_length_id, {0, array_length}});
@@ -789,7 +789,7 @@ uint32_t InterfaceVariableScalarReplacement::GetArrayType(
}
uint32_t InterfaceVariableScalarReplacement::GetPointerType(
uint32_t type_id, SpvStorageClass storage_class) {
uint32_t type_id, spv::StorageClass storage_class) {
analysis::Type* type = context()->get_type_mgr()->GetType(type_id);
analysis::Pointer ptr_type(type, storage_class);
return context()->get_type_mgr()->GetTypeInstruction(&ptr_type);
@@ -797,9 +797,9 @@ uint32_t InterfaceVariableScalarReplacement::GetPointerType(
InterfaceVariableScalarReplacement::NestedCompositeComponents
InterfaceVariableScalarReplacement::CreateScalarInterfaceVarsForArray(
Instruction* interface_var_type, SpvStorageClass storage_class,
Instruction* interface_var_type, spv::StorageClass storage_class,
uint32_t extra_array_length) {
assert(interface_var_type->opcode() == SpvOpTypeArray);
assert(interface_var_type->opcode() == spv::Op::OpTypeArray);
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
uint32_t array_length = GetArrayLength(def_use_mgr, interface_var_type);
@@ -818,9 +818,9 @@ InterfaceVariableScalarReplacement::CreateScalarInterfaceVarsForArray(
InterfaceVariableScalarReplacement::NestedCompositeComponents
InterfaceVariableScalarReplacement::CreateScalarInterfaceVarsForMatrix(
Instruction* interface_var_type, SpvStorageClass storage_class,
Instruction* interface_var_type, spv::StorageClass storage_class,
uint32_t extra_array_length) {
assert(interface_var_type->opcode() == SpvOpTypeMatrix);
assert(interface_var_type->opcode() == spv::Op::OpTypeMatrix);
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
uint32_t column_count = interface_var_type->GetSingleWordInOperand(
@@ -841,16 +841,16 @@ InterfaceVariableScalarReplacement::CreateScalarInterfaceVarsForMatrix(
InterfaceVariableScalarReplacement::NestedCompositeComponents
InterfaceVariableScalarReplacement::CreateScalarInterfaceVarsForReplacement(
Instruction* interface_var_type, SpvStorageClass storage_class,
Instruction* interface_var_type, spv::StorageClass storage_class,
uint32_t extra_array_length) {
// Handle array case.
if (interface_var_type->opcode() == SpvOpTypeArray) {
if (interface_var_type->opcode() == spv::Op::OpTypeArray) {
return CreateScalarInterfaceVarsForArray(interface_var_type, storage_class,
extra_array_length);
}
// Handle matrix case.
if (interface_var_type->opcode() == SpvOpTypeMatrix) {
if (interface_var_type->opcode() == spv::Op::OpTypeMatrix) {
return CreateScalarInterfaceVarsForMatrix(interface_var_type, storage_class,
extra_array_length);
}
@@ -865,7 +865,7 @@ InterfaceVariableScalarReplacement::CreateScalarInterfaceVarsForReplacement(
context()->get_type_mgr()->FindPointerToType(type_id, storage_class);
uint32_t id = TakeNextId();
std::unique_ptr<Instruction> variable(
new Instruction(context(), SpvOpVariable, ptr_type_id, id,
new Instruction(context(), spv::Op::OpVariable, ptr_type_id, id,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_STORAGE_CLASS,
{static_cast<uint32_t>(storage_class)}}}));
@@ -948,8 +948,8 @@ InterfaceVariableScalarReplacement::ReplaceInterfaceVarsWithScalars(
return Pass::Status::Failure;
}
if (interface_var_type->opcode() != SpvOpTypeArray &&
interface_var_type->opcode() != SpvOpTypeMatrix) {
if (interface_var_type->opcode() != spv::Op::OpTypeArray &&
interface_var_type->opcode() != spv::Op::OpTypeMatrix) {
continue;
}

Some files were not shown because too many files have changed in this diff Show More