Updated spirv-tools.

This commit is contained in:
Бранимир Караџић
2020-11-01 21:41:43 -08:00
parent 56f62b7de0
commit 39d1f8c32c
38 changed files with 637 additions and 421 deletions

View File

@@ -1 +1 @@
"v2020.6", "SPIRV-Tools v2020.6 25b32b391d8d2cf07c95edd7d164911cb00b4bc5"
"v2020.6", "SPIRV-Tools v2020.6 fecfd7c6d825bb09bd025cbd64db0ecbef420f9a"

View File

@@ -34,6 +34,8 @@ const char* ExtensionToString(Extension extension) {
return "SPV_EXT_physical_storage_buffer";
case Extension::kSPV_EXT_shader_atomic_float_add:
return "SPV_EXT_shader_atomic_float_add";
case Extension::kSPV_EXT_shader_image_int64:
return "SPV_EXT_shader_image_int64";
case Extension::kSPV_EXT_shader_stencil_export:
return "SPV_EXT_shader_stencil_export";
case Extension::kSPV_EXT_shader_viewport_index_layer:
@@ -74,6 +76,8 @@ const char* ExtensionToString(Extension extension) {
return "SPV_KHR_device_group";
case Extension::kSPV_KHR_float_controls:
return "SPV_KHR_float_controls";
case Extension::kSPV_KHR_fragment_shading_rate:
return "SPV_KHR_fragment_shading_rate";
case Extension::kSPV_KHR_multiview:
return "SPV_KHR_multiview";
case Extension::kSPV_KHR_no_integer_wrap_decoration:
@@ -143,8 +147,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_float_add", "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_blocking_pipes", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_kernel_attributes", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_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_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_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_float_add, 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_blocking_pipes, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_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_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_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_float_add", "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_blocking_pipes", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_kernel_attributes", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_fragment_shading_rate", "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_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_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_float_add, 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_blocking_pipes, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_fragment_shading_rate, 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_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
const auto b = std::begin(known_ext_strs);
const auto e = std::end(known_ext_strs);
const auto found = std::equal_range(
@@ -298,6 +302,8 @@ const char* CapabilityToString(SpvCapability capability) {
return "ShaderLayer";
case SpvCapabilityShaderViewportIndex:
return "ShaderViewportIndex";
case SpvCapabilityFragmentShadingRateKHR:
return "FragmentShadingRateKHR";
case SpvCapabilitySubgroupBallotKHR:
return "SubgroupBallotKHR";
case SpvCapabilityDrawParameters:
@@ -354,6 +360,8 @@ const char* CapabilityToString(SpvCapability capability) {
return "StencilExportEXT";
case SpvCapabilityImageReadWriteLodAMD:
return "ImageReadWriteLodAMD";
case SpvCapabilityInt64ImageEXT:
return "Int64ImageEXT";
case SpvCapabilityShaderClockKHR:
return "ShaderClockKHR";
case SpvCapabilitySampleMaskOverrideCoverageNV:

View File

@@ -15,6 +15,7 @@ kSPV_EXT_fragment_invocation_density,
kSPV_EXT_fragment_shader_interlock,
kSPV_EXT_physical_storage_buffer,
kSPV_EXT_shader_atomic_float_add,
kSPV_EXT_shader_image_int64,
kSPV_EXT_shader_stencil_export,
kSPV_EXT_shader_viewport_index_layer,
kSPV_GOOGLE_decorate_string,
@@ -35,6 +36,7 @@ kSPV_KHR_16bit_storage,
kSPV_KHR_8bit_storage,
kSPV_KHR_device_group,
kSPV_KHR_float_controls,
kSPV_KHR_fragment_shading_rate,
kSPV_KHR_multiview,
kSPV_KHR_no_integer_wrap_decoration,
kSPV_KHR_non_semantic_info,

View File

@@ -19,6 +19,7 @@ static const SpvCapability pygen_variable_caps_FragmentFullyCoveredEXT[] = {SpvC
static const SpvCapability pygen_variable_caps_FragmentShaderPixelInterlockEXT[] = {SpvCapabilityFragmentShaderPixelInterlockEXT};
static const SpvCapability pygen_variable_caps_FragmentShaderSampleInterlockEXT[] = {SpvCapabilityFragmentShaderSampleInterlockEXT};
static const SpvCapability pygen_variable_caps_FragmentShaderShadingRateInterlockEXT[] = {SpvCapabilityFragmentShaderShadingRateInterlockEXT};
static const SpvCapability pygen_variable_caps_FragmentShadingRateKHR[] = {SpvCapabilityFragmentShadingRateKHR};
static const SpvCapability pygen_variable_caps_FunctionPointersINTEL[] = {SpvCapabilityFunctionPointersINTEL};
static const SpvCapability pygen_variable_caps_GenericPointer[] = {SpvCapabilityGenericPointer};
static const SpvCapability pygen_variable_caps_Geometry[] = {SpvCapabilityGeometry};
@@ -40,6 +41,7 @@ static const SpvCapability pygen_variable_caps_IndirectReferencesINTEL[] = {SpvC
static const SpvCapability pygen_variable_caps_InputAttachment[] = {SpvCapabilityInputAttachment};
static const SpvCapability pygen_variable_caps_InputAttachmentShaderNonUniform[] = {SpvCapabilityInputAttachment, SpvCapabilityShaderNonUniform};
static const SpvCapability pygen_variable_caps_Int64[] = {SpvCapabilityInt64};
static const SpvCapability pygen_variable_caps_Int64ImageEXT[] = {SpvCapabilityInt64ImageEXT};
static const SpvCapability pygen_variable_caps_Kernel[] = {SpvCapabilityKernel};
static const SpvCapability pygen_variable_caps_KernelGroupNonUniform[] = {SpvCapabilityKernel, SpvCapabilityGroupNonUniform};
static const SpvCapability pygen_variable_caps_KernelGroupNonUniformSubgroupBallotKHR[] = {SpvCapabilityKernel, SpvCapabilityGroupNonUniform, SpvCapabilitySubgroupBallotKHR};
@@ -109,6 +111,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_invocation
static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_shader_interlock[] = {spvtools::Extension::kSPV_EXT_fragment_shader_interlock};
static const spvtools::Extension pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer[] = {spvtools::Extension::kSPV_EXT_physical_storage_buffer, spvtools::Extension::kSPV_KHR_physical_storage_buffer};
static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_atomic_float_add[] = {spvtools::Extension::kSPV_EXT_shader_atomic_float_add};
static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_image_int64[] = {spvtools::Extension::kSPV_EXT_shader_image_int64};
static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_stencil_export[] = {spvtools::Extension::kSPV_EXT_shader_stencil_export};
static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_viewport_index_layerSPV_NV_viewport_array2[] = {spvtools::Extension::kSPV_EXT_shader_viewport_index_layer, spvtools::Extension::kSPV_NV_viewport_array2};
static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1};
@@ -128,6 +131,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_KHR_16bit_storage[] = {
static const spvtools::Extension pygen_variable_exts_SPV_KHR_8bit_storage[] = {spvtools::Extension::kSPV_KHR_8bit_storage};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_device_group[] = {spvtools::Extension::kSPV_KHR_device_group};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_float_controls[] = {spvtools::Extension::kSPV_KHR_float_controls};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_fragment_shading_rate[] = {spvtools::Extension::kSPV_KHR_fragment_shading_rate};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_multiview[] = {spvtools::Extension::kSPV_KHR_multiview};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_no_integer_wrap_decoration[] = {spvtools::Extension::kSPV_KHR_no_integer_wrap_decoration};
static const spvtools::Extension pygen_variable_exts_SPV_KHR_post_depth_coverage[] = {spvtools::Extension::kSPV_KHR_post_depth_coverage};
@@ -279,6 +283,13 @@ static const spv_operand_desc_t pygen_variable_RayFlagsEntries[] = {
{"SkipAABBsKHR", 0x0200, 1, pygen_variable_caps_RayTraversalPrimitiveCullingProvisionalKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_FragmentShadingRateEntries[] = {
{"Vertical2Pixels", 0x0001, 1, pygen_variable_caps_FragmentShadingRateKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"Vertical4Pixels", 0x0002, 1, pygen_variable_caps_FragmentShadingRateKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"Horizontal2Pixels", 0x0004, 1, pygen_variable_caps_FragmentShadingRateKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"Horizontal4Pixels", 0x0008, 1, pygen_variable_caps_FragmentShadingRateKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_SourceLanguageEntries[] = {
{"Unknown", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"ESSL", 1, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
@@ -485,7 +496,9 @@ static const spv_operand_desc_t pygen_variable_ImageFormatEntries[] = {
{"Rg16ui", 36, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Rg8ui", 37, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"R16ui", 38, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"R8ui", 39, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"R8ui", 39, 1, pygen_variable_caps_StorageImageExtendedFormats, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"R64ui", 40, 1, pygen_variable_caps_Int64ImageEXT, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"R64i", 41, 1, pygen_variable_caps_Int64ImageEXT, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_ImageChannelOrderEntries[] = {
@@ -700,8 +713,10 @@ static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = {
{"BaseVertex", 4424, 1, pygen_variable_caps_DrawParameters, 1, pygen_variable_exts_SPV_KHR_shader_draw_parameters, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu},
{"BaseInstance", 4425, 1, pygen_variable_caps_DrawParameters, 1, pygen_variable_exts_SPV_KHR_shader_draw_parameters, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu},
{"DrawIndex", 4426, 2, pygen_variable_caps_DrawParametersMeshShadingNV, 2, pygen_variable_exts_SPV_KHR_shader_draw_parametersSPV_NV_mesh_shader, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu},
{"PrimitiveShadingRateKHR", 4432, 1, pygen_variable_caps_FragmentShadingRateKHR, 1, pygen_variable_exts_SPV_KHR_fragment_shading_rate, {}, 0xffffffffu, 0xffffffffu},
{"DeviceIndex", 4438, 1, pygen_variable_caps_DeviceGroup, 1, pygen_variable_exts_SPV_KHR_device_group, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu},
{"ViewIndex", 4440, 1, pygen_variable_caps_MultiView, 1, pygen_variable_exts_SPV_KHR_multiview, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu},
{"ShadingRateKHR", 4444, 1, pygen_variable_caps_FragmentShadingRateKHR, 1, pygen_variable_exts_SPV_KHR_fragment_shading_rate, {}, 0xffffffffu, 0xffffffffu},
{"BaryCoordNoPerspAMD", 4992, 0, nullptr, 1, pygen_variable_exts_SPV_AMD_shader_explicit_vertex_parameter, {}, 0xffffffffu, 0xffffffffu},
{"BaryCoordNoPerspCentroidAMD", 4993, 0, nullptr, 1, pygen_variable_exts_SPV_AMD_shader_explicit_vertex_parameter, {}, 0xffffffffu, 0xffffffffu},
{"BaryCoordNoPerspSampleAMD", 4994, 0, nullptr, 1, pygen_variable_exts_SPV_AMD_shader_explicit_vertex_parameter, {}, 0xffffffffu, 0xffffffffu},
@@ -862,6 +877,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"GroupNonUniformQuad", 68, 1, pygen_variable_caps_GroupNonUniform, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu},
{"ShaderLayer", 69, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
{"ShaderViewportIndex", 70, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu},
{"FragmentShadingRateKHR", 4422, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_fragment_shading_rate, {}, 0xffffffffu, 0xffffffffu},
{"SubgroupBallotKHR", 4423, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_shader_ballot, {}, 0xffffffffu, 0xffffffffu},
{"DrawParameters", 4427, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_shader_draw_parameters, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu},
{"SubgroupVoteKHR", 4431, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_subgroup_vote, {}, 0xffffffffu, 0xffffffffu},
@@ -892,6 +908,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
{"FragmentMaskAMD", 5010, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_AMD_shader_fragment_mask, {}, 0xffffffffu, 0xffffffffu},
{"StencilExportEXT", 5013, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_stencil_export, {}, 0xffffffffu, 0xffffffffu},
{"ImageReadWriteLodAMD", 5015, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_AMD_shader_image_load_store_lod, {}, 0xffffffffu, 0xffffffffu},
{"Int64ImageEXT", 5016, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_image_int64, {}, 0xffffffffu, 0xffffffffu},
{"ShaderClockKHR", 5055, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_shader_clock, {}, 0xffffffffu, 0xffffffffu},
{"SampleMaskOverrideCoverageNV", 5249, 1, pygen_variable_caps_SampleRateShading, 1, pygen_variable_exts_SPV_NV_sample_mask_override_coverage, {}, 0xffffffffu, 0xffffffffu},
{"GeometryShaderPassthroughNV", 5251, 1, pygen_variable_caps_Geometry, 1, pygen_variable_exts_SPV_NV_geometry_shader_passthrough, {}, 0xffffffffu, 0xffffffffu},
@@ -1110,6 +1127,7 @@ static const spv_operand_desc_group_t pygen_variable_OperandInfoTable[] = {
{SPV_OPERAND_TYPE_MEMORY_ACCESS, ARRAY_SIZE(pygen_variable_MemoryAccessEntries), pygen_variable_MemoryAccessEntries},
{SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO, ARRAY_SIZE(pygen_variable_KernelProfilingInfoEntries), pygen_variable_KernelProfilingInfoEntries},
{SPV_OPERAND_TYPE_RAY_FLAGS, ARRAY_SIZE(pygen_variable_RayFlagsEntries), pygen_variable_RayFlagsEntries},
{SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, ARRAY_SIZE(pygen_variable_FragmentShadingRateEntries), pygen_variable_FragmentShadingRateEntries},
{SPV_OPERAND_TYPE_SOURCE_LANGUAGE, ARRAY_SIZE(pygen_variable_SourceLanguageEntries), pygen_variable_SourceLanguageEntries},
{SPV_OPERAND_TYPE_EXECUTION_MODEL, ARRAY_SIZE(pygen_variable_ExecutionModelEntries), pygen_variable_ExecutionModelEntries},
{SPV_OPERAND_TYPE_ADDRESSING_MODEL, ARRAY_SIZE(pygen_variable_AddressingModelEntries), pygen_variable_AddressingModelEntries},

View File

@@ -176,12 +176,13 @@ typedef enum spv_operand_type_t {
// Set 5: Operands that are a single word bitmask.
// Sometimes a set bit indicates the instruction requires still more operands.
SPV_OPERAND_TYPE_IMAGE, // SPIR-V Sec 3.14
SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, // SPIR-V Sec 3.15
SPV_OPERAND_TYPE_SELECTION_CONTROL, // SPIR-V Sec 3.22
SPV_OPERAND_TYPE_LOOP_CONTROL, // SPIR-V Sec 3.23
SPV_OPERAND_TYPE_FUNCTION_CONTROL, // SPIR-V Sec 3.24
SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26
SPV_OPERAND_TYPE_IMAGE, // SPIR-V Sec 3.14
SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, // SPIR-V Sec 3.15
SPV_OPERAND_TYPE_SELECTION_CONTROL, // SPIR-V Sec 3.22
SPV_OPERAND_TYPE_LOOP_CONTROL, // SPIR-V Sec 3.23
SPV_OPERAND_TYPE_FUNCTION_CONTROL, // SPIR-V Sec 3.24
SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26
SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, // SPIR-V Sec 3.FSR
// The remaining operand types are only used internally by the assembler.
// There are two categories:

View File

@@ -536,28 +536,16 @@ Optimizer::PassToken CreateDeadInsertElimPass();
// eliminated with standard dead code elimination.
Optimizer::PassToken CreateAggressiveDCEPass();
// Create line propagation pass
// This pass propagates line information based on the rules for OpLine and
// OpNoline and clones an appropriate line instruction into every instruction
// which does not already have debug line instructions.
//
// This pass is intended to maximize preservation of source line information
// through passes which delete, move and clone instructions. Ideally it should
// be run before any such pass. It is a bookend pass with EliminateDeadLines
// which can be used to remove redundant line instructions at the end of a
// run of such passes and reduce final output file size.
// Creates an empty pass.
// This is deprecated and will be removed.
// TODO(jaebaek): remove this pass after handling glslang's broken unit tests.
// https://github.com/KhronosGroup/glslang/pull/2440
Optimizer::PassToken CreatePropagateLineInfoPass();
// Create dead line elimination pass
// This pass eliminates redundant line instructions based on the rules for
// OpLine and OpNoline. Its main purpose is to reduce the size of the file
// need to store the SPIR-V without losing line information.
//
// This is a bookend pass with PropagateLines which attaches line instructions
// to every instruction to preserve line information during passes which
// delete, move and clone instructions. DeadLineElim should be run after
// PropagateLines and all such subsequent passes. Normally it would be one
// of the last passes to be run.
// Creates an empty pass.
// This is deprecated and will be removed.
// TODO(jaebaek): remove this pass after handling glslang's broken unit tests.
// https://github.com/KhronosGroup/glslang/pull/2440
Optimizer::PassToken CreateRedundantLineInfoElimPass();
// Creates a compact ids pass.

View File

@@ -346,58 +346,64 @@ set_source_files_properties(
spvtools_pch(SPIRV_SOURCES pch_source)
add_library(${SPIRV_TOOLS}-static STATIC ${SPIRV_SOURCES})
spvtools_default_compile_options(${SPIRV_TOOLS}-static)
target_include_directories(${SPIRV_TOOLS}-static
PUBLIC
$<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
PRIVATE ${SPIRV_HEADER_INCLUDE_DIR}
# spirv_tools_default_target_options() sets the target options that are common
# for all ${SPIRV_TOOLS} targets.
function(spirv_tools_default_target_options target)
spvtools_default_compile_options(${target})
target_include_directories(${target}
PUBLIC
$<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
PRIVATE ${SPIRV_HEADER_INCLUDE_DIR}
)
set_property(TARGET ${SPIRV_TOOLS}-static PROPERTY FOLDER "SPIRV-Tools libraries")
spvtools_check_symbol_exports(${SPIRV_TOOLS}-static)
add_dependencies(${SPIRV_TOOLS}-static core_tables enum_string_mapping extinst_tables)
# The static target does not have the '-static' suffix.
set_target_properties(${SPIRV_TOOLS}-static PROPERTIES OUTPUT_NAME "${SPIRV_TOOLS}")
set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools libraries")
spvtools_check_symbol_exports(${target})
add_dependencies(${target} core_tables enum_string_mapping extinst_tables)
endfunction()
# Always build ${SPIRV_TOOLS}-shared. This is expected distro packages, and
# unlike the other SPIRV_TOOLS target, defaults to hidden symbol visibility.
add_library(${SPIRV_TOOLS}-shared SHARED ${SPIRV_SOURCES})
spvtools_default_compile_options(${SPIRV_TOOLS}-shared)
target_include_directories(${SPIRV_TOOLS}-shared
PUBLIC
$<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${spirv-tools_BINARY_DIR}
PRIVATE ${SPIRV_HEADER_INCLUDE_DIR}
)
spirv_tools_default_target_options(${SPIRV_TOOLS}-shared)
set_target_properties(${SPIRV_TOOLS}-shared PROPERTIES CXX_VISIBILITY_PRESET hidden)
set_property(TARGET ${SPIRV_TOOLS}-shared PROPERTY FOLDER "SPIRV-Tools libraries")
spvtools_check_symbol_exports(${SPIRV_TOOLS}-shared)
target_compile_definitions(${SPIRV_TOOLS}-shared
PRIVATE SPIRV_TOOLS_IMPLEMENTATION
PUBLIC SPIRV_TOOLS_SHAREDLIB
)
add_dependencies(${SPIRV_TOOLS}-shared core_tables enum_string_mapping extinst_tables)
# Create the "${SPIRV_TOOLS}" target as an alias to either "${SPIRV_TOOLS}-static"
# or "${SPIRV_TOOLS}-shared" depending on the value of BUILD_SHARED_LIBS.
if(BUILD_SHARED_LIBS)
if(SPIRV_TOOLS_BUILD_STATIC)
add_library(${SPIRV_TOOLS}-static STATIC ${SPIRV_SOURCES})
spirv_tools_default_target_options(${SPIRV_TOOLS}-static)
# The static target does not have the '-static' suffix.
set_target_properties(${SPIRV_TOOLS}-static PROPERTIES OUTPUT_NAME "${SPIRV_TOOLS}")
# Create the "${SPIRV_TOOLS}" target as an alias to either "${SPIRV_TOOLS}-static"
# or "${SPIRV_TOOLS}-shared" depending on the value of BUILD_SHARED_LIBS.
if(BUILD_SHARED_LIBS)
add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-shared)
else()
else()
add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-static)
endif()
set(SPIRV_TOOLS_TARGETS ${SPIRV_TOOLS}-static ${SPIRV_TOOLS}-shared)
else()
add_library(${SPIRV_TOOLS} ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_SOURCES})
spirv_tools_default_target_options(${SPIRV_TOOLS})
set(SPIRV_TOOLS_TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared)
endif()
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
find_library(LIBRT rt)
if(LIBRT)
target_link_libraries(${SPIRV_TOOLS}-static ${LIBRT})
target_link_libraries(${SPIRV_TOOLS}-shared ${LIBRT})
foreach(target ${SPIRV_TOOLS_TARGETS})
target_link_libraries(${target} ${LIBRT})
endforeach()
endif()
endif()
if(ENABLE_SPIRV_TOOLS_INSTALL)
install(TARGETS ${SPIRV_TOOLS}-static ${SPIRV_TOOLS}-shared EXPORT ${SPIRV_TOOLS}Targets
install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@@ -127,7 +127,7 @@ class CFA {
template <class BB>
bool CFA<BB>::FindInWorkList(const std::vector<block_info>& work_list,
uint32_t id) {
for (auto& b : work_list) {
for (const auto& b : work_list) {
if (b.block->id() == id) return true;
}
return false;

View File

@@ -11,7 +11,7 @@
# 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.
add_library(SPIRV-Tools-link STATIC
add_library(SPIRV-Tools-link ${SPIRV_TOOLS_LIBRARY_TYPE}
linker.cpp
)

View File

@@ -208,6 +208,8 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
case SPV_OPERAND_TYPE_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
return "memory access";
case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE:
return "shading rate";
case SPV_OPERAND_TYPE_SCOPE_ID:
return "scope ID";
case SPV_OPERAND_TYPE_GROUP_OPERATION:
@@ -360,6 +362,7 @@ bool spvOperandIsConcreteMask(spv_operand_type_t type) {
case SPV_OPERAND_TYPE_LOOP_CONTROL:
case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
case SPV_OPERAND_TYPE_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE:
case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
return true;

View File

@@ -43,6 +43,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
eliminate_dead_functions_pass.h
eliminate_dead_functions_util.h
eliminate_dead_members_pass.h
empty_pass.h
feature_manager.h
fix_storage_class.h
flatten_decoration_pass.h
@@ -89,7 +90,6 @@ set(SPIRV_TOOLS_OPT_SOURCES
pass.h
pass_manager.h
private_to_local_pass.h
process_lines_pass.h
propagator.h
reduce_load_size.h
redundancy_elimination.h
@@ -196,7 +196,6 @@ set(SPIRV_TOOLS_OPT_SOURCES
pass.cpp
pass_manager.cpp
private_to_local_pass.cpp
process_lines_pass.cpp
propagator.cpp
reduce_load_size.cpp
redundancy_elimination.cpp
@@ -233,7 +232,7 @@ endif()
spvtools_pch(SPIRV_TOOLS_OPT_SOURCES pch_source_opt)
add_library(SPIRV-Tools-opt STATIC ${SPIRV_TOOLS_OPT_SOURCES})
add_library(SPIRV-Tools-opt ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_TOOLS_OPT_SOURCES})
spvtools_default_compile_options(SPIRV-Tools-opt)
target_include_directories(SPIRV-Tools-opt
@@ -245,7 +244,7 @@ target_include_directories(SPIRV-Tools-opt
)
# We need the assembling and disassembling functionalities in the main library.
target_link_libraries(SPIRV-Tools-opt
PUBLIC ${SPIRV_TOOLS}-static)
PUBLIC ${SPIRV_TOOLS_FULL_VISIBILITY})
set_property(TARGET SPIRV-Tools-opt PROPERTY FOLDER "SPIRV-Tools libraries")
spvtools_check_symbol_exports(SPIRV-Tools-opt)

View File

@@ -135,23 +135,15 @@ SSAPropagator::PropStatus CCPPass::VisitAssignment(Instruction* instr) {
}
return it->second;
};
uint32_t next_id = context()->module()->IdBound();
Instruction* folded_inst =
context()->get_instruction_folder().FoldInstructionToConstant(instr,
map_func);
if (folded_inst != nullptr) {
// We do not want to change the body of the function by adding new
// instructions. When folding we can only generate new constants.
assert(folded_inst->IsConstant() && "CCP is only interested in constant.");
values_[instr->result_id()] = folded_inst->result_id();
// If the folded instruction has just been created, its result ID will
// match the previous ID bound. When this happens, we need to indicate
// that CCP has modified the IR, independently of whether the constant is
// actually propagated. See
// https://github.com/KhronosGroup/SPIRV-Tools/issues/3636 for details.
if (folded_inst->result_id() >= next_id) created_new_constant_ = true;
return SSAPropagator::kInteresting;
}
@@ -278,10 +270,14 @@ bool CCPPass::ReplaceValues() {
// Even if we make no changes to the function's IR, propagation may have
// created new constants. Even if those constants cannot be replaced in
// the IR, the constant definition itself is a change. To reflect this,
// we initialize the IR changed indicator with the value of the
// created_new_constant_ indicator. For an example, see the bug reported
// in https://github.com/KhronosGroup/SPIRV-Tools/issues/3636.
bool changed_ir = created_new_constant_;
// we check whether the next ID to be given by the module is different than
// the original bound ID. If that happens, new instructions were added to the
// module during propagation.
//
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/3636 and
// https://github.com/KhronosGroup/SPIRV-Tools/issues/3991 for details.
bool changed_ir = (context()->module()->IdBound() > original_id_bound_);
for (const auto& it : values_) {
uint32_t id = it.first;
uint32_t cst_id = it.second;
@@ -290,6 +286,7 @@ bool CCPPass::ReplaceValues() {
changed_ir |= context()->ReplaceAllUsesWith(id, cst_id);
}
}
return changed_ir;
}
@@ -329,7 +326,7 @@ void CCPPass::Initialize() {
}
}
created_new_constant_ = false;
original_id_bound_ = context()->module()->IdBound();
}
Pass::Status CCPPass::Process() {

View File

@@ -106,8 +106,9 @@ class CCPPass : public MemPass {
// Propagator engine used.
std::unique_ptr<SSAPropagator> propagator_;
// True if the pass created new constant instructions during propagation.
bool created_new_constant_;
// Value for the module's ID bound before running CCP. Used to detect whether
// propagation created new instructions.
uint32_t original_id_bound_;
};
} // namespace opt

View File

@@ -40,7 +40,6 @@ static const uint32_t kDebugLocalVariableOperandParentIndex = 9;
static const uint32_t kExtInstInstructionInIdx = 1;
static const uint32_t kDebugGlobalVariableOperandFlagsIndex = 12;
static const uint32_t kDebugLocalVariableOperandFlagsIndex = 10;
static const uint32_t kDebugLocalVariableOperandArgNumberIndex = 11;
namespace spvtools {
namespace opt {
@@ -441,32 +440,40 @@ bool DebugInfoManager::IsAncestorOfScope(uint32_t scope, uint32_t ancestor) {
return false;
}
Instruction* DebugInfoManager::GetDebugLocalVariableFromDeclare(
Instruction* dbg_declare) {
assert(dbg_declare);
bool DebugInfoManager::IsDeclareVisibleToInstr(Instruction* dbg_declare,
Instruction* scope) {
assert(dbg_declare != nullptr);
assert(scope != nullptr);
std::vector<uint32_t> scope_ids;
if (scope->opcode() == SpvOpPhi) {
scope_ids.push_back(scope->GetDebugScope().GetLexicalScope());
for (uint32_t i = 0; i < scope->NumInOperands(); i += 2) {
auto* value = context()->get_def_use_mgr()->GetDef(
scope->GetSingleWordInOperand(i));
if (value != nullptr)
scope_ids.push_back(value->GetDebugScope().GetLexicalScope());
}
} else {
scope_ids.push_back(scope->GetDebugScope().GetLexicalScope());
}
uint32_t dbg_local_var_id =
dbg_declare->GetSingleWordOperand(kDebugDeclareOperandLocalVariableIndex);
auto dbg_local_var_itr = id_to_dbg_inst_.find(dbg_local_var_id);
assert(dbg_local_var_itr != id_to_dbg_inst_.end());
return dbg_local_var_itr->second;
}
bool DebugInfoManager::IsFunctionParameter(Instruction* dbg_local_var) const {
// If a DebugLocalVariable has ArgNumber operand, it is a function parameter.
return dbg_local_var->NumOperands() >
kDebugLocalVariableOperandArgNumberIndex;
}
bool DebugInfoManager::IsLocalVariableVisibleToInstr(Instruction* dbg_local_var,
uint32_t instr_scope_id) {
if (instr_scope_id == kNoDebugScope) return false;
uint32_t decl_scope_id = dbg_local_var->GetSingleWordOperand(
uint32_t decl_scope_id = dbg_local_var_itr->second->GetSingleWordOperand(
kDebugLocalVariableOperandParentIndex);
// If the scope of DebugDeclare is an ancestor scope of the instruction's
// scope, the local variable is visible to the instruction.
return IsAncestorOfScope(instr_scope_id, decl_scope_id);
for (uint32_t scope_id : scope_ids) {
if (scope_id != kNoDebugScope &&
IsAncestorOfScope(scope_id, decl_scope_id)) {
return true;
}
}
return false;
}
Instruction* DebugInfoManager::AddDebugValueWithIndex(
@@ -509,26 +516,21 @@ Instruction* DebugInfoManager::AddDebugValueWithIndex(
void DebugInfoManager::AddDebugValueIfVarDeclIsVisible(
Instruction* scope_and_line, uint32_t variable_id, uint32_t value_id,
Instruction* insert_pos) {
Instruction* insert_pos,
std::unordered_set<Instruction*>* invisible_decls) {
auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
if (dbg_decl_itr == var_id_to_dbg_decl_.end()) return;
uint32_t instr_scope_id = scope_and_line->GetDebugScope().GetLexicalScope();
for (auto* dbg_decl_or_val : dbg_decl_itr->second) {
// If it declares a function parameter, the store instruction for the
// function parameter can exist out of the function parameter's scope
// because of the function inlining. We always add DebugValue for a
// function parameter next to the DebugDeclare regardless of the scope.
auto* dbg_local_var = GetDebugLocalVariableFromDeclare(dbg_decl_or_val);
bool is_function_param = IsFunctionParameter(dbg_local_var);
if (!is_function_param &&
!IsLocalVariableVisibleToInstr(dbg_local_var, instr_scope_id))
if (scope_and_line &&
!IsDeclareVisibleToInstr(dbg_decl_or_val, scope_and_line)) {
if (invisible_decls) invisible_decls->insert(dbg_decl_or_val);
continue;
}
// Avoid inserting the new DebugValue between OpPhi or OpVariable
// instructions.
Instruction* insert_before = is_function_param ? dbg_decl_or_val->NextNode()
: insert_pos->NextNode();
Instruction* insert_before = insert_pos->NextNode();
while (insert_before->opcode() == SpvOpPhi ||
insert_before->opcode() == SpvOpVariable) {
insert_before = insert_before->NextNode();
@@ -545,12 +547,36 @@ void DebugInfoManager::AddDebugValueIfVarDeclIsVisible(
kDebugValueOperandLocalVariableIndex),
value_id, 0, index_id, insert_before);
assert(added_dbg_value != nullptr);
added_dbg_value->UpdateDebugInfoFrom(is_function_param ? dbg_decl_or_val
: scope_and_line);
added_dbg_value->UpdateDebugInfoFrom(scope_and_line ? scope_and_line
: dbg_decl_or_val);
AnalyzeDebugInst(added_dbg_value);
}
}
bool DebugInfoManager::AddDebugValueForDecl(Instruction* dbg_decl,
uint32_t value_id) {
if (dbg_decl == nullptr || !IsDebugDeclare(dbg_decl)) return false;
std::unique_ptr<Instruction> dbg_val(dbg_decl->Clone(context()));
dbg_val->SetResultId(context()->TakeNextId());
dbg_val->SetInOperand(kExtInstInstructionInIdx,
{OpenCLDebugInfo100DebugValue});
dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id});
dbg_val->SetOperand(kDebugValueOperandExpressionIndex,
{GetEmptyDebugExpression()->result_id()});
auto* added_dbg_val = dbg_decl->InsertBefore(std::move(dbg_val));
AnalyzeDebugInst(added_dbg_val);
if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_val);
if (context()->AreAnalysesValid(
IRContext::Analysis::kAnalysisInstrToBlockMapping)) {
auto insert_blk = context()->get_instr_block(dbg_decl);
context()->set_instr_block(added_dbg_val, insert_blk);
}
return true;
}
uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
Instruction* inst) {
if (inst->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugValue) return 0;

View File

@@ -144,9 +144,11 @@ class DebugInfoManager {
// Generates a DebugValue instruction with value |value_id| for every local
// variable that is in the scope of |scope_and_line| and whose memory is
// |variable_id| and inserts it after the instruction |insert_pos|.
void AddDebugValueIfVarDeclIsVisible(Instruction* scope_and_line,
uint32_t variable_id, uint32_t value_id,
Instruction* insert_pos);
// |invisible_decls| returns DebugDeclares invisible to |scope_and_line|.
void AddDebugValueIfVarDeclIsVisible(
Instruction* scope_and_line, uint32_t variable_id, uint32_t value_id,
Instruction* insert_pos,
std::unordered_set<Instruction*>* invisible_decls);
// Generates a DebugValue instruction with |dbg_local_var_id|, |value_id|,
// |expr_id|, |index_id| operands and inserts it before |insert_before|.
@@ -155,6 +157,11 @@ class DebugInfoManager {
uint32_t index_id,
Instruction* insert_before);
// Adds DebugValue for DebugDeclare |dbg_decl|. The new DebugValue has the
// same line, scope, and operands but it uses |value_id| for value. Returns
// weather it succeeds or not.
bool AddDebugValueForDecl(Instruction* dbg_decl, uint32_t value_id);
// Erases |instr| from data structures of this class.
void ClearDebugInfo(Instruction* instr);
@@ -215,17 +222,9 @@ class DebugInfoManager {
// of |scope|.
bool IsAncestorOfScope(uint32_t scope, uint32_t ancestor);
// Returns the DebugLocalVariable declared by |dbg_declare|.
Instruction* GetDebugLocalVariableFromDeclare(Instruction* dbg_declare);
// Returns true if the DebugLocalVariable |dbg_local_var| is a function
// parameter.
bool IsFunctionParameter(Instruction* dbg_local_var) const;
// Returns true if the DebugLocalVariable |dbg_local_var| is visible
// in the scope of an instruction |instr_scope_id|.
bool IsLocalVariableVisibleToInstr(Instruction* dbg_local_var,
uint32_t instr_scope_id);
// Returns true if the declaration of a local variable |dbg_declare|
// is visible in the scope of an instruction |instr_scope_id|.
bool IsDeclareVisibleToInstr(Instruction* dbg_declare, Instruction* scope);
// Returns the parent scope of the scope |child_scope|.
uint32_t GetParentScope(uint32_t child_scope);

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2020 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_EMPTY_PASS_H_
#define SOURCE_OPT_EMPTY_PASS_H_
#include "source/opt/pass.h"
namespace spvtools {
namespace opt {
// Documented in optimizer.hpp
class EmptyPass : public Pass {
public:
EmptyPass() {}
const char* name() const override { return "empty-pass"; }
Status Process() override { return Status::SuccessWithoutChange; }
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_EMPTY_PASS_H_

View File

@@ -94,6 +94,9 @@ class Function {
// Returns function's return type id
inline uint32_t type_id() const { return def_inst_->type_id(); }
// Returns the function's control mask
inline uint32_t control_mask() const { return def_inst_->GetSingleWordInOperand(0); }
// Returns the entry basic block for this function.
const std::unique_ptr<BasicBlock>& entry() const { return blocks_.front(); }

View File

@@ -727,6 +727,12 @@ void InlinePass::AnalyzeReturns(Function* func) {
bool InlinePass::IsInlinableFunction(Function* func) {
// We can only inline a function if it has blocks.
if (func->cbegin() == func->cend()) return false;
// Do not inline functions with DontInline flag.
if (func->control_mask() & SpvFunctionControlDontInlineMask) {
return false;
}
// Do not inline functions with returns in loops. Currently early return
// functions are inlined by wrapping them in a one trip loop and implementing
// the returns as a branch to the loop's merge block. However, this can only

View File

@@ -349,8 +349,9 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref,
: SpvDecorationArrayStride;
uint32_t arr_stride = FindStride(curr_ty_id, stride_deco);
uint32_t arr_stride_id = builder->GetUintConstantId(arr_stride);
uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder);
Instruction* curr_offset_inst = builder->AddBinaryOp(
GetUintId(), SpvOpIMul, arr_stride_id, curr_idx_id);
GetUintId(), SpvOpIMul, arr_stride_id, curr_idx_32b_id);
curr_offset_id = curr_offset_inst->result_id();
// Get element type for next step
curr_ty_id = curr_ty_inst->GetSingleWordInOperand(0);
@@ -360,8 +361,9 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref,
uint32_t comp_ty_id = curr_ty_inst->GetSingleWordInOperand(0u);
uint32_t vec_stride = ByteSize(comp_ty_id);
uint32_t vec_stride_id = builder->GetUintConstantId(vec_stride);
uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder);
Instruction* curr_offset_inst = builder->AddBinaryOp(
GetUintId(), SpvOpIMul, vec_stride_id, curr_idx_id);
GetUintId(), SpvOpIMul, vec_stride_id, curr_idx_32b_id);
curr_offset_id = curr_offset_inst->result_id();
// Get element type for next step
curr_ty_id = comp_ty_id;
@@ -434,18 +436,27 @@ void InstBindlessCheckPass::GenCheckCode(
new_blk_ptr.reset(new BasicBlock(std::move(invalid_label)));
builder.SetInsertPoint(&*new_blk_ptr);
uint32_t u_index_id = GenUintCastCode(ref->desc_idx_id, &builder);
if (offset_id != 0)
if (offset_id != 0) {
// Buffer OOB
uint32_t u_offset_id = GenUintCastCode(offset_id, &builder);
uint32_t u_length_id = GenUintCastCode(length_id, &builder);
GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
{error_id, u_index_id, offset_id, length_id}, &builder);
else if (buffer_bounds_enabled_)
// So all error modes will use same debug stream write function
{error_id, u_index_id, u_offset_id, u_length_id},
&builder);
} else if (buffer_bounds_enabled_) {
// Uninitialized Descriptor - Return additional unused zero so all error
// modes will use same debug stream write function
uint32_t u_length_id = GenUintCastCode(length_id, &builder);
GenDebugStreamWrite(
uid2offset_[ref->ref_inst->unique_id()], stage_idx,
{error_id, u_index_id, length_id, builder.GetUintConstantId(0)},
{error_id, u_index_id, u_length_id, builder.GetUintConstantId(0)},
&builder);
else
} else {
// Uninitialized Descriptor - Normal error return
uint32_t u_length_id = GenUintCastCode(length_id, &builder);
GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
{error_id, u_index_id, length_id}, &builder);
{error_id, u_index_id, u_length_id}, &builder);
}
// Remember last invalid block id
uint32_t last_invalid_blk_id = new_blk_ptr->GetLabelInst()->result_id();
// Gen zero for invalid reference
@@ -516,8 +527,11 @@ void InstBindlessCheckPass::GenDescIdxCheckCode(
// Generate full runtime bounds test code with true branch
// being full reference and false branch being debug output and zero
// for the referenced value.
uint32_t desc_idx_32b_id = Gen32BitCvtCode(ref.desc_idx_id, &builder);
uint32_t length_32b_id = Gen32BitCvtCode(length_id, &builder);
Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan,
ref.desc_idx_id, length_id);
desc_idx_32b_id, length_32b_id);
ref.desc_idx_id = desc_idx_32b_id;
GenCheckCode(ult_inst->result_id(), error_id, 0u, length_id, stage_idx, &ref,
new_blocks);
// Move original block's remaining code into remainder/merge block and add

View File

@@ -527,7 +527,7 @@ void Instruction::UpdateDebugInfoFrom(const Instruction* from) {
if (from == nullptr) return;
clear_dbg_line_insts();
if (!from->dbg_line_insts().empty())
dbg_line_insts().push_back(from->dbg_line_insts()[0]);
dbg_line_insts().push_back(from->dbg_line_insts().back());
SetDebugScope(from->GetDebugScope());
if (!IsDebugLineInst(opcode()) &&
context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {

View File

@@ -88,12 +88,36 @@ std::unique_ptr<Instruction> InstrumentPass::NewLabel(uint32_t label_id) {
return newLabel;
}
uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id,
InstructionBuilder* builder) {
// Convert integer value to 32-bit if necessary
analysis::TypeManager* type_mgr = context()->get_type_mgr();
uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_id)->type_id();
analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
if (val_ty->width() == 32) return val_id;
bool is_signed = val_ty->IsSigned();
analysis::Integer val_32b_ty(32, is_signed);
analysis::Type* val_32b_reg_ty = type_mgr->GetRegisteredType(&val_32b_ty);
uint32_t val_32b_reg_ty_id = type_mgr->GetId(val_32b_reg_ty);
if (is_signed)
return builder->AddUnaryOp(val_32b_reg_ty_id, SpvOpSConvert, val_id)
->result_id();
else
return builder->AddUnaryOp(val_32b_reg_ty_id, SpvOpUConvert, val_id)
->result_id();
}
uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id,
InstructionBuilder* builder) {
// Cast value to 32-bit unsigned if necessary
if (get_def_use_mgr()->GetDef(val_id)->type_id() == GetUintId())
return val_id;
return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_id)->result_id();
// Convert value to 32-bit if necessary
uint32_t val_32b_id = Gen32BitCvtCode(val_id, builder);
// Cast value to unsigned if necessary
analysis::TypeManager* type_mgr = context()->get_type_mgr();
uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_32b_id)->type_id();
analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
if (!val_ty->IsSigned()) return val_32b_id;
return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_32b_id)
->result_id();
}
void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,

View File

@@ -213,8 +213,12 @@ class InstrumentPass : public Pass {
uint32_t GenDebugDirectRead(const std::vector<uint32_t>& offset_ids,
InstructionBuilder* builder);
// Generate code to cast |value_id| to unsigned, if needed. Return
// an id to the unsigned equivalent.
// Generate code to convert integer |value_id| to 32bit, if needed. Return
// an id to the 32bit equivalent.
uint32_t Gen32BitCvtCode(uint32_t value_id, InstructionBuilder* builder);
// Generate code to cast integer |value_id| to 32bit unsigned, if needed.
// Return an id to the Uint equivalent.
uint32_t GenUintCastCode(uint32_t value_id, InstructionBuilder* builder);
// Return new label.

View File

@@ -41,6 +41,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
++inst_index_;
const auto opcode = static_cast<SpvOp>(inst->opcode);
if (IsDebugLineInst(opcode)) {
last_line_inst_.reset();
dbg_line_info_.push_back(
Instruction(module()->context(), *inst, last_dbg_scope_));
return true;
@@ -90,7 +91,16 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
std::unique_ptr<Instruction> spv_inst(
new Instruction(module()->context(), *inst, std::move(dbg_line_info_)));
dbg_line_info_.clear();
if (!spv_inst->dbg_line_insts().empty()) {
if (spv_inst->dbg_line_insts().back().opcode() != SpvOpNoLine) {
last_line_inst_ = std::unique_ptr<Instruction>(
spv_inst->dbg_line_insts().back().Clone(module()->context()));
}
dbg_line_info_.clear();
} else if (last_line_inst_ != nullptr) {
last_line_inst_->SetDebugScope(last_dbg_scope_);
spv_inst->dbg_line_insts().push_back(*last_line_inst_);
}
const char* src = source_.c_str();
spv_position_t loc = {inst_index_, 0, 0};
@@ -141,6 +151,8 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
function_->AddBasicBlock(std::move(block_));
block_ = nullptr;
last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
last_line_inst_.reset();
dbg_line_info_.clear();
} else {
if (function_ == nullptr) { // Outside function definition
SPIRV_ASSERT(consumer_, block_ == nullptr);

View File

@@ -78,6 +78,8 @@ class IrLoader {
std::unique_ptr<BasicBlock> block_;
// Line related debug instructions accumulated thus far.
std::vector<Instruction> dbg_line_info_;
// Line instruction that should be applied to the next instruction.
std::unique_ptr<Instruction> last_line_inst_;
// The last DebugScope information that IrLoader::AddInstruction() handled.
DebugScope last_dbg_scope_;

View File

@@ -149,8 +149,8 @@ bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
const analysis::Type* store_type = var_type->AsPointer()->pointee_type();
if (!(store_type->AsStruct() || store_type->AsArray())) {
context()->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible(
store_inst, var_id, store_inst->GetSingleWordInOperand(1),
store_inst);
nullptr, var_id, store_inst->GetSingleWordInOperand(1), store_inst,
nullptr);
context()->get_debug_info_mgr()->KillDebugDeclares(var_id);
}
}

View File

@@ -143,8 +143,38 @@ void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const {
size_t bound_idx = binary->size() - 2;
DebugScope last_scope(kNoDebugScope, kNoInlinedAt);
auto write_inst = [binary, skip_nop, &last_scope,
this](const Instruction* i) {
const Instruction* last_line_inst = nullptr;
bool between_merge_and_branch = false;
auto write_inst = [binary, skip_nop, &last_scope, &last_line_inst,
&between_merge_and_branch, this](const Instruction* i) {
// Skip emitting line instructions between merge and branch instructions.
auto opcode = i->opcode();
if (between_merge_and_branch &&
(opcode == SpvOpLine || opcode == SpvOpNoLine)) {
return;
}
between_merge_and_branch = false;
if (last_line_inst != nullptr) {
// If the current instruction is OpLine and it is the same with
// the last line instruction that is still effective (can be applied
// to the next instruction), we skip writing the current instruction.
if (opcode == SpvOpLine) {
uint32_t operand_index = 0;
if (last_line_inst->WhileEachInOperand(
[&operand_index, i](const uint32_t* word) {
assert(i->NumInOperandWords() > operand_index);
return *word == i->GetSingleWordInOperand(operand_index++);
})) {
return;
}
} else if (opcode != SpvOpNoLine && i->dbg_line_insts().empty()) {
// If the current instruction does not have the line information,
// the last line information is not effective any more. Emit OpNoLine
// to specify it.
binary->push_back((1 << 16) | static_cast<uint16_t>(SpvOpNoLine));
last_line_inst = nullptr;
}
}
if (!(skip_nop && i->IsNop())) {
const auto& scope = i->GetDebugScope();
if (scope != last_scope) {
@@ -157,6 +187,15 @@ void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const {
i->ToBinaryWithoutAttachedDebugInsts(binary);
}
// Update the last line instruction.
if (IsTerminatorInst(opcode) || opcode == SpvOpNoLine) {
last_line_inst = nullptr;
} else if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) {
between_merge_and_branch = true;
last_line_inst = nullptr;
} else if (opcode == SpvOpLine) {
last_line_inst = i;
}
};
ForEachInst(write_inst, true);

View File

@@ -246,6 +246,12 @@ class Module {
// If |skip_nop| is true and this is a OpNop, do nothing.
void ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const;
// Pushes the binary segments for this instruction into the back of *|binary|
// including all OpLine and OpNoLine even if we can skip emitting some line
// instructions. If |skip_nop| is true and this is a OpNop, do nothing.
void ToBinaryWithAllOpLines(std::vector<uint32_t>* binary,
bool skip_nop) const;
// Returns 1 more than the maximum Id value mentioned in the module.
uint32_t ComputeIdBound() const;

View File

@@ -339,10 +339,6 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
RegisterPass(CreateDescriptorScalarReplacementPass());
} else if (pass_name == "eliminate-dead-code-aggressive") {
RegisterPass(CreateAggressiveDCEPass());
} else if (pass_name == "propagate-line-info") {
RegisterPass(CreatePropagateLineInfoPass());
} else if (pass_name == "eliminate-redundant-line-info") {
RegisterPass(CreateRedundantLineInfoElimPass());
} else if (pass_name == "eliminate-insert-extract") {
RegisterPass(CreateInsertExtractElimPass());
} else if (pass_name == "eliminate-local-single-block") {
@@ -758,13 +754,11 @@ Optimizer::PassToken CreateAggressiveDCEPass() {
}
Optimizer::PassToken CreatePropagateLineInfoPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::ProcessLinesPass>(opt::kLinesPropagateLines));
return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
}
Optimizer::PassToken CreateRedundantLineInfoElimPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::ProcessLinesPass>(opt::kLinesEliminateDeadLines));
return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
}
Optimizer::PassToken CreateCompactIdsPass() {

View File

@@ -35,6 +35,7 @@
#include "source/opt/eliminate_dead_constant_pass.h"
#include "source/opt/eliminate_dead_functions_pass.h"
#include "source/opt/eliminate_dead_members_pass.h"
#include "source/opt/empty_pass.h"
#include "source/opt/fix_storage_class.h"
#include "source/opt/flatten_decoration_pass.h"
#include "source/opt/fold_spec_constant_op_and_composite_pass.h"
@@ -61,7 +62,6 @@
#include "source/opt/merge_return_pass.h"
#include "source/opt/null_pass.h"
#include "source/opt/private_to_local_pass.h"
#include "source/opt/process_lines_pass.h"
#include "source/opt/reduce_load_size.h"
#include "source/opt/redundancy_elimination.h"
#include "source/opt/relax_float_ops_pass.h"

View File

@@ -1,157 +0,0 @@
// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018 Valve Corporation
// Copyright (c) 2018 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/opt/process_lines_pass.h"
#include <set>
#include <unordered_set>
#include <vector>
namespace {
// Input Operand Indices
static const int kSpvLineFileInIdx = 0;
static const int kSpvLineLineInIdx = 1;
static const int kSpvLineColInIdx = 2;
} // anonymous namespace
namespace spvtools {
namespace opt {
Pass::Status ProcessLinesPass::Process() {
bool modified = ProcessLines();
return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
}
bool ProcessLinesPass::ProcessLines() {
bool modified = false;
uint32_t file_id = 0;
uint32_t line = 0;
uint32_t col = 0;
// Process types, globals, constants
for (Instruction& inst : get_module()->types_values())
modified |= line_process_func_(&inst, &file_id, &line, &col);
// Process functions
for (Function& function : *get_module()) {
modified |= line_process_func_(&function.DefInst(), &file_id, &line, &col);
function.ForEachParam(
[this, &modified, &file_id, &line, &col](Instruction* param) {
modified |= line_process_func_(param, &file_id, &line, &col);
});
for (BasicBlock& block : function) {
modified |=
line_process_func_(block.GetLabelInst(), &file_id, &line, &col);
for (Instruction& inst : block) {
modified |= line_process_func_(&inst, &file_id, &line, &col);
// Don't process terminal instruction if preceeded by merge
if (inst.opcode() == SpvOpSelectionMerge ||
inst.opcode() == SpvOpLoopMerge)
break;
}
// Nullify line info after each block.
file_id = 0;
}
modified |= line_process_func_(function.EndInst(), &file_id, &line, &col);
}
return modified;
}
bool ProcessLinesPass::PropagateLine(Instruction* inst, uint32_t* file_id,
uint32_t* line, uint32_t* col) {
bool modified = false;
// only the last debug instruction needs to be considered
auto line_itr = inst->dbg_line_insts().rbegin();
// if no line instructions, propagate previous info
if (line_itr == inst->dbg_line_insts().rend()) {
// if no current line info, add OpNoLine, else OpLine
if (*file_id == 0)
inst->dbg_line_insts().push_back(Instruction(context(), SpvOpNoLine));
else
inst->dbg_line_insts().push_back(Instruction(
context(), SpvOpLine, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*file_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {*line}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {*col}}}));
modified = true;
} else {
// else pre-existing line instruction, so update source line info
if (line_itr->opcode() == SpvOpNoLine) {
*file_id = 0;
} else {
assert(line_itr->opcode() == SpvOpLine && "unexpected debug inst");
*file_id = line_itr->GetSingleWordInOperand(kSpvLineFileInIdx);
*line = line_itr->GetSingleWordInOperand(kSpvLineLineInIdx);
*col = line_itr->GetSingleWordInOperand(kSpvLineColInIdx);
}
}
return modified;
}
bool ProcessLinesPass::EliminateDeadLines(Instruction* inst, uint32_t* file_id,
uint32_t* line, uint32_t* col) {
// If no debug line instructions, return without modifying lines
if (inst->dbg_line_insts().empty()) return false;
// Only the last debug instruction needs to be considered; delete all others
bool modified = inst->dbg_line_insts().size() > 1;
Instruction last_inst = inst->dbg_line_insts().back();
inst->dbg_line_insts().clear();
// If last line is OpNoLine
if (last_inst.opcode() == SpvOpNoLine) {
// If no propagated line info, throw away redundant OpNoLine
if (*file_id == 0) {
modified = true;
// Else replace OpNoLine and propagate no line info
} else {
inst->dbg_line_insts().push_back(last_inst);
*file_id = 0;
}
} else {
// Else last line is OpLine
assert(last_inst.opcode() == SpvOpLine && "unexpected debug inst");
// If propagated info matches last line, throw away last line
if (*file_id == last_inst.GetSingleWordInOperand(kSpvLineFileInIdx) &&
*line == last_inst.GetSingleWordInOperand(kSpvLineLineInIdx) &&
*col == last_inst.GetSingleWordInOperand(kSpvLineColInIdx)) {
modified = true;
} else {
// Else replace last line and propagate line info
*file_id = last_inst.GetSingleWordInOperand(kSpvLineFileInIdx);
*line = last_inst.GetSingleWordInOperand(kSpvLineLineInIdx);
*col = last_inst.GetSingleWordInOperand(kSpvLineColInIdx);
inst->dbg_line_insts().push_back(last_inst);
}
}
return modified;
}
ProcessLinesPass::ProcessLinesPass(uint32_t func_id) {
if (func_id == kLinesPropagateLines) {
line_process_func_ = [this](Instruction* inst, uint32_t* file_id,
uint32_t* line, uint32_t* col) {
return PropagateLine(inst, file_id, line, col);
};
} else {
assert(func_id == kLinesEliminateDeadLines && "unknown Lines param");
line_process_func_ = [this](Instruction* inst, uint32_t* file_id,
uint32_t* line, uint32_t* col) {
return EliminateDeadLines(inst, file_id, line, col);
};
}
}
} // namespace opt
} // namespace spvtools

View File

@@ -1,87 +0,0 @@
// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018 Valve Corporation
// Copyright (c) 2018 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_OPT_PROPAGATE_LINES_PASS_H_
#define SOURCE_OPT_PROPAGATE_LINES_PASS_H_
#include "source/opt/function.h"
#include "source/opt/ir_context.h"
#include "source/opt/pass.h"
namespace spvtools {
namespace opt {
namespace {
// Constructor Parameters
static const int kLinesPropagateLines = 0;
static const int kLinesEliminateDeadLines = 1;
} // anonymous namespace
// See optimizer.hpp for documentation.
class ProcessLinesPass : public Pass {
using LineProcessFunction =
std::function<bool(Instruction*, uint32_t*, uint32_t*, uint32_t*)>;
public:
ProcessLinesPass(uint32_t func_id);
~ProcessLinesPass() override = default;
const char* name() const override { return "propagate-lines"; }
// See optimizer.hpp for this pass' user documentation.
Status Process() override;
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse |
IRContext::kAnalysisInstrToBlockMapping |
IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis |
IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants |
IRContext::kAnalysisTypes;
}
private:
// If |inst| has no debug line instruction, create one with
// |file_id, line, col|. If |inst| has debug line instructions, set
// |file_id, line, col| from the last. |file_id| equals 0 indicates no line
// info is available. Return true if |inst| modified.
bool PropagateLine(Instruction* inst, uint32_t* file_id, uint32_t* line,
uint32_t* col);
// If last debug line instruction of |inst| matches |file_id, line, col|,
// delete all debug line instructions of |inst|. If they do not match,
// replace all debug line instructions of |inst| with new line instruction
// set from |file_id, line, col|. If |inst| has no debug line instructions,
// do not modify |inst|. |file_id| equals 0 indicates no line info is
// available. Return true if |inst| modified.
bool EliminateDeadLines(Instruction* inst, uint32_t* file_id, uint32_t* line,
uint32_t* col);
// Apply lpfn() to all type, constant, global variable and function
// instructions in their physical order.
bool ProcessLines();
// A function that calls either PropagateLine or EliminateDeadLines.
// Initialized by the class constructor.
LineProcessFunction line_process_func_;
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_PROPAGATE_LINES_PASS_H_

View File

@@ -66,6 +66,7 @@ namespace opt {
namespace {
const uint32_t kStoreValIdInIdx = 1;
const uint32_t kVariableInitIdInIdx = 1;
const uint32_t kDebugDeclareOperandVariableIdx = 5;
} // namespace
std::string SSARewriter::PhiCandidate::PrettyPrint(const CFG* cfg) const {
@@ -241,8 +242,8 @@ uint32_t SSARewriter::AddPhiOperands(PhiCandidate* phi_candidate) {
return repl_id;
}
uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) {
// If |var_id| has a definition in |bb|, return it.
uint32_t SSARewriter::GetValueAtBlock(uint32_t var_id, BasicBlock* bb) {
assert(bb != nullptr);
const auto& bb_it = defs_at_block_.find(bb);
if (bb_it != defs_at_block_.end()) {
const auto& current_defs = bb_it->second;
@@ -251,9 +252,15 @@ uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) {
return var_it->second;
}
}
return 0;
}
uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) {
// If |var_id| has a definition in |bb|, return it.
uint32_t val_id = GetValueAtBlock(var_id, bb);
if (val_id != 0) return val_id;
// Otherwise, look up the value for |var_id| in |bb|'s predecessors.
uint32_t val_id = 0;
auto& predecessors = pass_->cfg()->preds(bb->id());
if (predecessors.size() == 1) {
// If |bb| has exactly one predecessor, we look for |var_id|'s definition
@@ -308,7 +315,7 @@ void SSARewriter::ProcessStore(Instruction* inst, BasicBlock* bb) {
if (pass_->IsTargetVar(var_id)) {
WriteVariable(var_id, bb, val_id);
pass_->context()->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible(
inst, var_id, val_id, inst);
inst, var_id, val_id, inst, &decls_invisible_to_value_assignment_);
#if SSA_REWRITE_DEBUGGING_LEVEL > 1
std::cerr << "\tFound store '%" << var_id << " = %" << val_id << "': "
@@ -439,8 +446,6 @@ bool SSARewriter::ApplyReplacements() {
// Add Phi instructions from completed Phi candidates.
std::vector<Instruction*> generated_phis;
// Add DebugValue instructions for Phi instructions.
std::vector<Instruction*> dbg_values_for_phis;
for (const PhiCandidate* phi_candidate : phis_to_generate_) {
#if SSA_REWRITE_DEBUGGING_LEVEL > 2
std::cerr << "Phi candidate: " << phi_candidate->PrettyPrint(pass_->cfg())
@@ -493,7 +498,7 @@ bool SSARewriter::ApplyReplacements() {
insert_it->SetDebugScope(local_var->GetDebugScope());
pass_->context()->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible(
&*insert_it, phi_candidate->var_id(), phi_candidate->result_id(),
&*insert_it);
&*insert_it, &decls_invisible_to_value_assignment_);
modified = true;
}
@@ -581,6 +586,61 @@ void SSARewriter::FinalizePhiCandidates() {
}
}
Pass::Status SSARewriter::AddDebugValuesForInvisibleDebugDecls(Function* fp) {
// For the cases the value assignment is invisible to DebugDeclare e.g.,
// the argument passing for an inlined function.
//
// Before inlining foo(int x):
// a = 3;
// foo(3);
// After inlining:
// a = 3; // we want to specify "DebugValue: %x = %int_3"
// foo and x disappeared!
//
// We want to specify the value for the variable using |defs_at_block_[bb]|,
// where |bb| is the basic block contains the decl.
DominatorAnalysis* dom_tree = pass_->context()->GetDominatorAnalysis(fp);
Pass::Status status = Pass::Status::SuccessWithoutChange;
for (auto* decl : decls_invisible_to_value_assignment_) {
uint32_t var_id =
decl->GetSingleWordOperand(kDebugDeclareOperandVariableIdx);
auto* var = pass_->get_def_use_mgr()->GetDef(var_id);
if (var->opcode() == SpvOpFunctionParameter) continue;
auto* bb = pass_->context()->get_instr_block(decl);
uint32_t value_id = GetValueAtBlock(var_id, bb);
Instruction* value = nullptr;
if (value_id) value = pass_->get_def_use_mgr()->GetDef(value_id);
// If |value| is defined before the function body, it dominates |decl|.
// If |value| dominates |decl|, we can set it as DebugValue.
if (value && (pass_->context()->get_instr_block(value) == nullptr ||
dom_tree->Dominates(value, decl))) {
if (!pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl(
decl, value->result_id())) {
return Pass::Status::Failure;
}
} else {
// If |value| in the same basic block does not dominate |decl|, we can
// assign the value in the immediate dominator.
value_id = GetValueAtBlock(var_id, dom_tree->ImmediateDominator(bb));
if (value_id &&
!pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl(
decl, value_id)) {
return Pass::Status::Failure;
}
}
// DebugDeclares of target variables will be removed by
// SSARewritePass::Process().
if (!pass_->IsTargetVar(var_id)) {
pass_->context()->get_debug_info_mgr()->KillDebugDeclares(var_id);
}
status = Pass::Status::SuccessWithChange;
}
return status;
}
Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
#if SSA_REWRITE_DEBUGGING_LEVEL > 0
std::cerr << "Function before SSA rewrite:\n"
@@ -610,6 +670,12 @@ Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
// Finally, apply all the replacements in the IR.
bool modified = ApplyReplacements();
auto status = AddDebugValuesForInvisibleDebugDecls(fp);
if (status == Pass::Status::SuccessWithChange ||
status == Pass::Status::Failure) {
return status;
}
#if SSA_REWRITE_DEBUGGING_LEVEL > 0
std::cerr << "\n\n\nFunction after SSA rewrite:\n"
<< fp->PrettyPrint(0) << "\n";

View File

@@ -192,6 +192,10 @@ class SSARewriter {
}
}
// Returns the value of |var_id| at |bb| if |defs_at_block_| contains it.
// Otherwise, returns 0.
uint32_t GetValueAtBlock(uint32_t var_id, BasicBlock* bb);
// Processes the store operation |inst| in basic block |bb|. This extracts
// the variable ID being stored into, determines whether the variable is an
// SSA-target variable, and, if it is, it stores its value in the
@@ -249,6 +253,11 @@ class SSARewriter {
// candidates.
void FinalizePhiCandidates();
// Adds DebugValues for DebugDeclares in
// |decls_invisible_to_value_assignment_|. Returns whether the function was
// modified or not, and whether or not the conversion was successful.
Pass::Status AddDebugValuesForInvisibleDebugDecls(Function* fp);
// Prints the table of Phi candidates to std::cerr.
void PrintPhiCandidates() const;
@@ -286,6 +295,10 @@ class SSARewriter {
// Memory pass requesting the SSA rewriter.
MemPass* pass_;
// Set of DebugDeclare instructions that are not added as DebugValue because
// they are invisible to the store or phi instructions.
std::unordered_set<Instruction*> decls_invisible_to_value_assignment_;
};
class SSARewritePass : public MemPass {

View File

@@ -78,7 +78,7 @@ endif()
spvtools_pch(SPIRV_TOOLS_REDUCE_SOURCES pch_source_reduce)
add_library(SPIRV-Tools-reduce STATIC ${SPIRV_TOOLS_REDUCE_SOURCES})
add_library(SPIRV-Tools-reduce ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_TOOLS_REDUCE_SOURCES})
spvtools_default_compile_options(SPIRV-Tools-reduce)
target_include_directories(SPIRV-Tools-reduce
@@ -90,7 +90,7 @@ target_include_directories(SPIRV-Tools-reduce
)
# The reducer reuses a lot of functionality from the SPIRV-Tools library.
target_link_libraries(SPIRV-Tools-reduce
PUBLIC ${SPIRV_TOOLS}-static
PUBLIC ${SPIRV_TOOLS_FULL_VISIBILITY}
PUBLIC SPIRV-Tools-opt)
set_property(TARGET SPIRV-Tools-reduce PROPERTY FOLDER "SPIRV-Tools libraries")

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2017 Google Inc.
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
// reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -151,7 +153,9 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
}
if (spvIsVulkanEnv(_.context()->target_env) &&
_.GetBitWidth(result_type) != 32) {
(_.GetBitWidth(result_type) != 32 &&
(_.GetBitWidth(result_type) != 64 ||
!_.HasCapability(SpvCapabilityInt64ImageEXT)))) {
switch (opcode) {
case SpvOpAtomicSMin:
case SpvOpAtomicUMin:

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2018 Google LLC.
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
// reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,8 +16,6 @@
// Validates correctness of built-in variables.
#include "source/val/validate.h"
#include <functional>
#include <list>
#include <map>
@@ -31,6 +31,7 @@
#include "source/spirv_target_env.h"
#include "source/util/bitutils.h"
#include "source/val/instruction.h"
#include "source/val/validate.h"
#include "source/val/validation_state.h"
namespace spvtools {
@@ -230,6 +231,12 @@ class BuiltInsValidator {
spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration,
const Instruction& inst);
spv_result_t ValidatePrimitiveShadingRateAtDefinition(
const Decoration& decoration, const Instruction& inst);
spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration,
const Instruction& inst);
// The following section contains functions which are called when id defined
// by |referenced_inst| is
// 1. referenced by |referenced_from_inst|
@@ -383,6 +390,16 @@ class BuiltInsValidator {
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
spv_result_t ValidatePrimitiveShadingRateAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
spv_result_t ValidateShadingRateAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
// Validates that |built_in_inst| is not (even indirectly) referenced from
// within a function which can be called with |execution_model|.
//
@@ -2623,12 +2640,26 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference(
case SpvExecutionModelVertex:
case SpvExecutionModelTessellationEvaluation: {
if (!_.HasCapability(SpvCapabilityShaderViewportIndexLayerEXT)) {
if (operand == SpvBuiltInViewportIndex &&
_.HasCapability(SpvCapabilityShaderViewportIndex))
break; // Ok
if (operand == SpvBuiltInLayer &&
_.HasCapability(SpvCapabilityShaderLayer))
break; // Ok
const char* capability = "ShaderViewportIndexLayerEXT";
if (operand == SpvBuiltInViewportIndex)
capability = "ShaderViewportIndexLayerEXT or ShaderViewportIndex";
if (operand == SpvBuiltInLayer)
capability = "ShaderViewportIndexLayerEXT or ShaderLayer";
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< "Using BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
operand)
<< " in Vertex or Tessellation execution model requires "
"the ShaderViewportIndexLayerEXT capability.";
<< " in Vertex or Tessellation execution model requires the "
<< capability << " capability.";
}
break;
}
@@ -3314,6 +3345,142 @@ spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtReference(
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
if (spv_result_t error = ValidateI32(
decoration, inst,
[this, &inst,
&decoration](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(4486)
<< "According to the Vulkan spec BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 32-bit int scalar. "
<< message;
})) {
return error;
}
}
// Seed at reference checks with this built-in.
return ValidatePrimitiveShadingRateAtReference(decoration, inst, inst, inst);
}
spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassOutput) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(4485) << "Vulkan spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be only used for variables with Output storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
<< " " << GetStorageClassDesc(referenced_from_inst);
}
for (const SpvExecutionModel execution_model : execution_models_) {
switch (execution_model) {
case SpvExecutionModelVertex:
case SpvExecutionModelGeometry:
case SpvExecutionModelMeshNV:
break;
default: {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(4484) << "Vulkan spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be used only with Vertex, Geometry, or MeshNV "
"execution models. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
}
}
}
}
if (function_id_ == 0) {
// Propagate this rule to all dependant ids in the global scope.
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
std::bind(&BuiltInsValidator::ValidatePrimitiveShadingRateAtReference,
this, decoration, built_in_inst, referenced_from_inst,
std::placeholders::_1));
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateShadingRateAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
if (spv_result_t error = ValidateI32(
decoration, inst,
[this, &inst,
&decoration](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(4492)
<< "According to the Vulkan spec BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 32-bit int scalar. "
<< message;
})) {
return error;
}
}
// Seed at reference checks with this built-in.
return ValidateShadingRateAtReference(decoration, inst, inst, inst);
}
spv_result_t BuiltInsValidator::ValidateShadingRateAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(4491) << "Vulkan spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
<< " " << GetStorageClassDesc(referenced_from_inst);
}
for (const SpvExecutionModel execution_model : execution_models_) {
if (execution_model != SpvExecutionModelFragment) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(4490) << "Vulkan spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be used only with the Fragment execution model. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
}
}
}
if (function_id_ == 0) {
// Propagate this rule to all dependant ids in the global scope.
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
&BuiltInsValidator::ValidateShadingRateAtReference, this, decoration,
built_in_inst, referenced_from_inst, std::placeholders::_1));
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
const Decoration& decoration, const Instruction& inst) {
const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
@@ -3514,6 +3681,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case SpvBuiltInRayGeometryIndexKHR: {
// No validation rules (for the moment).
break;
case SpvBuiltInPrimitiveShadingRateKHR:
return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
case SpvBuiltInShadingRateKHR:
return ValidateShadingRateAtDefinition(decoration, inst);
}
}
return SPV_SUCCESS;

View File

@@ -89,6 +89,8 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) {
<< block->predecessors()->size() << ").";
}
std::unordered_set<uint32_t> observed_predecessors;
for (size_t i = 3; i < inst->words().size(); ++i) {
auto inc_id = inst->word(i);
if (i % 2 == 1) {
@@ -115,6 +117,17 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) {
<< " is not a predecessor of <id> " << _.getIdName(block->id())
<< ".";
}
// We must not have already seen this predecessor as one of the phi's
// operands.
if (observed_predecessors.count(inc_id) != 0) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpPhi references incoming basic block <id> "
<< _.getIdName(inc_id) << " multiple times.";
}
// Note the fact that we have now observed this predecessor.
observed_predecessors.insert(inc_id);
}
}

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2017 Google Inc.
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
// reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -737,7 +739,9 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
if ((!_.IsFloatScalarType(info.sampled_type) &&
!_.IsIntScalarType(info.sampled_type)) ||
32 != _.GetBitWidth(info.sampled_type)) {
(32 != _.GetBitWidth(info.sampled_type) &&
(64 != _.GetBitWidth(info.sampled_type) ||
!_.HasCapability(SpvCapabilityInt64ImageEXT)))) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Sampled Type to be a 32-bit int or float "
"scalar type for Vulkan environment";