mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-17 20:52:36 +01:00
Updated spirv-tools.
This commit is contained in:
@@ -1 +1 @@
|
||||
"v2021.3-dev", "SPIRV-Tools v2021.3-dev 25ef0e5c8566c2abe88852e3b72e0facccbbbcb9"
|
||||
"v2021.3-dev", "SPIRV-Tools v2021.3-dev 39e3d51fa1194e78df5376072164455270154b39"
|
||||
|
||||
@@ -44,6 +44,7 @@ static const SpvCapability pygen_variable_caps_Pipes[] = {SpvCapabilityPipes};
|
||||
static const SpvCapability pygen_variable_caps_RayQueryKHR[] = {SpvCapabilityRayQueryKHR};
|
||||
static const SpvCapability pygen_variable_caps_RayTracingKHR[] = {SpvCapabilityRayTracingKHR};
|
||||
static const SpvCapability pygen_variable_caps_RayTracingKHRRayQueryKHR[] = {SpvCapabilityRayTracingKHR, SpvCapabilityRayQueryKHR};
|
||||
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_RayTracingNVRayTracingKHRRayQueryKHR[] = {SpvCapabilityRayTracingNV, SpvCapabilityRayTracingKHR, SpvCapabilityRayQueryKHR};
|
||||
@@ -90,6 +91,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shader[] = {spv
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing, spvtools::Extension::kSPV_KHR_ray_tracing};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query[] = {spvtools::Extension::kSPV_NV_ray_tracing, spvtools::Extension::kSPV_KHR_ray_tracing, spvtools::Extension::kSPV_KHR_ray_query};
|
||||
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_shader_image_footprint[] = {spvtools::Extension::kSPV_NV_shader_image_footprint};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_NV_shader_subgroup_partitioned[] = {spvtools::Extension::kSPV_NV_shader_subgroup_partitioned};
|
||||
|
||||
@@ -482,6 +484,8 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
|
||||
{"IgnoreIntersectionNV", SpvOpIgnoreIntersectionNV, 1, pygen_variable_caps_RayTracingNV, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu},
|
||||
{"TerminateRayNV", SpvOpTerminateRayNV, 1, pygen_variable_caps_RayTracingNV, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu},
|
||||
{"TraceNV", SpvOpTraceNV, 1, pygen_variable_caps_RayTracingNV, 11, {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_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu},
|
||||
{"TraceMotionNV", SpvOpTraceMotionNV, 1, pygen_variable_caps_RayTracingMotionBlurNV, 12, {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_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, 0xffffffffu, 0xffffffffu},
|
||||
{"TraceRayMotionNV", SpvOpTraceRayMotionNV, 1, pygen_variable_caps_RayTracingMotionBlurNV, 12, {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_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, 0xffffffffu, 0xffffffffu},
|
||||
{"TypeAccelerationStructureKHR", SpvOpTypeAccelerationStructureKHR, 3, pygen_variable_caps_RayTracingNVRayTracingKHRRayQueryKHR, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 3, pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query, 0xffffffffu, 0xffffffffu},
|
||||
{"TypeAccelerationStructureNV", SpvOpTypeAccelerationStructureNV, 3, pygen_variable_caps_RayTracingNVRayTracingKHRRayQueryKHR, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 3, pygen_variable_exts_SPV_NV_ray_tracingSPV_KHR_ray_tracingSPV_KHR_ray_query, 0xffffffffu, 0xffffffffu},
|
||||
{"ExecuteCallableNV", SpvOpExecuteCallableNV, 1, pygen_variable_caps_RayTracingNV, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 1, pygen_variable_exts_SPV_NV_ray_tracing, 0xffffffffu, 0xffffffffu},
|
||||
@@ -693,7 +697,6 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
|
||||
{"ArbitraryFloatPowINTEL", SpvOpArbitraryFloatPowINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 10, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
{"ArbitraryFloatPowRINTEL", SpvOpArbitraryFloatPowRINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 10, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
{"ArbitraryFloatPowNINTEL", SpvOpArbitraryFloatPowNINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
{"ArbitraryFloatPowNINTEL", SpvOpArbitraryFloatPowNINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFloatingPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
{"LoopControlINTEL", SpvOpLoopControlINTEL, 1, pygen_variable_caps_UnstructuredLoopControlsINTEL, 1, {SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER}, 0, 0, 1, pygen_variable_exts_SPV_INTEL_unstructured_loop_controls, 0xffffffffu, 0xffffffffu},
|
||||
{"FixedSqrtINTEL", SpvOpFixedSqrtINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
{"FixedRecipINTEL", SpvOpFixedRecipINTEL, 1, pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL, 9, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
|
||||
|
||||
@@ -174,6 +174,8 @@ const char* ExtensionToString(Extension extension) {
|
||||
return "SPV_NV_mesh_shader";
|
||||
case Extension::kSPV_NV_ray_tracing:
|
||||
return "SPV_NV_ray_tracing";
|
||||
case Extension::kSPV_NV_ray_tracing_motion_blur:
|
||||
return "SPV_NV_ray_tracing_motion_blur";
|
||||
case Extension::kSPV_NV_sample_mask_override_coverage:
|
||||
return "SPV_NV_sample_mask_override_coverage";
|
||||
case Extension::kSPV_NV_shader_image_footprint:
|
||||
@@ -197,8 +199,8 @@ const char* ExtensionToString(Extension extension) {
|
||||
|
||||
|
||||
bool GetExtensionFromString(const char* str, Extension* extension) {
|
||||
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_atomic_float16_add", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_shader_atomic_float_min_max", "SPV_EXT_shader_image_int64", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_arbitrary_precision_fixed_point", "SPV_INTEL_arbitrary_precision_floating_point", "SPV_INTEL_arbitrary_precision_integers", "SPV_INTEL_blocking_pipes", "SPV_INTEL_debug_module", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_float_controls2", "SPV_INTEL_fp_fast_math_mode", "SPV_INTEL_fpga_buffer_location", "SPV_INTEL_fpga_cluster_attributes", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_accesses", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_inline_assembly", "SPV_INTEL_io_pipes", "SPV_INTEL_kernel_attributes", "SPV_INTEL_long_constant_composite", "SPV_INTEL_loop_fuse", "SPV_INTEL_media_block_io", "SPV_INTEL_optnone", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_INTEL_usm_storage_classes", "SPV_INTEL_variable_length_array", "SPV_INTEL_vector_compute", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_bit_instructions", "SPV_KHR_device_group", "SPV_KHR_expect_assume", "SPV_KHR_float_controls", "SPV_KHR_fragment_shading_rate", "SPV_KHR_integer_dot_product", "SPV_KHR_linkonce_odr", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_non_semantic_info", "SPV_KHR_physical_storage_buffer", "SPV_KHR_post_depth_coverage", "SPV_KHR_ray_query", "SPV_KHR_ray_tracing", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_clock", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_KHR_workgroup_memory_explicit_layout", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
|
||||
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_atomic_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_optnone, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_INTEL_usm_storage_classes, Extension::kSPV_INTEL_variable_length_array, Extension::kSPV_INTEL_vector_compute, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_bit_instructions, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_expect_assume, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_fragment_shading_rate, Extension::kSPV_KHR_integer_dot_product, Extension::kSPV_KHR_linkonce_odr, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_non_semantic_info, Extension::kSPV_KHR_physical_storage_buffer, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_ray_query, Extension::kSPV_KHR_ray_tracing, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_clock, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_KHR_workgroup_memory_explicit_layout, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
|
||||
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_atomic_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_optnone", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_INTEL_usm_storage_classes", "SPV_INTEL_variable_length_array", "SPV_INTEL_vector_compute", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_bit_instructions", "SPV_KHR_device_group", "SPV_KHR_expect_assume", "SPV_KHR_float_controls", "SPV_KHR_fragment_shading_rate", "SPV_KHR_integer_dot_product", "SPV_KHR_linkonce_odr", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_non_semantic_info", "SPV_KHR_physical_storage_buffer", "SPV_KHR_post_depth_coverage", "SPV_KHR_ray_query", "SPV_KHR_ray_tracing", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_clock", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_KHR_workgroup_memory_explicit_layout", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_ray_tracing_motion_blur", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
|
||||
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_atomic_float16_add, Extension::kSPV_EXT_shader_atomic_float_add, Extension::kSPV_EXT_shader_atomic_float_min_max, Extension::kSPV_EXT_shader_image_int64, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_arbitrary_precision_fixed_point, Extension::kSPV_INTEL_arbitrary_precision_floating_point, Extension::kSPV_INTEL_arbitrary_precision_integers, Extension::kSPV_INTEL_blocking_pipes, Extension::kSPV_INTEL_debug_module, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_float_controls2, Extension::kSPV_INTEL_fp_fast_math_mode, Extension::kSPV_INTEL_fpga_buffer_location, Extension::kSPV_INTEL_fpga_cluster_attributes, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_accesses, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_inline_assembly, Extension::kSPV_INTEL_io_pipes, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_long_constant_composite, Extension::kSPV_INTEL_loop_fuse, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_optnone, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_INTEL_usm_storage_classes, Extension::kSPV_INTEL_variable_length_array, Extension::kSPV_INTEL_vector_compute, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_bit_instructions, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_expect_assume, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_fragment_shading_rate, Extension::kSPV_KHR_integer_dot_product, Extension::kSPV_KHR_linkonce_odr, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_non_semantic_info, Extension::kSPV_KHR_physical_storage_buffer, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_ray_query, Extension::kSPV_KHR_ray_tracing, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_clock, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_KHR_workgroup_memory_explicit_layout, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_ray_tracing_motion_blur, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
|
||||
const auto b = std::begin(known_ext_strs);
|
||||
const auto e = std::end(known_ext_strs);
|
||||
const auto found = std::equal_range(
|
||||
@@ -476,6 +478,8 @@ const char* CapabilityToString(SpvCapability capability) {
|
||||
return "StorageTexelBufferArrayNonUniformIndexing";
|
||||
case SpvCapabilityRayTracingNV:
|
||||
return "RayTracingNV";
|
||||
case SpvCapabilityRayTracingMotionBlurNV:
|
||||
return "RayTracingMotionBlurNV";
|
||||
case SpvCapabilityVulkanMemoryModel:
|
||||
return "VulkanMemoryModel";
|
||||
case SpvCapabilityVulkanMemoryModelDeviceScope:
|
||||
|
||||
@@ -85,6 +85,7 @@ kSPV_NV_fragment_shader_barycentric,
|
||||
kSPV_NV_geometry_shader_passthrough,
|
||||
kSPV_NV_mesh_shader,
|
||||
kSPV_NV_ray_tracing,
|
||||
kSPV_NV_ray_tracing_motion_blur,
|
||||
kSPV_NV_sample_mask_override_coverage,
|
||||
kSPV_NV_shader_image_footprint,
|
||||
kSPV_NV_shader_sm_builtins,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{16, "X-LEGEND", "Mesa-IR/SPIR-V Translator", "X-LEGEND Mesa-IR/SPIR-V Translator"},
|
||||
{17, "Khronos", "SPIR-V Tools Linker", "Khronos SPIR-V Tools Linker"},
|
||||
{18, "Wine", "VKD3D Shader Compiler", "Wine VKD3D Shader Compiler"},
|
||||
{19, "Clay", "Clay Shader Compiler", "Clay Clay Shader Compiler"},
|
||||
{19, "Tellusim", "Clay Shader Compiler", "Tellusim Clay Shader Compiler"},
|
||||
{20, "W3C WebGPU Group", "WHLSL Shader Translator", "W3C WebGPU Group WHLSL Shader Translator"},
|
||||
{21, "Google", "Clspv", "Google Clspv"},
|
||||
{22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"},
|
||||
|
||||
@@ -64,12 +64,14 @@ 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_MultiViewportShaderViewportIndexShaderViewportIndexLayerEXTMeshShadingNV[] = {SpvCapabilityMultiViewport, SpvCapabilityShaderViewportIndex, SpvCapabilityShaderViewportIndexLayerEXT, SpvCapabilityMeshShadingNV};
|
||||
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_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_RayTraversalPrimitiveCullingKHR[] = {SpvCapabilityRayTraversalPrimitiveCullingKHR};
|
||||
@@ -199,6 +201,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_NV_geometry_shader_pass
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shader[] = {spvtools::Extension::kSPV_NV_mesh_shader};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_NV_mesh_shaderSPV_NV_viewport_array2[] = {spvtools::Extension::kSPV_NV_mesh_shader, spvtools::Extension::kSPV_NV_viewport_array2};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_NV_ray_tracing[] = {spvtools::Extension::kSPV_NV_ray_tracing};
|
||||
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_sm_builtins[] = {spvtools::Extension::kSPV_NV_shader_sm_builtins};
|
||||
@@ -272,7 +275,7 @@ static const spv_operand_desc_t pygen_variable_FunctionControlEntries[] = {
|
||||
{"DontInline", 0x0002, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
|
||||
{"Pure", 0x0004, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
|
||||
{"Const", 0x0008, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
|
||||
{"OptNoneINTEL", 0x10000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
|
||||
{"OptNoneINTEL", 0x10000, 1, pygen_variable_caps_OptNoneINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
|
||||
};
|
||||
|
||||
static const spv_operand_desc_t pygen_variable_MemorySemanticsEntries[] = {
|
||||
@@ -876,6 +879,7 @@ static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = {
|
||||
{"HitTNV", 5332, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"HitKindNV", 5333, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"HitKindKHR", 5333, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"CurrentRayTimeNV", 5334, 1, pygen_variable_caps_RayTracingMotionBlurNV, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"IncomingRayFlagsNV", 5351, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"IncomingRayFlagsKHR", 5351, 2, pygen_variable_caps_RayTracingNVRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_tracingSPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"RayGeometryIndexKHR", 5352, 1, pygen_variable_caps_RayTracingKHR, 1, pygen_variable_exts_SPV_KHR_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
|
||||
@@ -1060,6 +1064,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
|
||||
{"StorageTexelBufferArrayNonUniformIndexing", 5312, 2, pygen_variable_caps_ImageBufferShaderNonUniform, 1, pygen_variable_exts_SPV_EXT_descriptor_indexing, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
|
||||
{"StorageTexelBufferArrayNonUniformIndexingEXT", 5312, 2, pygen_variable_caps_ImageBufferShaderNonUniform, 1, pygen_variable_exts_SPV_EXT_descriptor_indexing, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
|
||||
{"RayTracingNV", 5340, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"RayTracingMotionBlurNV", 5341, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_ray_tracing_motion_blur, {}, 0xffffffffu, 0xffffffffu},
|
||||
{"VulkanMemoryModel", 5345, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
|
||||
{"VulkanMemoryModelKHR", 5345, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
|
||||
{"VulkanMemoryModelDeviceScope", 5346, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "libspirv.hpp"
|
||||
@@ -27,6 +28,7 @@ namespace spvtools {
|
||||
|
||||
namespace opt {
|
||||
class Pass;
|
||||
struct DescriptorSetAndBinding;
|
||||
}
|
||||
|
||||
// C++ interface for SPIR-V optimization functionalities. It wraps the context
|
||||
@@ -854,6 +856,16 @@ Optimizer::PassToken CreateAmdExtToKhrPass();
|
||||
// propagated into their final positions.
|
||||
Optimizer::PassToken CreateInterpolateFixupPass();
|
||||
|
||||
// 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
|
||||
// binding that is one of the given pairs, they will be converted to a sampled
|
||||
// image. In addition, if only an image has the descriptor set and binding that
|
||||
// is one of the given pairs, it will be converted to a sampled image as well.
|
||||
Optimizer::PassToken CreateConvertToSampledImagePass(
|
||||
const std::vector<opt::DescriptorSetAndBinding>&
|
||||
descriptor_set_binding_pairs);
|
||||
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_
|
||||
|
||||
@@ -1002,7 +1002,7 @@ const analysis::Constant* FoldClamp1(
|
||||
"Expecting a GLSLstd450 extended instruction.");
|
||||
|
||||
// Make sure all Clamp operands are constants.
|
||||
for (uint32_t i = 1; i < 3; i++) {
|
||||
for (uint32_t i = 1; i < 4; i++) {
|
||||
if (constants[i] == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1017,7 +1017,7 @@ const analysis::Constant* FoldClamp1(
|
||||
context);
|
||||
}
|
||||
|
||||
// Fold a clamp instruction when |x >= min_val|.
|
||||
// Fold a clamp instruction when |x <= min_val|.
|
||||
const analysis::Constant* FoldClamp2(
|
||||
IRContext* context, Instruction* inst,
|
||||
const std::vector<const analysis::Constant*>& constants) {
|
||||
|
||||
@@ -432,6 +432,12 @@ uint32_t ConstantManager::GetSIntConst(int32_t val) {
|
||||
return GetDefiningInstruction(c)->result_id();
|
||||
}
|
||||
|
||||
uint32_t ConstantManager::GetUIntConst(uint32_t val) {
|
||||
Type* uint_type = context()->get_type_mgr()->GetUIntType();
|
||||
const Constant* c = GetConstant(uint_type, {val});
|
||||
return GetDefiningInstruction(c)->result_id();
|
||||
}
|
||||
|
||||
std::vector<const analysis::Constant*> Constant::GetVectorComponents(
|
||||
analysis::ConstantManager* const_mgr) const {
|
||||
std::vector<const analysis::Constant*> components;
|
||||
|
||||
3
3rdparty/spirv-tools/source/opt/constants.h
vendored
3
3rdparty/spirv-tools/source/opt/constants.h
vendored
@@ -642,6 +642,9 @@ class ConstantManager {
|
||||
// Returns the id of a 32-bit signed integer constant with value |val|.
|
||||
uint32_t GetSIntConst(int32_t val);
|
||||
|
||||
// Returns the id of a 32-bit unsigned integer constant with value |val|.
|
||||
uint32_t GetUIntConst(uint32_t val);
|
||||
|
||||
private:
|
||||
// Creates a Constant instance with the given type and a vector of constant
|
||||
// defining words. Returns a unique pointer to the created Constant instance
|
||||
|
||||
437
3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp
vendored
Normal file
437
3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.cpp
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
// Copyright (c) 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/opt/convert_to_sampled_image_pass.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
|
||||
#include "source/opt/ir_builder.h"
|
||||
#include "source/util/make_unique.h"
|
||||
#include "source/util/parse_number.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
using VectorOfDescriptorSetAndBindingPairs =
|
||||
std::vector<DescriptorSetAndBinding>;
|
||||
using DescriptorSetBindingToInstruction =
|
||||
ConvertToSampledImagePass::DescriptorSetBindingToInstruction;
|
||||
|
||||
namespace {
|
||||
|
||||
using utils::ParseNumber;
|
||||
|
||||
// Returns true if the given char is ':', '\0' or considered as blank space
|
||||
// (i.e.: '\n', '\r', '\v', '\t', '\f' and ' ').
|
||||
bool IsSeparator(char ch) {
|
||||
return std::strchr(":\0", ch) || std::isspace(ch) != 0;
|
||||
}
|
||||
|
||||
// Reads characters starting from |str| until it meets a separator. Parses a
|
||||
// number from the characters and stores it into |number|. Returns the pointer
|
||||
// to the separator if it succeeds. Otherwise, returns nullptr.
|
||||
const char* ParseNumberUntilSeparator(const char* str, uint32_t* number) {
|
||||
const char* number_begin = str;
|
||||
while (!IsSeparator(*str)) str++;
|
||||
const char* number_end = str;
|
||||
std::string number_in_str(number_begin, number_end - number_begin);
|
||||
if (!utils::ParseNumber(number_in_str.c_str(), number)) {
|
||||
// The descriptor set is not a valid uint32 number.
|
||||
return nullptr;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// Returns id of the image type used for the sampled image type of
|
||||
// |sampled_image|.
|
||||
uint32_t GetImageTypeOfSampledImage(analysis::TypeManager* type_mgr,
|
||||
Instruction* sampled_image) {
|
||||
auto* sampled_image_type =
|
||||
type_mgr->GetType(sampled_image->type_id())->AsSampledImage();
|
||||
return type_mgr->GetTypeInstruction(sampled_image_type->image_type());
|
||||
}
|
||||
|
||||
// Finds the instruction whose id is |inst_id|. Follows the operand of
|
||||
// OpCopyObject recursively if the opcode of the instruction is OpCopyObject
|
||||
// and returns the first instruction that does not have OpCopyObject as opcode.
|
||||
Instruction* GetNonCopyObjectDef(analysis::DefUseManager* def_use_mgr,
|
||||
uint32_t inst_id) {
|
||||
Instruction* inst = def_use_mgr->GetDef(inst_id);
|
||||
while (inst->opcode() == SpvOpCopyObject) {
|
||||
inst_id = inst->GetSingleWordInOperand(0u);
|
||||
inst = def_use_mgr->GetDef(inst_id);
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ConvertToSampledImagePass::GetDescriptorSetBinding(
|
||||
const Instruction& inst,
|
||||
DescriptorSetAndBinding* descriptor_set_binding) const {
|
||||
auto* decoration_manager = context()->get_decoration_mgr();
|
||||
bool found_descriptor_set_to_convert = false;
|
||||
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) {
|
||||
if (found_descriptor_set_to_convert) {
|
||||
assert(false && "A resource has two OpDecorate for the descriptor set");
|
||||
return false;
|
||||
}
|
||||
descriptor_set_binding->descriptor_set =
|
||||
decorate->GetSingleWordInOperand(2u);
|
||||
found_descriptor_set_to_convert = true;
|
||||
} else if (decoration == SpvDecorationBinding) {
|
||||
if (found_binding_to_convert) {
|
||||
assert(false && "A resource has two OpDecorate for the binding");
|
||||
return false;
|
||||
}
|
||||
descriptor_set_binding->binding = decorate->GetSingleWordInOperand(2u);
|
||||
found_binding_to_convert = true;
|
||||
}
|
||||
}
|
||||
return found_descriptor_set_to_convert && found_binding_to_convert;
|
||||
}
|
||||
|
||||
bool ConvertToSampledImagePass::ShouldResourceBeConverted(
|
||||
const DescriptorSetAndBinding& descriptor_set_binding) const {
|
||||
return descriptor_set_binding_pairs_.find(descriptor_set_binding) !=
|
||||
descriptor_set_binding_pairs_.end();
|
||||
}
|
||||
|
||||
const analysis::Type* ConvertToSampledImagePass::GetVariableType(
|
||||
const Instruction& variable) const {
|
||||
if (variable.opcode() != SpvOpVariable) return nullptr;
|
||||
auto* type = context()->get_type_mgr()->GetType(variable.type_id());
|
||||
auto* pointer_type = type->AsPointer();
|
||||
if (!pointer_type) return nullptr;
|
||||
|
||||
return pointer_type->pointee_type();
|
||||
}
|
||||
|
||||
SpvStorageClass ConvertToSampledImagePass::GetStorageClass(
|
||||
const Instruction& variable) const {
|
||||
assert(variable.opcode() == SpvOpVariable);
|
||||
auto* type = context()->get_type_mgr()->GetType(variable.type_id());
|
||||
auto* pointer_type = type->AsPointer();
|
||||
if (!pointer_type) return SpvStorageClassMax;
|
||||
|
||||
return pointer_type->storage_class();
|
||||
}
|
||||
|
||||
bool ConvertToSampledImagePass::CollectResourcesToConvert(
|
||||
DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler,
|
||||
DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image)
|
||||
const {
|
||||
for (auto& inst : context()->types_values()) {
|
||||
const auto* variable_type = GetVariableType(inst);
|
||||
if (variable_type == nullptr) continue;
|
||||
|
||||
DescriptorSetAndBinding descriptor_set_binding;
|
||||
if (!GetDescriptorSetBinding(inst, &descriptor_set_binding)) continue;
|
||||
|
||||
if (!ShouldResourceBeConverted(descriptor_set_binding)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (variable_type->AsImage()) {
|
||||
if (!descriptor_set_binding_pair_to_image
|
||||
->insert({descriptor_set_binding, &inst})
|
||||
.second) {
|
||||
return false;
|
||||
}
|
||||
} else if (variable_type->AsSampler()) {
|
||||
if (!descriptor_set_binding_pair_to_sampler
|
||||
->insert({descriptor_set_binding, &inst})
|
||||
.second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Pass::Status ConvertToSampledImagePass::Process() {
|
||||
Status status = Status::SuccessWithoutChange;
|
||||
|
||||
DescriptorSetBindingToInstruction descriptor_set_binding_pair_to_sampler,
|
||||
descriptor_set_binding_pair_to_image;
|
||||
if (!CollectResourcesToConvert(&descriptor_set_binding_pair_to_sampler,
|
||||
&descriptor_set_binding_pair_to_image)) {
|
||||
return Status::Failure;
|
||||
}
|
||||
|
||||
for (auto& image : descriptor_set_binding_pair_to_image) {
|
||||
status = CombineStatus(
|
||||
status, UpdateImageVariableToSampledImage(image.second, image.first));
|
||||
if (status == Status::Failure) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& sampler : descriptor_set_binding_pair_to_sampler) {
|
||||
// Converting only a Sampler to Sampled Image is not allowed. It must have a
|
||||
// corresponding image to combine the sampler with.
|
||||
auto image_itr = descriptor_set_binding_pair_to_image.find(sampler.first);
|
||||
if (image_itr == descriptor_set_binding_pair_to_image.end() ||
|
||||
image_itr->second == nullptr) {
|
||||
return Status::Failure;
|
||||
}
|
||||
|
||||
status = CombineStatus(
|
||||
status, CheckUsesOfSamplerVariable(sampler.second, image_itr->second));
|
||||
if (status == Status::Failure) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void ConvertToSampledImagePass::FindUses(const Instruction* inst,
|
||||
std::vector<Instruction*>* uses,
|
||||
uint32_t 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) {
|
||||
FindUses(user, uses, user_opcode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ConvertToSampledImagePass::FindUsesOfImage(
|
||||
const Instruction* image, std::vector<Instruction*>* uses) const {
|
||||
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:
|
||||
uses->push_back(user);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (user->opcode() == SpvOpCopyObject) {
|
||||
FindUsesOfImage(user, uses);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Instruction* ConvertToSampledImagePass::CreateImageExtraction(
|
||||
Instruction* sampled_image) {
|
||||
InstructionBuilder builder(
|
||||
context(), sampled_image->NextNode(),
|
||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
||||
return builder.AddUnaryOp(
|
||||
GetImageTypeOfSampledImage(context()->get_type_mgr(), sampled_image),
|
||||
SpvOpImage, sampled_image->result_id());
|
||||
}
|
||||
|
||||
uint32_t ConvertToSampledImagePass::GetSampledImageTypeForImage(
|
||||
Instruction* image_variable) {
|
||||
const auto* variable_type = GetVariableType(*image_variable);
|
||||
if (variable_type == nullptr) return 0;
|
||||
const auto* image_type = variable_type->AsImage();
|
||||
if (image_type == nullptr) return 0;
|
||||
|
||||
analysis::Image image_type_for_sampled_image(*image_type);
|
||||
analysis::SampledImage sampled_image_type(&image_type_for_sampled_image);
|
||||
return context()->get_type_mgr()->GetTypeInstruction(&sampled_image_type);
|
||||
}
|
||||
|
||||
Instruction* ConvertToSampledImagePass::UpdateImageUses(
|
||||
Instruction* sampled_image_load) {
|
||||
std::vector<Instruction*> uses_of_load;
|
||||
FindUsesOfImage(sampled_image_load, &uses_of_load);
|
||||
if (uses_of_load.empty()) return nullptr;
|
||||
|
||||
auto* extracted_image = CreateImageExtraction(sampled_image_load);
|
||||
for (auto* user : uses_of_load) {
|
||||
user->SetInOperand(0, {extracted_image->result_id()});
|
||||
context()->get_def_use_mgr()->AnalyzeInstUse(user);
|
||||
}
|
||||
return extracted_image;
|
||||
}
|
||||
|
||||
bool ConvertToSampledImagePass::
|
||||
IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
|
||||
Instruction* sampled_image_inst,
|
||||
const DescriptorSetAndBinding& descriptor_set_binding) {
|
||||
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;
|
||||
auto* sampler = def_use_mgr->GetDef(sampler_load->GetSingleWordInOperand(0u));
|
||||
DescriptorSetAndBinding sampler_descriptor_set_binding;
|
||||
return GetDescriptorSetBinding(*sampler, &sampler_descriptor_set_binding) &&
|
||||
sampler_descriptor_set_binding == descriptor_set_binding;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
auto* def_use_mgr = context()->get_def_use_mgr();
|
||||
for (auto* sampled_image_inst : sampled_image_users) {
|
||||
if (IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
|
||||
sampled_image_inst, image_descriptor_set_binding)) {
|
||||
context()->ReplaceAllUsesWith(sampled_image_inst->result_id(),
|
||||
image_load->result_id());
|
||||
def_use_mgr->AnalyzeInstUse(image_load);
|
||||
context()->KillInst(sampled_image_inst);
|
||||
} else {
|
||||
if (!image_extraction)
|
||||
image_extraction = CreateImageExtraction(image_load);
|
||||
sampled_image_inst->SetInOperand(0, {image_extraction->result_id()});
|
||||
def_use_mgr->AnalyzeInstUse(sampled_image_inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertToSampledImagePass::MoveInstructionNextToType(Instruction* inst,
|
||||
uint32_t type_id) {
|
||||
auto* type_inst = context()->get_def_use_mgr()->GetDef(type_id);
|
||||
inst->SetResultType(type_id);
|
||||
inst->RemoveFromList();
|
||||
inst->InsertAfter(type_inst);
|
||||
}
|
||||
|
||||
bool ConvertToSampledImagePass::ConvertImageVariableToSampledImage(
|
||||
Instruction* image_variable, uint32_t sampled_image_type_id) {
|
||||
auto* sampled_image_type =
|
||||
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;
|
||||
analysis::Pointer sampled_image_pointer(sampled_image_type, storage_class);
|
||||
|
||||
// Make sure |image_variable| is behind its type i.e., avoid the forward
|
||||
// reference.
|
||||
uint32_t type_id =
|
||||
context()->get_type_mgr()->GetTypeInstruction(&sampled_image_pointer);
|
||||
MoveInstructionNextToType(image_variable, type_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
if (image_variable_loads.empty()) return Status::SuccessWithoutChange;
|
||||
|
||||
const uint32_t sampled_image_type_id =
|
||||
GetSampledImageTypeForImage(image_variable);
|
||||
if (!sampled_image_type_id) return Status::Failure;
|
||||
|
||||
for (auto* load : image_variable_loads) {
|
||||
load->SetResultType(sampled_image_type_id);
|
||||
auto* image_extraction = UpdateImageUses(load);
|
||||
UpdateSampledImageUses(load, image_extraction, descriptor_set_binding);
|
||||
}
|
||||
|
||||
return ConvertImageVariableToSampledImage(image_variable,
|
||||
sampled_image_type_id)
|
||||
? Status::SuccessWithChange
|
||||
: Status::Failure;
|
||||
}
|
||||
|
||||
bool ConvertToSampledImagePass::DoesSampledImageReferenceImage(
|
||||
Instruction* sampled_image_inst, Instruction* image_variable) {
|
||||
if (sampled_image_inst->opcode() != SpvOpSampledImage) 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;
|
||||
auto* image =
|
||||
GetNonCopyObjectDef(def_use_mgr, image_load->GetSingleWordInOperand(0u));
|
||||
return image->opcode() == SpvOpVariable &&
|
||||
image->result_id() == image_variable->result_id();
|
||||
}
|
||||
|
||||
Pass::Status ConvertToSampledImagePass::CheckUsesOfSamplerVariable(
|
||||
const Instruction* sampler_variable,
|
||||
Instruction* image_to_be_combined_with) {
|
||||
if (image_to_be_combined_with == nullptr) return Status::Failure;
|
||||
|
||||
std::vector<Instruction*> sampler_variable_loads;
|
||||
FindUses(sampler_variable, &sampler_variable_loads, SpvOpLoad);
|
||||
for (auto* load : sampler_variable_loads) {
|
||||
std::vector<Instruction*> sampled_image_users;
|
||||
FindUses(load, &sampled_image_users, SpvOpSampledImage);
|
||||
for (auto* sampled_image_inst : sampled_image_users) {
|
||||
if (!DoesSampledImageReferenceImage(sampled_image_inst,
|
||||
image_to_be_combined_with)) {
|
||||
return Status::Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
std::unique_ptr<VectorOfDescriptorSetAndBindingPairs>
|
||||
ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
|
||||
const char* str) {
|
||||
if (!str) return nullptr;
|
||||
|
||||
auto descriptor_set_binding_pairs =
|
||||
MakeUnique<VectorOfDescriptorSetAndBindingPairs>();
|
||||
|
||||
while (std::isspace(*str)) str++; // skip leading spaces.
|
||||
|
||||
// The parsing loop, break when points to the end.
|
||||
while (*str) {
|
||||
// Parse the descriptor set.
|
||||
uint32_t descriptor_set = 0;
|
||||
str = ParseNumberUntilSeparator(str, &descriptor_set);
|
||||
if (str == nullptr) return nullptr;
|
||||
|
||||
// Find the ':', spaces between the descriptor set and the ':' are not
|
||||
// allowed.
|
||||
if (*str++ != ':') {
|
||||
// ':' not found
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Parse the binding.
|
||||
uint32_t binding = 0;
|
||||
str = ParseNumberUntilSeparator(str, &binding);
|
||||
if (str == nullptr) return nullptr;
|
||||
|
||||
descriptor_set_binding_pairs->push_back({descriptor_set, binding});
|
||||
|
||||
// Skip trailing spaces.
|
||||
while (std::isspace(*str)) str++;
|
||||
}
|
||||
|
||||
return descriptor_set_binding_pairs;
|
||||
}
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
207
3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.h
vendored
Normal file
207
3rdparty/spirv-tools/source/opt/convert_to_sampled_image_pass.h
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
|
||||
#define SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
#include "source/opt/pass.h"
|
||||
#include "source/opt/types.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// A struct for a pair of descriptor set and binding.
|
||||
struct DescriptorSetAndBinding {
|
||||
uint32_t descriptor_set;
|
||||
uint32_t binding;
|
||||
|
||||
bool operator==(const DescriptorSetAndBinding& descriptor_set_binding) const {
|
||||
return descriptor_set_binding.descriptor_set == descriptor_set &&
|
||||
descriptor_set_binding.binding == binding;
|
||||
}
|
||||
};
|
||||
|
||||
// See optimizer.hpp for documentation.
|
||||
class ConvertToSampledImagePass : public Pass {
|
||||
public:
|
||||
// Hashing functor for the pair of descriptor set and binding.
|
||||
struct DescriptorSetAndBindingHash {
|
||||
size_t operator()(
|
||||
const DescriptorSetAndBinding& descriptor_set_binding) const {
|
||||
return std::hash<uint32_t>()(descriptor_set_binding.descriptor_set) ^
|
||||
std::hash<uint32_t>()(descriptor_set_binding.binding);
|
||||
}
|
||||
};
|
||||
|
||||
using SetOfDescriptorSetAndBindingPairs =
|
||||
std::unordered_set<DescriptorSetAndBinding, DescriptorSetAndBindingHash>;
|
||||
using DescriptorSetBindingToInstruction =
|
||||
std::unordered_map<DescriptorSetAndBinding, Instruction*,
|
||||
DescriptorSetAndBindingHash>;
|
||||
|
||||
explicit ConvertToSampledImagePass(
|
||||
const std::vector<DescriptorSetAndBinding>& descriptor_set_binding_pairs)
|
||||
: descriptor_set_binding_pairs_(descriptor_set_binding_pairs.begin(),
|
||||
descriptor_set_binding_pairs.end()) {}
|
||||
|
||||
const char* name() const override { return "convert-to-sampled-image"; }
|
||||
Status Process() override;
|
||||
|
||||
// Parses the given null-terminated C string to get a vector of descriptor set
|
||||
// and binding pairs. Returns a unique pointer to the vector of descriptor set
|
||||
// and binding pairs built from the given |str| on success. Returns a nullptr
|
||||
// if the given string is not valid for building the vector of pairs.
|
||||
// A valid string for building the vector of pairs should follow the rule
|
||||
// below:
|
||||
//
|
||||
// "<descriptor set>:<binding> <descriptor set>:<binding> ..."
|
||||
// Example:
|
||||
// "3:5 2:1 0:4"
|
||||
//
|
||||
// Entries are separated with blank spaces (i.e.:' ', '\n', '\r', '\t',
|
||||
// '\f', '\v'). Each entry corresponds to a descriptor set and binding pair.
|
||||
// Multiple spaces between, before or after entries are allowed. However,
|
||||
// spaces are not allowed within a descriptor set or binding.
|
||||
//
|
||||
// In each entry, the descriptor set and binding are separated by ':'.
|
||||
// Missing ':' in any entry is invalid. And it is invalid to have blank
|
||||
// spaces in between the descriptor set and ':' or ':' and the binding.
|
||||
//
|
||||
// <descriptor set>: the descriptor set.
|
||||
// The text must represent a valid uint32_t number.
|
||||
//
|
||||
// <binding>: the binding.
|
||||
// The text must represent a valid uint32_t number.
|
||||
static std::unique_ptr<std::vector<DescriptorSetAndBinding>>
|
||||
ParseDescriptorSetBindingPairsString(const char* str);
|
||||
|
||||
private:
|
||||
// Collects resources to convert to sampled image and saves them in
|
||||
// |descriptor_set_binding_pair_to_sampler| if the resource is a sampler and
|
||||
// saves them in |descriptor_set_binding_pair_to_image| if the resource is an
|
||||
// image. Returns false if two samplers or two images have the same descriptor
|
||||
// set and binding. Otherwise, returns true.
|
||||
bool CollectResourcesToConvert(
|
||||
DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler,
|
||||
DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image)
|
||||
const;
|
||||
|
||||
// Finds an OpDecorate with DescriptorSet decorating |inst| and another
|
||||
// OpDecorate with Binding decorating |inst|. Stores the descriptor set and
|
||||
// binding in |descriptor_set_binding|. Returns whether it successfully finds
|
||||
// the descriptor set and binding or not.
|
||||
bool GetDescriptorSetBinding(
|
||||
const Instruction& inst,
|
||||
DescriptorSetAndBinding* descriptor_set_binding) const;
|
||||
|
||||
// Returns whether |descriptor_set_binding| is a pair of a descriptor set
|
||||
// and a binding that we have to convert resources with it to a sampled image
|
||||
// or not.
|
||||
bool ShouldResourceBeConverted(
|
||||
const DescriptorSetAndBinding& descriptor_set_binding) const;
|
||||
|
||||
// Returns the pointee type of the type of variable |variable|. If |variable|
|
||||
// is not an OpVariable instruction, just returns nullptr.
|
||||
const analysis::Type* GetVariableType(const Instruction& variable) const;
|
||||
|
||||
// Returns the storage class of |variable|.
|
||||
SpvStorageClass 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;
|
||||
|
||||
// Finds OpImage* instructions using |image| or OpCopyObject instructions that
|
||||
// copy |image| and puts them in |uses|.
|
||||
void FindUsesOfImage(const Instruction* image,
|
||||
std::vector<Instruction*>* uses) const;
|
||||
|
||||
// Creates an OpImage instruction that extracts the image from the sampled
|
||||
// image |sampled_image|.
|
||||
Instruction* CreateImageExtraction(Instruction* sampled_image);
|
||||
|
||||
// Converts |image_variable| whose type is an image pointer to sampled image
|
||||
// type. Updates users of |image_variable| accordingly. If some instructions
|
||||
// e.g., OpImageRead use |image_variable| as an Image operand, creates an
|
||||
// image extracted from the sampled image using OpImage and replace the Image
|
||||
// operands of the users with the extracted image. If some OpSampledImage
|
||||
// instructions use |image_variable| and sampler whose descriptor set and
|
||||
// binding are the same with |image_variable|, just combines |image_variable|
|
||||
// and the sampler to a sampled image.
|
||||
Pass::Status UpdateImageVariableToSampledImage(
|
||||
Instruction* image_variable,
|
||||
const DescriptorSetAndBinding& descriptor_set_binding);
|
||||
|
||||
// Returns the id of type sampled image type whose image type is the one of
|
||||
// |image_variable|.
|
||||
uint32_t GetSampledImageTypeForImage(Instruction* image_variable);
|
||||
|
||||
// Moves |inst| next to the OpType* instruction with |type_id|.
|
||||
void MoveInstructionNextToType(Instruction* inst, uint32_t type_id);
|
||||
|
||||
// Converts |image_variable| whose type is an image pointer to sampled image
|
||||
// with the type id |sampled_image_type_id|. Returns whether it successfully
|
||||
// converts the type of |image_variable| or not.
|
||||
bool ConvertImageVariableToSampledImage(Instruction* image_variable,
|
||||
uint32_t sampled_image_type_id);
|
||||
|
||||
// Replaces |sampled_image_load| instruction used by OpImage* with the image
|
||||
// extracted from |sampled_image_load|. Returns the extracted image or nullptr
|
||||
// if it does not have uses.
|
||||
Instruction* UpdateImageUses(Instruction* sampled_image_load);
|
||||
|
||||
// Returns true if the sampler of |sampled_image_inst| is decorated by a
|
||||
// descriptor set and a binding |descriptor_set_binding|.
|
||||
bool IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
|
||||
Instruction* sampled_image_inst,
|
||||
const DescriptorSetAndBinding& descriptor_set_binding);
|
||||
|
||||
// Replaces OpSampledImage instructions using |image_load| with |image_load|
|
||||
// if the sampler of the OpSampledImage instruction has descriptor set and
|
||||
// binding |image_descriptor_set_binding|. Otherwise, replaces |image_load|
|
||||
// with |image_extraction|.
|
||||
void UpdateSampledImageUses(
|
||||
Instruction* image_load, Instruction* image_extraction,
|
||||
const DescriptorSetAndBinding& image_descriptor_set_binding);
|
||||
|
||||
// Checks the uses of |sampler_variable|. When a sampler is used by
|
||||
// OpSampledImage instruction, the corresponding image must be
|
||||
// |image_to_be_combined_with| that should be already converted to a sampled
|
||||
// image by UpdateImageVariableToSampledImage() method.
|
||||
Pass::Status CheckUsesOfSamplerVariable(
|
||||
const Instruction* sampler_variable,
|
||||
Instruction* image_to_be_combined_with);
|
||||
|
||||
// Returns true if Image operand of |sampled_image_inst| is the image of
|
||||
// |image_variable|.
|
||||
bool DoesSampledImageReferenceImage(Instruction* sampled_image_inst,
|
||||
Instruction* image_variable);
|
||||
|
||||
// A set of pairs of descriptor set and binding. If an image and/or a sampler
|
||||
// have a pair of descriptor set and binding that is an element of
|
||||
// |descriptor_set_binding_pairs_|, they/it will be converted to a sampled
|
||||
// image by this pass.
|
||||
const SetOfDescriptorSetAndBindingPairs descriptor_set_binding_pairs_;
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
|
||||
91
3rdparty/spirv-tools/source/opt/dataflow.cpp
vendored
Normal file
91
3rdparty/spirv-tools/source/opt/dataflow.cpp
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2021 Google LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/opt/dataflow.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
bool DataFlowAnalysis::Enqueue(Instruction* inst) {
|
||||
bool& is_enqueued = on_worklist_[inst];
|
||||
if (is_enqueued) return false;
|
||||
is_enqueued = true;
|
||||
worklist_.push(inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
DataFlowAnalysis::VisitResult DataFlowAnalysis::RunOnce(
|
||||
Function* function, bool is_first_iteration) {
|
||||
InitializeWorklist(function, is_first_iteration);
|
||||
VisitResult ret = VisitResult::kResultFixed;
|
||||
while (!worklist_.empty()) {
|
||||
Instruction* top = worklist_.front();
|
||||
worklist_.pop();
|
||||
on_worklist_[top] = false;
|
||||
VisitResult result = Visit(top);
|
||||
if (result == VisitResult::kResultChanged) {
|
||||
EnqueueSuccessors(top);
|
||||
ret = VisitResult::kResultChanged;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DataFlowAnalysis::Run(Function* function) {
|
||||
VisitResult result = RunOnce(function, true);
|
||||
while (result == VisitResult::kResultChanged) {
|
||||
result = RunOnce(function, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ForwardDataFlowAnalysis::InitializeWorklist(Function* function,
|
||||
bool /*is_first_iteration*/) {
|
||||
context().cfg()->ForEachBlockInReversePostOrder(
|
||||
function->entry().get(), [this](BasicBlock* bb) {
|
||||
if (label_position_ == LabelPosition::kLabelsOnly) {
|
||||
Enqueue(bb->GetLabelInst());
|
||||
return;
|
||||
}
|
||||
if (label_position_ == LabelPosition::kLabelsAtBeginning) {
|
||||
Enqueue(bb->GetLabelInst());
|
||||
}
|
||||
for (Instruction& inst : *bb) {
|
||||
Enqueue(&inst);
|
||||
}
|
||||
if (label_position_ == LabelPosition::kLabelsAtEnd) {
|
||||
Enqueue(bb->GetLabelInst());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ForwardDataFlowAnalysis::EnqueueUsers(Instruction* inst) {
|
||||
context().get_def_use_mgr()->ForEachUser(
|
||||
inst, [this](Instruction* user) { Enqueue(user); });
|
||||
}
|
||||
|
||||
void ForwardDataFlowAnalysis::EnqueueBlockSuccessors(Instruction* inst) {
|
||||
if (inst->opcode() != SpvOpLabel) return;
|
||||
context()
|
||||
.cfg()
|
||||
->block(inst->result_id())
|
||||
->ForEachSuccessorLabel([this](uint32_t* label) {
|
||||
Enqueue(context().cfg()->block(*label)->GetLabelInst());
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
148
3rdparty/spirv-tools/source/opt/dataflow.h
vendored
Normal file
148
3rdparty/spirv-tools/source/opt/dataflow.h
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2021 Google LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_OPT_DATAFLOW_H_
|
||||
#define SOURCE_OPT_DATAFLOW_H_
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// Generic data-flow analysis.
|
||||
// Maintains a worklist of instructions to process and processes them in a
|
||||
// specified order. See also ForwardDataFlowAnalysis, which is specialized for
|
||||
// forward data-flow analysis.
|
||||
class DataFlowAnalysis {
|
||||
public:
|
||||
// The result of a |Visit| operation on an instruction.
|
||||
// This is used to determine when analysis has reached a fixpoint.
|
||||
enum class VisitResult {
|
||||
// The analysis result for this instruction has changed.
|
||||
// This means that any instructions that depend on it (its successors) must
|
||||
// be recomputed.
|
||||
kResultChanged,
|
||||
// The analysis result for this instruction has not changed.
|
||||
// When all visit operations return |kResultFixed|, the analysis has reached
|
||||
// a fixpoint (converged).
|
||||
kResultFixed,
|
||||
};
|
||||
|
||||
virtual ~DataFlowAnalysis() {}
|
||||
|
||||
// Run this analysis on a given function.
|
||||
// For analyses which work interprocedurally, |function| may be ignored.
|
||||
void Run(Function* function);
|
||||
|
||||
protected:
|
||||
DataFlowAnalysis(IRContext& context) : context_(context) {}
|
||||
|
||||
// Initialize the worklist for a given function.
|
||||
// |is_first_iteration| is true on the first call to |Run| and false
|
||||
// afterwards. All subsequent runs are only necessary to check if the analysis
|
||||
// has converged; if |EnqueueSuccessors| is complete, |InitializeWorklist|
|
||||
// should do nothing after the first iteration.
|
||||
virtual void InitializeWorklist(Function* function,
|
||||
bool is_first_iteration) = 0;
|
||||
|
||||
// Enqueues the successors (instructions which use the analysis result) of
|
||||
// |inst|. This is not required to be complete, but convergence is faster when
|
||||
// it is. This is called whenever |Visit| returns |kResultChanged|.
|
||||
virtual void EnqueueSuccessors(Instruction* inst) = 0;
|
||||
|
||||
// Visits the given instruction, recomputing the analysis result. This is
|
||||
// called once per instruction queued in |InitializeWorklist| and afterward
|
||||
// when a predecessor is changed, through |EnqueueSuccessors|.
|
||||
virtual VisitResult Visit(Instruction* inst) = 0;
|
||||
|
||||
// Enqueues the given instruction to be visited. Ignored if already in the
|
||||
// worklist.
|
||||
bool Enqueue(Instruction* inst);
|
||||
|
||||
IRContext& context() { return context_; }
|
||||
|
||||
private:
|
||||
// Runs one pass, calling |InitializeWorklist| and then iterating through the
|
||||
// worklist until all fixed.
|
||||
VisitResult RunOnce(Function* function, bool is_first_iteration);
|
||||
|
||||
IRContext& context_;
|
||||
std::unordered_map<Instruction*, bool> on_worklist_;
|
||||
// The worklist, which contains the list of instructions to be visited.
|
||||
//
|
||||
// The choice of data structure was influenced by the data in "Iterative
|
||||
// Data-flow Analysis, Revisited" (Cooper et al, 2002).
|
||||
// https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.125.1549&rep=rep1&type=pdf
|
||||
// The paper shows that the overall performance benefit of a priority queue
|
||||
// over a regular queue or stack is relatively small (or negative).
|
||||
//
|
||||
// A queue has the advantage that nodes are visited in the same order they are
|
||||
// enqueued, which relieves the analysis from inserting nodes "backwards", for
|
||||
// example in worklist initialization. Also, as the paper claims that sorting
|
||||
// successors does not improve runtime, we can use a single queue which is
|
||||
// modified during iteration.
|
||||
std::queue<Instruction*> worklist_;
|
||||
};
|
||||
|
||||
// A generic data flow analysis, specialized for forward analysis.
|
||||
class ForwardDataFlowAnalysis : public DataFlowAnalysis {
|
||||
public:
|
||||
// Indicates where labels should be in the worklist RPO ordering.
|
||||
enum class LabelPosition {
|
||||
// Labels should be placed at the beginning of their blocks.
|
||||
kLabelsAtBeginning,
|
||||
// Labels should be placed at the end of their blocks.
|
||||
kLabelsAtEnd,
|
||||
// Labels should not be in the worklist.
|
||||
kNoLabels,
|
||||
// Only labels should be placed in the worklist.
|
||||
kLabelsOnly,
|
||||
};
|
||||
|
||||
ForwardDataFlowAnalysis(IRContext& context, LabelPosition label_position)
|
||||
: DataFlowAnalysis(context), label_position_(label_position) {}
|
||||
|
||||
protected:
|
||||
// Initializes the worklist in reverse postorder, regardless of
|
||||
// |is_first_iteration|. Labels are placed according to the label position
|
||||
// specified in the constructor.
|
||||
void InitializeWorklist(Function* function, bool is_first_iteration) override;
|
||||
|
||||
// Enqueues the users and block successors of the given instruction.
|
||||
// See |EnqueueUsers| and |EnqueueBlockSuccessors|.
|
||||
void EnqueueSuccessors(Instruction* inst) override {
|
||||
EnqueueUsers(inst);
|
||||
EnqueueBlockSuccessors(inst);
|
||||
}
|
||||
|
||||
// Enqueues the users of the given instruction.
|
||||
void EnqueueUsers(Instruction* inst);
|
||||
|
||||
// Enqueues the labels of the successors of the block corresponding to the
|
||||
// given label instruction. Does nothing for other instructions.
|
||||
void EnqueueBlockSuccessors(Instruction* inst);
|
||||
|
||||
private:
|
||||
LabelPosition label_position_;
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_OPT_DATAFLOW_H_
|
||||
@@ -18,12 +18,15 @@
|
||||
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
// Constants for OpenCL.DebugInfo.100 extension instructions.
|
||||
// Constants for OpenCL.DebugInfo.100 & NonSemantic.Vulkan.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 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;
|
||||
@@ -46,8 +49,8 @@ namespace {
|
||||
|
||||
void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) {
|
||||
assert(dbg_inlined_at);
|
||||
assert(dbg_inlined_at->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugInlinedAt);
|
||||
assert(dbg_inlined_at->GetCommonDebugOpcode() ==
|
||||
CommonDebugInfoDebugInlinedAt);
|
||||
if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) {
|
||||
dbg_inlined_at->AddOperand(
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inlined_operand}});
|
||||
@@ -59,8 +62,8 @@ void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) {
|
||||
|
||||
uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) {
|
||||
assert(dbg_inlined_at);
|
||||
assert(dbg_inlined_at->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugInlinedAt);
|
||||
assert(dbg_inlined_at->GetCommonDebugOpcode() ==
|
||||
CommonDebugInfoDebugInlinedAt);
|
||||
if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex)
|
||||
return kNoInlinedAt;
|
||||
return dbg_inlined_at->GetSingleWordOperand(
|
||||
@@ -68,8 +71,7 @@ uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) {
|
||||
}
|
||||
|
||||
bool IsEmptyDebugExpression(Instruction* instr) {
|
||||
return instr->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugExpression &&
|
||||
return (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression) &&
|
||||
instr->NumOperands() == kDebugExpressOperandOperationIndex;
|
||||
}
|
||||
|
||||
@@ -79,43 +81,63 @@ DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) {
|
||||
AnalyzeDebugInsts(*c->module());
|
||||
}
|
||||
|
||||
uint32_t DebugInfoManager::GetDbgSetImportId() {
|
||||
uint32_t setId =
|
||||
context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
|
||||
if (setId == 0) {
|
||||
setId =
|
||||
context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo();
|
||||
}
|
||||
return setId;
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::GetDbgInst(uint32_t id) {
|
||||
auto dbg_inst_it = id_to_dbg_inst_.find(id);
|
||||
return dbg_inst_it == id_to_dbg_inst_.end() ? nullptr : dbg_inst_it->second;
|
||||
}
|
||||
|
||||
void DebugInfoManager::RegisterDbgInst(Instruction* inst) {
|
||||
assert(
|
||||
inst->NumInOperands() != 0 &&
|
||||
context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() ==
|
||||
inst->GetInOperand(0).words[0] &&
|
||||
"Given instruction is not a debug instruction");
|
||||
assert(inst->NumInOperands() != 0 &&
|
||||
(GetDbgSetImportId() == inst->GetInOperand(0).words[0]) &&
|
||||
"Given instruction is not a debug instruction");
|
||||
id_to_dbg_inst_[inst->result_id()] = inst;
|
||||
}
|
||||
|
||||
void DebugInfoManager::RegisterDbgFunction(Instruction* inst) {
|
||||
assert(inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction &&
|
||||
"inst is not a DebugFunction");
|
||||
auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
|
||||
// Do not register function that has been optimized away
|
||||
auto fn_inst = GetDbgInst(fn_id);
|
||||
if (fn_inst != nullptr) {
|
||||
assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugInfoNone);
|
||||
return;
|
||||
if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
|
||||
auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
|
||||
// Do not register function that has been optimized away.
|
||||
auto fn_inst = GetDbgInst(fn_id);
|
||||
if (fn_inst != nullptr) {
|
||||
assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugInfoNone);
|
||||
return;
|
||||
}
|
||||
assert(
|
||||
fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() &&
|
||||
"Register DebugFunction for a function that already has DebugFunction");
|
||||
fn_id_to_dbg_fn_[fn_id] = inst;
|
||||
} else if (inst->GetVulkan100DebugOpcode() ==
|
||||
NonSemanticVulkanDebugInfo100DebugFunctionDefinition) {
|
||||
auto fn_id = inst->GetSingleWordOperand(
|
||||
kDebugFunctionDefinitionOperandOpFunctionIndex);
|
||||
auto fn_inst = GetDbgInst(inst->GetSingleWordOperand(
|
||||
kDebugFunctionDefinitionOperandDebugFunctionIndex));
|
||||
assert(fn_inst && fn_inst->GetVulkan100DebugOpcode() ==
|
||||
NonSemanticVulkanDebugInfo100DebugFunction);
|
||||
assert(fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() &&
|
||||
"Register DebugFunctionDefinition for a function that already has "
|
||||
"DebugFunctionDefinition");
|
||||
fn_id_to_dbg_fn_[fn_id] = fn_inst;
|
||||
} else {
|
||||
assert(false && "inst is not a DebugFunction");
|
||||
}
|
||||
assert(
|
||||
fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() &&
|
||||
"Register DebugFunction for a function that already has DebugFunction");
|
||||
fn_id_to_dbg_fn_[fn_id] = inst;
|
||||
}
|
||||
|
||||
void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
|
||||
Instruction* dbg_declare) {
|
||||
assert(dbg_declare->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugDeclare ||
|
||||
dbg_declare->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugValue);
|
||||
assert(dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
|
||||
dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugValue);
|
||||
auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_id);
|
||||
if (dbg_decl_itr == var_id_to_dbg_decl_.end()) {
|
||||
var_id_to_dbg_decl_[var_id] = {dbg_declare};
|
||||
@@ -126,27 +148,36 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
|
||||
|
||||
uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
|
||||
const DebugScope& scope) {
|
||||
if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() ==
|
||||
0)
|
||||
return kNoInlinedAt;
|
||||
uint32_t setId = GetDbgSetImportId();
|
||||
|
||||
if (setId == 0) return kNoInlinedAt;
|
||||
|
||||
spv_operand_type_t line_number_type =
|
||||
spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER;
|
||||
|
||||
// In NonSemantic.Vulkan.DebugInfo.100, all constants are IDs of OpConstant,
|
||||
// not literals.
|
||||
if (setId ==
|
||||
context()->get_feature_mgr()->GetExtInstImportId_Vulkan100DebugInfo())
|
||||
line_number_type = spv_operand_type_t::SPV_OPERAND_TYPE_ID;
|
||||
|
||||
uint32_t line_number = 0;
|
||||
if (line == nullptr) {
|
||||
auto* lexical_scope_inst = GetDbgInst(scope.GetLexicalScope());
|
||||
if (lexical_scope_inst == nullptr) return kNoInlinedAt;
|
||||
OpenCLDebugInfo100Instructions debug_opcode =
|
||||
lexical_scope_inst->GetOpenCL100DebugOpcode();
|
||||
CommonDebugInfoInstructions debug_opcode =
|
||||
lexical_scope_inst->GetCommonDebugOpcode();
|
||||
switch (debug_opcode) {
|
||||
case OpenCLDebugInfo100DebugFunction:
|
||||
case CommonDebugInfoDebugFunction:
|
||||
line_number = lexical_scope_inst->GetSingleWordOperand(
|
||||
kLineOperandIndexDebugFunction);
|
||||
break;
|
||||
case OpenCLDebugInfo100DebugLexicalBlock:
|
||||
case CommonDebugInfoDebugLexicalBlock:
|
||||
line_number = lexical_scope_inst->GetSingleWordOperand(
|
||||
kLineOperandIndexDebugLexicalBlock);
|
||||
break;
|
||||
case OpenCLDebugInfo100DebugTypeComposite:
|
||||
case OpenCLDebugInfo100DebugCompilationUnit:
|
||||
case CommonDebugInfoDebugTypeComposite:
|
||||
case CommonDebugInfoDebugCompilationUnit:
|
||||
assert(false &&
|
||||
"DebugTypeComposite and DebugCompilationUnit are lexical "
|
||||
"scopes, but we inline functions into a function or a block "
|
||||
@@ -161,6 +192,13 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
|
||||
}
|
||||
} else {
|
||||
line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex);
|
||||
|
||||
// If we need the line number as an ID, generate that constant now.
|
||||
if (line_number_type == spv_operand_type_t::SPV_OPERAND_TYPE_ID) {
|
||||
uint32_t line_id =
|
||||
context()->get_constant_mgr()->GetUIntConst(line_number);
|
||||
line_number = line_id;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t result_id = context()->TakeNextId();
|
||||
@@ -168,13 +206,10 @@ uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
result_id,
|
||||
{
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {setId}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugInlinedAt)}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}},
|
||||
{static_cast<uint32_t>(CommonDebugInfoDebugInlinedAt)}},
|
||||
{line_number_type, {line_number}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetLexicalScope()}},
|
||||
}));
|
||||
// |scope| already has DebugInlinedAt. We put the existing DebugInlinedAt
|
||||
@@ -257,19 +292,34 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
|
||||
if (deref_operation_ != nullptr) return deref_operation_;
|
||||
|
||||
uint32_t result_id = context()->TakeNextId();
|
||||
std::unique_ptr<Instruction> deref_operation(new Instruction(
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
result_id,
|
||||
{
|
||||
{SPV_OPERAND_TYPE_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugOperation)}},
|
||||
{SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
|
||||
}));
|
||||
std::unique_ptr<Instruction> deref_operation;
|
||||
|
||||
if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
|
||||
deref_operation = std::unique_ptr<Instruction>(new Instruction(
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
result_id,
|
||||
{
|
||||
{SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
|
||||
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugOperation)}},
|
||||
{SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
|
||||
}));
|
||||
} else {
|
||||
uint32_t deref_id = context()->get_constant_mgr()->GetUIntConst(
|
||||
NonSemanticVulkanDebugInfo100Deref);
|
||||
|
||||
deref_operation = std::unique_ptr<Instruction>(
|
||||
new Instruction(context(), SpvOpExtInst,
|
||||
context()->get_type_mgr()->GetVoidTypeId(), result_id,
|
||||
{
|
||||
{SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
|
||||
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(
|
||||
NonSemanticVulkanDebugInfo100DebugOperation)}},
|
||||
{SPV_OPERAND_TYPE_ID, {deref_id}},
|
||||
}));
|
||||
}
|
||||
|
||||
// Add to the front of |ext_inst_debuginfo_|.
|
||||
deref_operation_ =
|
||||
@@ -283,8 +333,7 @@ Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::DerefDebugExpression(Instruction* dbg_expr) {
|
||||
assert(dbg_expr->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugExpression);
|
||||
assert(dbg_expr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression);
|
||||
std::unique_ptr<Instruction> deref_expr(dbg_expr->Clone(context()));
|
||||
deref_expr->SetResultId(context()->TakeNextId());
|
||||
deref_expr->InsertOperand(
|
||||
@@ -306,12 +355,9 @@ Instruction* DebugInfoManager::GetDebugInfoNone() {
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
result_id,
|
||||
{
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugInfoNone)}},
|
||||
{static_cast<uint32_t>(CommonDebugInfoDebugInfoNone)}},
|
||||
}));
|
||||
|
||||
// Add to the front of |ext_inst_debuginfo_|.
|
||||
@@ -333,12 +379,9 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() {
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
result_id,
|
||||
{
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugExpression)}},
|
||||
{static_cast<uint32_t>(CommonDebugInfoDebugExpression)}},
|
||||
}));
|
||||
|
||||
// Add to the front of |ext_inst_debuginfo_|.
|
||||
@@ -355,8 +398,7 @@ Instruction* DebugInfoManager::GetEmptyDebugExpression() {
|
||||
Instruction* DebugInfoManager::GetDebugInlinedAt(uint32_t dbg_inlined_at_id) {
|
||||
auto* inlined_at = GetDbgInst(dbg_inlined_at_id);
|
||||
if (inlined_at == nullptr) return nullptr;
|
||||
if (inlined_at->GetOpenCL100DebugOpcode() !=
|
||||
OpenCLDebugInfo100DebugInlinedAt) {
|
||||
if (inlined_at->GetCommonDebugOpcode() != CommonDebugInfoDebugInlinedAt) {
|
||||
return nullptr;
|
||||
}
|
||||
return inlined_at;
|
||||
@@ -403,23 +445,23 @@ bool DebugInfoManager::KillDebugDeclares(uint32_t variable_id) {
|
||||
uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) {
|
||||
auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope);
|
||||
assert(dbg_scope_itr != id_to_dbg_inst_.end());
|
||||
OpenCLDebugInfo100Instructions debug_opcode =
|
||||
dbg_scope_itr->second->GetOpenCL100DebugOpcode();
|
||||
CommonDebugInfoInstructions debug_opcode =
|
||||
dbg_scope_itr->second->GetCommonDebugOpcode();
|
||||
uint32_t parent_scope = kNoDebugScope;
|
||||
switch (debug_opcode) {
|
||||
case OpenCLDebugInfo100DebugFunction:
|
||||
case CommonDebugInfoDebugFunction:
|
||||
parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
|
||||
kDebugFunctionOperandParentIndex);
|
||||
break;
|
||||
case OpenCLDebugInfo100DebugLexicalBlock:
|
||||
case CommonDebugInfoDebugLexicalBlock:
|
||||
parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
|
||||
kDebugLexicalBlockOperandParentIndex);
|
||||
break;
|
||||
case OpenCLDebugInfo100DebugTypeComposite:
|
||||
case CommonDebugInfoDebugTypeComposite:
|
||||
parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
|
||||
kDebugTypeCompositeOperandParentIndex);
|
||||
break;
|
||||
case OpenCLDebugInfo100DebugCompilationUnit:
|
||||
case CommonDebugInfoDebugCompilationUnit:
|
||||
// DebugCompilationUnit does not have a parent scope.
|
||||
break;
|
||||
default:
|
||||
@@ -513,8 +555,7 @@ Instruction* DebugInfoManager::AddDebugValueForDecl(
|
||||
|
||||
std::unique_ptr<Instruction> dbg_val(dbg_decl->Clone(context()));
|
||||
dbg_val->SetResultId(context()->TakeNextId());
|
||||
dbg_val->SetInOperand(kExtInstInstructionInIdx,
|
||||
{OpenCLDebugInfo100DebugValue});
|
||||
dbg_val->SetInOperand(kExtInstInstructionInIdx, {CommonDebugInfoDebugValue});
|
||||
dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id});
|
||||
dbg_val->SetOperand(kDebugValueOperandExpressionIndex,
|
||||
{GetEmptyDebugExpression()->result_id()});
|
||||
@@ -532,9 +573,20 @@ Instruction* DebugInfoManager::AddDebugValueForDecl(
|
||||
return added_dbg_val;
|
||||
}
|
||||
|
||||
uint32_t DebugInfoManager::GetVulkanDebugOperation(Instruction* inst) {
|
||||
assert(inst->GetVulkan100DebugOpcode() ==
|
||||
NonSemanticVulkanDebugInfo100DebugOperation &&
|
||||
"inst must be Vulkan DebugOperation");
|
||||
return context()
|
||||
->get_constant_mgr()
|
||||
->GetConstantFromInst(context()->get_def_use_mgr()->GetDef(
|
||||
inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex)))
|
||||
->GetU32();
|
||||
}
|
||||
|
||||
uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
|
||||
Instruction* inst) {
|
||||
if (inst->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugValue) return 0;
|
||||
if (inst->GetCommonDebugOpcode() != CommonDebugInfoDebugValue) return 0;
|
||||
|
||||
auto* expr =
|
||||
GetDbgInst(inst->GetSingleWordOperand(kDebugValueOperandExpressionIndex));
|
||||
@@ -544,9 +596,19 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
|
||||
auto* operation = GetDbgInst(
|
||||
expr->GetSingleWordOperand(kDebugExpressOperandOperationIndex));
|
||||
if (operation == nullptr) return 0;
|
||||
if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) !=
|
||||
OpenCLDebugInfo100Deref) {
|
||||
return 0;
|
||||
|
||||
// OpenCL.DebugInfo.100 contains a literal for the operation, Vulkan uses an
|
||||
// OpConstant.
|
||||
if (inst->IsOpenCL100DebugInstr()) {
|
||||
if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) !=
|
||||
OpenCLDebugInfo100Deref) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
uint32_t operation_const = GetVulkanDebugOperation(operation);
|
||||
if (operation_const != NonSemanticVulkanDebugInfo100Deref) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t var_id =
|
||||
@@ -567,8 +629,8 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
|
||||
}
|
||||
|
||||
bool DebugInfoManager::IsDebugDeclare(Instruction* instr) {
|
||||
if (!instr->IsOpenCL100DebugInstr()) return false;
|
||||
return instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare ||
|
||||
if (!instr->IsCommonDebugInstr()) return false;
|
||||
return instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
|
||||
GetVariableIdOfDebugValueUsedForDeclare(instr) != 0;
|
||||
}
|
||||
|
||||
@@ -615,14 +677,13 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
|
||||
users.insert(inst);
|
||||
}
|
||||
|
||||
if (!inst->IsOpenCL100DebugInstr()) return;
|
||||
if (!inst->IsCommonDebugInstr()) return;
|
||||
|
||||
RegisterDbgInst(inst);
|
||||
|
||||
if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
|
||||
assert(GetDebugFunction(inst->GetSingleWordOperand(
|
||||
kDebugFunctionOperandFunctionIndex)) == nullptr &&
|
||||
"Two DebugFunction instruction exists for a single OpFunction.");
|
||||
if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction ||
|
||||
inst->GetVulkan100DebugOpcode() ==
|
||||
NonSemanticVulkanDebugInfo100DebugFunctionDefinition) {
|
||||
RegisterDbgFunction(inst);
|
||||
}
|
||||
|
||||
@@ -633,8 +694,17 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
|
||||
deref_operation_ = inst;
|
||||
}
|
||||
|
||||
if (deref_operation_ == nullptr &&
|
||||
inst->GetVulkan100DebugOpcode() ==
|
||||
NonSemanticVulkanDebugInfo100DebugOperation) {
|
||||
uint32_t operation_const = GetVulkanDebugOperation(inst);
|
||||
if (operation_const == NonSemanticVulkanDebugInfo100Deref) {
|
||||
deref_operation_ = inst;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_info_none_inst_ == nullptr &&
|
||||
inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
|
||||
inst->GetCommonDebugOpcode() == CommonDebugInfoDebugInfoNone) {
|
||||
debug_info_none_inst_ = inst;
|
||||
}
|
||||
|
||||
@@ -642,7 +712,7 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
|
||||
empty_debug_expr_inst_ = inst;
|
||||
}
|
||||
|
||||
if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) {
|
||||
if (inst->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) {
|
||||
uint32_t var_id =
|
||||
inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
|
||||
RegisterDbgDeclare(var_id, inst);
|
||||
@@ -655,8 +725,8 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
|
||||
|
||||
void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
|
||||
Instruction* dbg_global_var, Instruction* local_var) {
|
||||
if (dbg_global_var->GetOpenCL100DebugOpcode() !=
|
||||
OpenCLDebugInfo100DebugGlobalVariable) {
|
||||
if (dbg_global_var->GetCommonDebugOpcode() !=
|
||||
CommonDebugInfoDebugGlobalVariable) {
|
||||
return;
|
||||
}
|
||||
assert(local_var->opcode() == SpvOpVariable ||
|
||||
@@ -664,7 +734,7 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
|
||||
|
||||
// Convert |dbg_global_var| to DebugLocalVariable
|
||||
dbg_global_var->SetInOperand(kExtInstInstructionInIdx,
|
||||
{OpenCLDebugInfo100DebugLocalVariable});
|
||||
{CommonDebugInfoDebugLocalVariable});
|
||||
auto flags = dbg_global_var->GetSingleWordOperand(
|
||||
kDebugGlobalVariableOperandFlagsIndex);
|
||||
for (uint32_t i = dbg_global_var->NumInOperands() - 1;
|
||||
@@ -680,12 +750,9 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
context()->TakeNextId(),
|
||||
{
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugDeclare)}},
|
||||
{static_cast<uint32_t>(CommonDebugInfoDebugDeclare)}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{dbg_global_var->result_id()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {local_var->result_id()}},
|
||||
@@ -713,7 +780,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
|
||||
// list.
|
||||
if (empty_debug_expr_inst_ != nullptr &&
|
||||
empty_debug_expr_inst_->PreviousNode() != nullptr &&
|
||||
empty_debug_expr_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
|
||||
empty_debug_expr_inst_->PreviousNode()->IsCommonDebugInstr()) {
|
||||
empty_debug_expr_inst_->InsertBefore(
|
||||
&*context()->module()->ext_inst_debuginfo_begin());
|
||||
}
|
||||
@@ -722,7 +789,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
|
||||
// list.
|
||||
if (debug_info_none_inst_ != nullptr &&
|
||||
debug_info_none_inst_->PreviousNode() != nullptr &&
|
||||
debug_info_none_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
|
||||
debug_info_none_inst_->PreviousNode()->IsCommonDebugInstr()) {
|
||||
debug_info_none_inst_->InsertBefore(
|
||||
&*context()->module()->ext_inst_debuginfo_begin());
|
||||
}
|
||||
@@ -740,7 +807,7 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
inlinedat_id_to_users_itr->second.erase(instr);
|
||||
}
|
||||
|
||||
if (instr == nullptr || !instr->IsOpenCL100DebugInstr()) {
|
||||
if (instr == nullptr || !instr->IsCommonDebugInstr()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -751,9 +818,15 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
instr->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
|
||||
fn_id_to_dbg_fn_.erase(fn_id);
|
||||
}
|
||||
if (instr->GetVulkan100DebugOpcode() ==
|
||||
NonSemanticVulkanDebugInfo100DebugFunction) {
|
||||
auto fn_id = instr->GetSingleWordOperand(
|
||||
kDebugFunctionDefinitionOperandOpFunctionIndex);
|
||||
fn_id_to_dbg_fn_.erase(fn_id);
|
||||
}
|
||||
|
||||
if (instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare ||
|
||||
instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue) {
|
||||
if (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
|
||||
instr->GetCommonDebugOpcode() == CommonDebugInfoDebugValue) {
|
||||
auto var_or_value_id =
|
||||
instr->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
|
||||
auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_or_value_id);
|
||||
@@ -767,6 +840,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
|
||||
dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
|
||||
++dbg_instr_itr) {
|
||||
// OpenCL.DebugInfo.100 contains the operation as a literal operand, in
|
||||
// Vulkan it's referenced as an OpConstant.
|
||||
if (instr != &*dbg_instr_itr &&
|
||||
dbg_instr_itr->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugOperation &&
|
||||
@@ -775,6 +850,15 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
OpenCLDebugInfo100Deref) {
|
||||
deref_operation_ = &*dbg_instr_itr;
|
||||
break;
|
||||
} else if (instr != &*dbg_instr_itr &&
|
||||
dbg_instr_itr->GetVulkan100DebugOpcode() ==
|
||||
NonSemanticVulkanDebugInfo100DebugOperation) {
|
||||
uint32_t operation_const = GetVulkanDebugOperation(&*dbg_instr_itr);
|
||||
|
||||
if (operation_const == NonSemanticVulkanDebugInfo100Deref) {
|
||||
deref_operation_ = &*dbg_instr_itr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -784,9 +868,8 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
|
||||
for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
|
||||
dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
|
||||
++dbg_instr_itr) {
|
||||
if (instr != &*dbg_instr_itr &&
|
||||
dbg_instr_itr->GetOpenCL100DebugOpcode() ==
|
||||
OpenCLDebugInfo100DebugInfoNone) {
|
||||
if (instr != &*dbg_instr_itr && dbg_instr_itr->GetCommonDebugOpcode() ==
|
||||
CommonDebugInfoDebugInfoNone) {
|
||||
debug_info_none_inst_ = &*dbg_instr_itr;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ class DebugInlinedAtContext {
|
||||
std::unordered_map<uint32_t, uint32_t> callee_inlined_at2chain_;
|
||||
};
|
||||
|
||||
// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 extension
|
||||
// instructions.
|
||||
// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 and
|
||||
// NonSemantic.Vulkan.DebugInfo.100 extension instructions.
|
||||
class DebugInfoManager {
|
||||
public:
|
||||
// Constructs a debug information manager from the given |context|.
|
||||
@@ -85,7 +85,7 @@ class DebugInfoManager {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
// Analyzes OpenCL.DebugInfo.100 instruction |dbg_inst|.
|
||||
// Analyzes DebugInfo instruction |dbg_inst|.
|
||||
void AnalyzeDebugInst(Instruction* dbg_inst);
|
||||
|
||||
// Creates new DebugInlinedAt and returns its id. Its line operand is the
|
||||
@@ -164,6 +164,9 @@ class DebugInfoManager {
|
||||
// Erases |instr| from data structures of this class.
|
||||
void ClearDebugInfo(Instruction* instr);
|
||||
|
||||
// Return the opcode for the Vulkan DebugOperation inst
|
||||
uint32_t GetVulkanDebugOperation(Instruction* inst);
|
||||
|
||||
// Returns the id of Value operand if |inst| is DebugValue who has Deref
|
||||
// operation and its Value operand is a result id of OpVariable with
|
||||
// Function storage class. Otherwise, returns 0.
|
||||
@@ -190,10 +193,13 @@ class DebugInfoManager {
|
||||
private:
|
||||
IRContext* context() { return context_; }
|
||||
|
||||
// Analyzes OpenCL.DebugInfo.100 instructions in the given |module| and
|
||||
// Analyzes DebugInfo instructions in the given |module| and
|
||||
// populates data structures in this class.
|
||||
void AnalyzeDebugInsts(Module& module);
|
||||
|
||||
// Get the DebugInfo ExtInstImport Id, or 0 if no DebugInfo is available.
|
||||
uint32_t GetDbgSetImportId();
|
||||
|
||||
// Returns the debug instruction whose id is |id|. Returns |nullptr| if one
|
||||
// does not exists.
|
||||
Instruction* GetDbgInst(uint32_t id);
|
||||
@@ -230,7 +236,7 @@ class DebugInfoManager {
|
||||
|
||||
IRContext* context_;
|
||||
|
||||
// Mapping from ids of OpenCL.DebugInfo.100 extension instructions
|
||||
// Mapping from ids of DebugInfo extension instructions.
|
||||
// to their Instruction instances.
|
||||
std::unordered_map<uint32_t, Instruction*> id_to_dbg_inst_;
|
||||
|
||||
|
||||
@@ -967,12 +967,11 @@ FoldingRule MergeDivMulArithmetic() {
|
||||
// Fold divides of a constant and a negation.
|
||||
// Cases:
|
||||
// (-x) / 2 = x / -2
|
||||
// 2 / (-x) = 2 / -x
|
||||
// 2 / (-x) = -2 / x
|
||||
FoldingRule MergeDivNegateArithmetic() {
|
||||
return [](IRContext* context, Instruction* inst,
|
||||
const std::vector<const analysis::Constant*>& constants) {
|
||||
assert(inst->opcode() == SpvOpFDiv || inst->opcode() == SpvOpSDiv ||
|
||||
inst->opcode() == SpvOpUDiv);
|
||||
assert(inst->opcode() == SpvOpFDiv || inst->opcode() == SpvOpSDiv);
|
||||
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
|
||||
const analysis::Type* type =
|
||||
context->get_type_mgr()->GetType(inst->type_id());
|
||||
@@ -2572,8 +2571,6 @@ void FoldingRules::AddFoldingRules() {
|
||||
|
||||
rules_[SpvOpStore].push_back(StoringUndef());
|
||||
|
||||
rules_[SpvOpUDiv].push_back(MergeDivNegateArithmetic());
|
||||
|
||||
rules_[SpvOpVectorShuffle].push_back(VectorShuffleFeedingShuffle());
|
||||
|
||||
rules_[SpvOpImageSampleImplicitLod].push_back(UpdateImageOperands());
|
||||
|
||||
27
3rdparty/spirv-tools/source/opt/optimizer.cpp
vendored
27
3rdparty/spirv-tools/source/opt/optimizer.cpp
vendored
@@ -499,6 +499,26 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
|
||||
RegisterPass(CreateAmdExtToKhrPass());
|
||||
} else if (pass_name == "interpolate-fixup") {
|
||||
RegisterPass(CreateInterpolateFixupPass());
|
||||
} else if (pass_name == "convert-to-sampled-image") {
|
||||
if (pass_args.size() > 0) {
|
||||
auto descriptor_set_binding_pairs =
|
||||
opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
|
||||
pass_args.c_str());
|
||||
if (!descriptor_set_binding_pairs) {
|
||||
Errorf(consumer(), nullptr, {},
|
||||
"Invalid argument for --convert-to-sampled-image: %s",
|
||||
pass_args.c_str());
|
||||
return false;
|
||||
}
|
||||
RegisterPass(CreateConvertToSampledImagePass(
|
||||
std::move(*descriptor_set_binding_pairs)));
|
||||
} else {
|
||||
Errorf(consumer(), nullptr, {},
|
||||
"Invalid pairs of descriptor set and binding '%s'. Expected a "
|
||||
"string of <descriptor set>:<binding> pairs.",
|
||||
pass_args.c_str());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Errorf(consumer(), nullptr, {},
|
||||
"Unknown flag '--%s'. Use --help for a list of valid flags",
|
||||
@@ -940,4 +960,11 @@ Optimizer::PassToken CreateInterpolateFixupPass() {
|
||||
MakeUnique<opt::InterpFixupPass>());
|
||||
}
|
||||
|
||||
Optimizer::PassToken CreateConvertToSampledImagePass(
|
||||
const std::vector<opt::DescriptorSetAndBinding>&
|
||||
descriptor_set_binding_pairs) {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
|
||||
}
|
||||
|
||||
} // namespace spvtools
|
||||
|
||||
1
3rdparty/spirv-tools/source/opt/passes.h
vendored
1
3rdparty/spirv-tools/source/opt/passes.h
vendored
@@ -26,6 +26,7 @@
|
||||
#include "source/opt/combine_access_chains.h"
|
||||
#include "source/opt/compact_ids_pass.h"
|
||||
#include "source/opt/convert_to_half_pass.h"
|
||||
#include "source/opt/convert_to_sampled_image_pass.h"
|
||||
#include "source/opt/copy_prop_arrays.h"
|
||||
#include "source/opt/dead_branch_elim_pass.h"
|
||||
#include "source/opt/dead_insert_elim_pass.h"
|
||||
|
||||
@@ -2846,7 +2846,7 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec allows BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
|
||||
<< " to be used only with GLCompute execution model. "
|
||||
<< " to be used only with GLCompute, MeshNV, or TaskNV execution model. "
|
||||
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
|
||||
referenced_from_inst, execution_model);
|
||||
}
|
||||
@@ -2928,7 +2928,7 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec allows BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
|
||||
<< " to be used only with GLCompute execution model. "
|
||||
<< " to be used only with GLCompute, MeshNV, or TaskNV execution model. "
|
||||
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
|
||||
referenced_from_inst, execution_model);
|
||||
}
|
||||
@@ -3070,14 +3070,16 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
|
||||
const Instruction& referenced_from_inst) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
for (const SpvExecutionModel execution_model : execution_models_) {
|
||||
if (execution_model != SpvExecutionModelGLCompute) {
|
||||
if (execution_model != SpvExecutionModelGLCompute &&
|
||||
execution_model != SpvExecutionModelTaskNV &&
|
||||
execution_model != SpvExecutionModelMeshNV) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
|
||||
<< _.VkErrorID(4425)
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec allows BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " to be used only with GLCompute execution model. "
|
||||
<< " to be used only with GLCompute, MeshNV, or TaskNV execution model. "
|
||||
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
|
||||
referenced_from_inst, execution_model);
|
||||
}
|
||||
@@ -4190,6 +4192,7 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
|
||||
case SpvBuiltInMeshViewIndicesNV:
|
||||
case SpvBuiltInBaryCoordNV:
|
||||
case SpvBuiltInBaryCoordNoPerspNV:
|
||||
case SpvBuiltInCurrentRayTimeNV:
|
||||
// No validation rules (for the moment).
|
||||
break;
|
||||
|
||||
|
||||
@@ -506,12 +506,10 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
|
||||
return recursive_status;
|
||||
// Check matrix stride.
|
||||
if (SpvOpTypeMatrix == opcode) {
|
||||
for (auto& decoration : vstate.id_decorations(id)) {
|
||||
if (SpvDecorationMatrixStride == decoration.dec_type() &&
|
||||
!IsAlignedTo(decoration.params()[0], alignment))
|
||||
return fail(memberIdx)
|
||||
<< "is a matrix with stride " << decoration.params()[0]
|
||||
<< " not satisfying alignment to " << alignment;
|
||||
const auto stride = constraint.matrix_stride;
|
||||
if (!IsAlignedTo(stride, alignment)) {
|
||||
return fail(memberIdx) << "is a matrix with stride " << stride
|
||||
<< " not satisfying alignment to " << alignment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ namespace spvtools {
|
||||
namespace val {
|
||||
namespace {
|
||||
|
||||
// Limit the number of checked locations to 4096. Multiplied by 4 to represent
|
||||
// all the components. This limit is set to be well beyond practical use cases.
|
||||
const uint32_t kMaxLocations = 4096 * 4;
|
||||
|
||||
// Returns true if \c inst is an input or output variable.
|
||||
bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) {
|
||||
if (is_spv_1_4) {
|
||||
@@ -347,6 +351,11 @@ spv_result_t GetLocationsForVariable(
|
||||
uint32_t num_components = NumConsumedComponents(_, sub_type);
|
||||
uint32_t array_location = location + (num_locations * array_idx);
|
||||
uint32_t start = array_location * 4;
|
||||
if (kMaxLocations <= start) {
|
||||
// Too many locations, give up.
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t end = (array_location + num_locations) * 4;
|
||||
if (num_components != 0) {
|
||||
start += component;
|
||||
@@ -416,6 +425,11 @@ spv_result_t GetLocationsForVariable(
|
||||
}
|
||||
|
||||
uint32_t start = location * 4;
|
||||
if (kMaxLocations <= start) {
|
||||
// Too many locations, give up.
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t end = (location + num_locations) * 4;
|
||||
if (num_components != 0) {
|
||||
start += component;
|
||||
@@ -454,6 +468,7 @@ spv_result_t ValidateLocations(ValidationState_t& _,
|
||||
std::unordered_set<uint32_t> input_locations;
|
||||
std::unordered_set<uint32_t> output_locations_index0;
|
||||
std::unordered_set<uint32_t> output_locations_index1;
|
||||
std::unordered_set<uint32_t> seen;
|
||||
for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
|
||||
auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
|
||||
auto interface_var = _.FindDef(interface_id);
|
||||
@@ -462,6 +477,11 @@ spv_result_t ValidateLocations(ValidationState_t& _,
|
||||
storage_class != SpvStorageClassOutput) {
|
||||
continue;
|
||||
}
|
||||
if (!seen.insert(interface_id).second) {
|
||||
// Pre-1.4 an interface variable could be listed multiple times in an
|
||||
// entry point. Validation for 1.4 or later is done elsewhere.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto locations = (storage_class == SpvStorageClassInput)
|
||||
? &input_locations
|
||||
|
||||
@@ -893,6 +893,12 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) {
|
||||
<< "'s type.";
|
||||
}
|
||||
|
||||
if (!_.options()->before_hlsl_legalization &&
|
||||
_.ContainsRuntimeArray(inst->type_id())) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Cannot load a runtime-sized array";
|
||||
}
|
||||
|
||||
if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
|
||||
|
||||
if (_.HasCapability(SpvCapabilityShader) &&
|
||||
|
||||
@@ -1262,16 +1262,13 @@ const Instruction* ValidationState_t::TracePointer(
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
|
||||
uint32_t width) const {
|
||||
if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false;
|
||||
|
||||
bool ValidationState_t::ContainsType(
|
||||
uint32_t id, const std::function<bool(const Instruction*)>& f,
|
||||
bool traverse_all_types) const {
|
||||
const auto inst = FindDef(id);
|
||||
if (!inst) return false;
|
||||
|
||||
if (inst->opcode() == type) {
|
||||
return inst->GetOperandAs<uint32_t>(1u) == width;
|
||||
}
|
||||
if (f(inst)) return true;
|
||||
|
||||
switch (inst->opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
@@ -1281,24 +1278,45 @@ bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
|
||||
case SpvOpTypeImage:
|
||||
case SpvOpTypeSampledImage:
|
||||
case SpvOpTypeCooperativeMatrixNV:
|
||||
return ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(1u), type,
|
||||
width);
|
||||
return ContainsType(inst->GetOperandAs<uint32_t>(1u), f,
|
||||
traverse_all_types);
|
||||
case SpvOpTypePointer:
|
||||
if (IsForwardPointer(id)) return false;
|
||||
return ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(2u), type,
|
||||
width);
|
||||
case SpvOpTypeFunction:
|
||||
case SpvOpTypeStruct: {
|
||||
for (uint32_t i = 1; i < inst->operands().size(); ++i) {
|
||||
if (ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(i), type,
|
||||
width))
|
||||
return true;
|
||||
if (traverse_all_types) {
|
||||
return ContainsType(inst->GetOperandAs<uint32_t>(2u), f,
|
||||
traverse_all_types);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SpvOpTypeFunction:
|
||||
case SpvOpTypeStruct:
|
||||
if (inst->opcode() == SpvOpTypeFunction && !traverse_all_types) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 1; i < inst->operands().size(); ++i) {
|
||||
if (ContainsType(inst->GetOperandAs<uint32_t>(i), f,
|
||||
traverse_all_types)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
|
||||
uint32_t width) const {
|
||||
if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false;
|
||||
|
||||
const auto f = [type, width](const Instruction* inst) {
|
||||
if (inst->opcode() == type) {
|
||||
return inst->GetOperandAs<uint32_t>(1u) == width;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return ContainsType(id, f);
|
||||
}
|
||||
|
||||
bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
|
||||
@@ -1313,6 +1331,13 @@ bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValidationState_t::ContainsRuntimeArray(uint32_t id) const {
|
||||
const auto f = [](const Instruction* inst) {
|
||||
return inst->opcode() == SpvOpTypeRuntimeArray;
|
||||
};
|
||||
return ContainsType(id, f, /* traverse_all_types = */ false);
|
||||
}
|
||||
|
||||
bool ValidationState_t::IsValidStorageClass(
|
||||
SpvStorageClass storage_class) const {
|
||||
if (spvIsVulkanEnv(context()->target_env)) {
|
||||
|
||||
@@ -595,6 +595,17 @@ class ValidationState_t {
|
||||
// 16-bit float that is not generally enabled for use.
|
||||
bool ContainsLimitedUseIntOrFloatType(uint32_t id) const;
|
||||
|
||||
// Returns true if |id| is a type that contains a runtime-sized array.
|
||||
// Does not consider a pointers as contains the array.
|
||||
bool ContainsRuntimeArray(uint32_t id) const;
|
||||
|
||||
// Generic type traversal.
|
||||
// Only traverse pointers and functions if |traverse_all_types| is true.
|
||||
// Recursively tests |f| against the type hierarchy headed by |id|.
|
||||
bool ContainsType(uint32_t id,
|
||||
const std::function<bool(const Instruction*)>& f,
|
||||
bool traverse_all_types = true) const;
|
||||
|
||||
// Gets value from OpConstant and OpSpecConstant as uint64.
|
||||
// Returns false on failure (no instruction, wrong instruction, not int).
|
||||
bool GetConstantValUint64(uint32_t id, uint64_t* val) const;
|
||||
|
||||
Reference in New Issue
Block a user