mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-20 22:03:12 +01:00
Updated spirv-tools.
This commit is contained in:
1
3rdparty/spirv-tools/Android.mk
vendored
1
3rdparty/spirv-tools/Android.mk
vendored
@@ -76,6 +76,7 @@ SPVTOOLS_OPT_SRC_FILES := \
|
||||
source/opt/aggressive_dead_code_elim_pass.cpp \
|
||||
source/opt/basic_block.cpp \
|
||||
source/opt/block_merge_pass.cpp \
|
||||
source/opt/block_merge_util.cpp \
|
||||
source/opt/build_module.cpp \
|
||||
source/opt/cfg.cpp \
|
||||
source/opt/cfg_cleanup_pass.cpp \
|
||||
|
||||
17
3rdparty/spirv-tools/README.md
vendored
17
3rdparty/spirv-tools/README.md
vendored
@@ -128,6 +128,23 @@ See the [CHANGES](CHANGES) file for reports on completed work, and the [General
|
||||
sub-project](https://github.com/KhronosGroup/SPIRV-Tools/projects/2) for
|
||||
planned and in-progress work.
|
||||
|
||||
|
||||
### Reducer
|
||||
|
||||
*Note:* The reducer is still under development.
|
||||
|
||||
The reducer simplifies and shrinks a SPIR-V module with respect to a
|
||||
user-supplied *interestingness function*. For example, given a large
|
||||
SPIR-V module that cause some SPIR-V compiler to fail with a given
|
||||
fatal error message, the reducer could be used to look for a smaller
|
||||
version of the module that causes the compiler to fail with the same
|
||||
fatal error message.
|
||||
|
||||
To suggest an additional capability for the reducer, [file an
|
||||
issue](https://github.com/KhronosGroup/SPIRV-Tools/issues]) with
|
||||
"Reducer:" as the start of its title.
|
||||
|
||||
|
||||
### Extras
|
||||
|
||||
* [Utility filters](#utility-filters)
|
||||
|
||||
@@ -1 +1 @@
|
||||
"v2019.2-dev", "SPIRV-Tools v2019.2-dev 7d149d91055744e5a9bc6368de7b3bb605d0e1a9"
|
||||
"v2019.2-dev", "SPIRV-Tools v2019.2-dev eae8dd2d23578d8b3cbb404d2caa01b27d69da15"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
static const SpvCapability pygen_variable_caps_Addresses[] = {SpvCapabilityAddresses};
|
||||
static const SpvCapability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBuffer[] = {SpvCapabilityAddresses, SpvCapabilityVariablePointers, SpvCapabilityVariablePointersStorageBuffer};
|
||||
static const SpvCapability pygen_variable_caps_AddressesPhysicalStorageBufferAddressesEXT[] = {SpvCapabilityAddresses, SpvCapabilityPhysicalStorageBufferAddressesEXT};
|
||||
static const SpvCapability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBufferPhysicalStorageBufferAddressesEXT[] = {SpvCapabilityAddresses, SpvCapabilityVariablePointers, SpvCapabilityVariablePointersStorageBuffer, SpvCapabilityPhysicalStorageBufferAddressesEXT};
|
||||
static const SpvCapability pygen_variable_caps_DerivativeControl[] = {SpvCapabilityDerivativeControl};
|
||||
static const SpvCapability pygen_variable_caps_DeviceEnqueue[] = {SpvCapabilityDeviceEnqueue};
|
||||
static const SpvCapability pygen_variable_caps_FragmentMaskAMD[] = {SpvCapabilityFragmentMaskAMD};
|
||||
@@ -82,7 +83,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
|
||||
{"TypeReserveId", SpvOpTypeReserveId, 1, pygen_variable_caps_Pipes, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"TypeQueue", SpvOpTypeQueue, 1, pygen_variable_caps_DeviceEnqueue, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"TypePipe", SpvOpTypePipe, 1, pygen_variable_caps_Pipes, 2, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ACCESS_QUALIFIER}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"TypeForwardPointer", SpvOpTypeForwardPointer, 1, pygen_variable_caps_Addresses, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_STORAGE_CLASS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"TypeForwardPointer", SpvOpTypeForwardPointer, 2, pygen_variable_caps_AddressesPhysicalStorageBufferAddressesEXT, 2, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_STORAGE_CLASS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"ConstantTrue", SpvOpConstantTrue, 0, nullptr, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"ConstantFalse", SpvOpConstantFalse, 0, nullptr, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"Constant", SpvOpConstant, 0, nullptr, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
@@ -106,7 +107,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
|
||||
{"CopyMemorySized", SpvOpCopyMemorySized, 1, pygen_variable_caps_Addresses, 4, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"AccessChain", SpvOpAccessChain, 0, nullptr, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"InBoundsAccessChain", SpvOpInBoundsAccessChain, 0, nullptr, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"PtrAccessChain", SpvOpPtrAccessChain, 3, pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBuffer, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"PtrAccessChain", SpvOpPtrAccessChain, 4, pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBufferPhysicalStorageBufferAddressesEXT, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"ArrayLength", SpvOpArrayLength, 1, pygen_variable_caps_Shader, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"GenericPtrMemSemantics", SpvOpGenericPtrMemSemantics, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"InBoundsPtrAccessChain", SpvOpInBoundsPtrAccessChain, 1, pygen_variable_caps_Addresses, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
@@ -153,10 +154,10 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
|
||||
{"SConvert", SpvOpSConvert, 0, nullptr, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"FConvert", SpvOpFConvert, 0, nullptr, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"QuantizeToF16", SpvOpQuantizeToF16, 0, nullptr, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"ConvertPtrToU", SpvOpConvertPtrToU, 1, pygen_variable_caps_Addresses, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"ConvertPtrToU", SpvOpConvertPtrToU, 2, pygen_variable_caps_AddressesPhysicalStorageBufferAddressesEXT, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"SatConvertSToU", SpvOpSatConvertSToU, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"SatConvertUToS", SpvOpSatConvertUToS, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"ConvertUToPtr", SpvOpConvertUToPtr, 1, pygen_variable_caps_Addresses, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"ConvertUToPtr", SpvOpConvertUToPtr, 2, pygen_variable_caps_AddressesPhysicalStorageBufferAddressesEXT, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"PtrCastToGeneric", SpvOpPtrCastToGeneric, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"GenericCastToPtr", SpvOpGenericCastToPtr, 1, pygen_variable_caps_Kernel, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"GenericCastToPtrExplicit", SpvOpGenericCastToPtrExplicit, 1, pygen_variable_caps_Kernel, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_STORAGE_CLASS}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
|
||||
@@ -26,6 +26,8 @@ const char* ExtensionToString(Extension extension) {
|
||||
return "SPV_EXT_fragment_fully_covered";
|
||||
case Extension::kSPV_EXT_fragment_invocation_density:
|
||||
return "SPV_EXT_fragment_invocation_density";
|
||||
case Extension::kSPV_EXT_physical_storage_buffer:
|
||||
return "SPV_EXT_physical_storage_buffer";
|
||||
case Extension::kSPV_EXT_shader_stencil_export:
|
||||
return "SPV_EXT_shader_stencil_export";
|
||||
case Extension::kSPV_EXT_shader_viewport_index_layer:
|
||||
@@ -97,8 +99,8 @@ const char* ExtensionToString(Extension extension) {
|
||||
|
||||
|
||||
bool GetExtensionFromString(const char* str, Extension* extension) {
|
||||
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_INTEL_subgroups", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_vote", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_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_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
|
||||
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_INTEL_subgroups, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_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_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
|
||||
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_INTEL_subgroups", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_device_group", "SPV_KHR_float_controls", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_vote", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_compute_shader_derivatives", "SPV_NV_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_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
|
||||
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_INTEL_subgroups, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_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_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(
|
||||
@@ -364,6 +366,8 @@ const char* CapabilityToString(SpvCapability capability) {
|
||||
return "ComputeDerivativeGroupLinearNV";
|
||||
case SpvCapabilityFragmentDensityEXT:
|
||||
return "FragmentDensityEXT";
|
||||
case SpvCapabilityPhysicalStorageBufferAddressesEXT:
|
||||
return "PhysicalStorageBufferAddressesEXT";
|
||||
case SpvCapabilityMax:
|
||||
assert(0 && "Attempting to convert SpvCapabilityMax to string");
|
||||
return "";
|
||||
|
||||
@@ -11,6 +11,7 @@ kSPV_AMD_texture_gather_bias_lod,
|
||||
kSPV_EXT_descriptor_indexing,
|
||||
kSPV_EXT_fragment_fully_covered,
|
||||
kSPV_EXT_fragment_invocation_density,
|
||||
kSPV_EXT_physical_storage_buffer,
|
||||
kSPV_EXT_shader_stencil_export,
|
||||
kSPV_EXT_shader_viewport_index_layer,
|
||||
kSPV_GOOGLE_decorate_string,
|
||||
|
||||
@@ -42,6 +42,7 @@ 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_PerViewAttributesNVMeshShadingNV[] = {SpvCapabilityPerViewAttributesNV, SpvCapabilityMeshShadingNV};
|
||||
static const SpvCapability pygen_variable_caps_PhysicalStorageBufferAddressesEXT[] = {SpvCapabilityPhysicalStorageBufferAddressesEXT};
|
||||
static const SpvCapability pygen_variable_caps_Pipes[] = {SpvCapabilityPipes};
|
||||
static const SpvCapability pygen_variable_caps_RayTracingNV[] = {SpvCapabilityRayTracingNV};
|
||||
static const SpvCapability pygen_variable_caps_RoundingModeRTE[] = {SpvCapabilityRoundingModeRTE};
|
||||
@@ -87,6 +88,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_AMD_texture_gather_bias
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_descriptor_indexing[] = {spvtools::Extension::kSPV_EXT_descriptor_indexing};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_fully_covered[] = {spvtools::Extension::kSPV_EXT_fragment_fully_covered};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate[] = {spvtools::Extension::kSPV_EXT_fragment_invocation_density, spvtools::Extension::kSPV_NV_shading_rate};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_EXT_physical_storage_buffer[] = {spvtools::Extension::kSPV_EXT_physical_storage_buffer};
|
||||
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_layer[] = {spvtools::Extension::kSPV_EXT_shader_viewport_index_layer};
|
||||
static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1};
|
||||
@@ -231,7 +233,8 @@ static const spv_operand_desc_t pygen_variable_ExecutionModelEntries[] = {
|
||||
static const spv_operand_desc_t pygen_variable_AddressingModelEntries[] = {
|
||||
{"Logical", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"Physical32", 1, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"Physical64", 2, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)}
|
||||
{"Physical64", 2, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"PhysicalStorageBuffer64EXT", 5348, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1, 0)}
|
||||
};
|
||||
|
||||
static const spv_operand_desc_t pygen_variable_MemoryModelEntries[] = {
|
||||
@@ -313,7 +316,8 @@ static const spv_operand_desc_t pygen_variable_StorageClassEntries[] = {
|
||||
{"RayPayloadNV", 5338, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"HitAttributeNV", 5339, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"IncomingRayPayloadNV", 5342, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"ShaderRecordBufferNV", 5343, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)}
|
||||
{"ShaderRecordBufferNV", 5343, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"PhysicalStorageBufferEXT", 5349, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1, 0)}
|
||||
};
|
||||
|
||||
static const spv_operand_desc_t pygen_variable_DimEntries[] = {
|
||||
@@ -513,6 +517,8 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
|
||||
{"PerTaskNV", 5273, 1, pygen_variable_caps_MeshShadingNV, 1, pygen_variable_exts_SPV_NV_mesh_shader, {}, 0xffffffffu},
|
||||
{"PerVertexNV", 5285, 1, pygen_variable_caps_FragmentBarycentricNV, 1, pygen_variable_exts_SPV_NV_fragment_shader_barycentric, {}, 0xffffffffu},
|
||||
{"NonUniformEXT", 5300, 1, pygen_variable_caps_ShaderNonUniformEXT, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0)},
|
||||
{"RestrictPointerEXT", 5355, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu},
|
||||
{"AliasedPointerEXT", 5356, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu},
|
||||
{"HlslCounterBufferGOOGLE", 5634, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_ID}, 0xffffffffu},
|
||||
{"HlslSemanticGOOGLE", 5635, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_LITERAL_STRING}, 0xffffffffu}
|
||||
};
|
||||
@@ -769,6 +775,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
|
||||
{"RayTracingNV", 5340, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu},
|
||||
{"VulkanMemoryModelKHR", 5345, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, 0xffffffffu},
|
||||
{"VulkanMemoryModelDeviceScopeKHR", 5346, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, 0xffffffffu},
|
||||
{"PhysicalStorageBufferAddressesEXT", 5347, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu},
|
||||
{"ComputeDerivativeGroupLinearNV", 5350, 0, nullptr, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu},
|
||||
{"SubgroupShuffleINTEL", 5568, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu},
|
||||
{"SubgroupBufferBlockIOINTEL", 5569, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu},
|
||||
|
||||
@@ -235,6 +235,9 @@ class SpirvTools {
|
||||
bool Validate(const uint32_t* binary, size_t binary_size,
|
||||
spv_validator_options options) const;
|
||||
|
||||
// Was this object successfully constructed.
|
||||
bool IsValid() const;
|
||||
|
||||
private:
|
||||
struct Impl; // Opaque struct for holding the data fields used by this class.
|
||||
std::unique_ptr<Impl> impl_; // Unique pointer to implementation data.
|
||||
|
||||
2
3rdparty/spirv-tools/source/libspirv.cpp
vendored
2
3rdparty/spirv-tools/source/libspirv.cpp
vendored
@@ -128,4 +128,6 @@ bool SpirvTools::Validate(const uint32_t* binary, const size_t binary_size,
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool SpirvTools::IsValid() const { return impl_->context != nullptr; }
|
||||
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -15,6 +15,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
||||
aggressive_dead_code_elim_pass.h
|
||||
basic_block.h
|
||||
block_merge_pass.h
|
||||
block_merge_util.h
|
||||
build_module.h
|
||||
ccp_pass.h
|
||||
cfg_cleanup_pass.h
|
||||
@@ -108,6 +109,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
||||
aggressive_dead_code_elim_pass.cpp
|
||||
basic_block.cpp
|
||||
block_merge_pass.cpp
|
||||
block_merge_util.cpp
|
||||
build_module.cpp
|
||||
ccp_pass.cpp
|
||||
cfg_cleanup_pass.cpp
|
||||
|
||||
106
3rdparty/spirv-tools/source/opt/block_merge_pass.cpp
vendored
106
3rdparty/spirv-tools/source/opt/block_merge_pass.cpp
vendored
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "source/opt/block_merge_util.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/opt/iterator.h"
|
||||
|
||||
@@ -27,112 +28,17 @@ namespace opt {
|
||||
bool BlockMergePass::MergeBlocks(Function* func) {
|
||||
bool modified = false;
|
||||
for (auto bi = func->begin(); bi != func->end();) {
|
||||
// Find block with single successor which has no other predecessors.
|
||||
auto ii = bi->end();
|
||||
--ii;
|
||||
Instruction* br = &*ii;
|
||||
if (br->opcode() != SpvOpBranch) {
|
||||
if (blockmergeutil::CanMergeWithSuccessor(context(), &*bi)) {
|
||||
blockmergeutil::MergeWithSuccessor(context(), func, bi);
|
||||
// Reprocess block.
|
||||
modified = true;
|
||||
} else {
|
||||
++bi;
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t lab_id = br->GetSingleWordInOperand(0);
|
||||
if (cfg()->preds(lab_id).size() != 1) {
|
||||
++bi;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool pred_is_merge = IsMerge(&*bi);
|
||||
bool succ_is_merge = IsMerge(lab_id);
|
||||
if (pred_is_merge && succ_is_merge) {
|
||||
// Cannot merge two merges together.
|
||||
++bi;
|
||||
continue;
|
||||
}
|
||||
|
||||
Instruction* merge_inst = bi->GetMergeInst();
|
||||
bool pred_is_header = IsHeader(&*bi);
|
||||
if (pred_is_header && lab_id != merge_inst->GetSingleWordInOperand(0u)) {
|
||||
bool succ_is_header = IsHeader(lab_id);
|
||||
if (pred_is_header && succ_is_header) {
|
||||
// Cannot merge two headers together when the successor is not the merge
|
||||
// block of the predecessor.
|
||||
++bi;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is a header block and the successor is not its merge, we must
|
||||
// be careful about which blocks we are willing to merge together.
|
||||
// OpLoopMerge must be followed by a conditional or unconditional branch.
|
||||
// The merge must be a loop merge because a selection merge cannot be
|
||||
// followed by an unconditional branch.
|
||||
BasicBlock* succ_block = context()->get_instr_block(lab_id);
|
||||
SpvOp succ_term_op = succ_block->terminator()->opcode();
|
||||
assert(merge_inst->opcode() == SpvOpLoopMerge);
|
||||
if (succ_term_op != SpvOpBranch &&
|
||||
succ_term_op != SpvOpBranchConditional) {
|
||||
++bi;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge blocks.
|
||||
context()->KillInst(br);
|
||||
auto sbi = bi;
|
||||
for (; sbi != func->end(); ++sbi)
|
||||
if (sbi->id() == lab_id) break;
|
||||
// If bi is sbi's only predecessor, it dominates sbi and thus
|
||||
// sbi must follow bi in func's ordering.
|
||||
assert(sbi != func->end());
|
||||
|
||||
// Update the inst-to-block mapping for the instructions in sbi.
|
||||
for (auto& inst : *sbi) {
|
||||
context()->set_instr_block(&inst, &*bi);
|
||||
}
|
||||
|
||||
// Now actually move the instructions.
|
||||
bi->AddInstructions(&*sbi);
|
||||
|
||||
if (merge_inst) {
|
||||
if (pred_is_header && lab_id == merge_inst->GetSingleWordInOperand(0u)) {
|
||||
// Merging the header and merge blocks, so remove the structured control
|
||||
// flow declaration.
|
||||
context()->KillInst(merge_inst);
|
||||
} else {
|
||||
// Move the merge instruction to just before the terminator.
|
||||
merge_inst->InsertBefore(bi->terminator());
|
||||
}
|
||||
}
|
||||
context()->ReplaceAllUsesWith(lab_id, bi->id());
|
||||
context()->KillInst(sbi->GetLabelInst());
|
||||
(void)sbi.Erase();
|
||||
// Reprocess block.
|
||||
modified = true;
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool BlockMergePass::IsHeader(BasicBlock* block) {
|
||||
return block->GetMergeInst() != nullptr;
|
||||
}
|
||||
|
||||
bool BlockMergePass::IsHeader(uint32_t id) {
|
||||
return IsHeader(context()->get_instr_block(get_def_use_mgr()->GetDef(id)));
|
||||
}
|
||||
|
||||
bool BlockMergePass::IsMerge(uint32_t id) {
|
||||
return !get_def_use_mgr()->WhileEachUse(id, [](Instruction* user,
|
||||
uint32_t index) {
|
||||
SpvOp op = user->opcode();
|
||||
if ((op == SpvOpLoopMerge || op == SpvOpSelectionMerge) && index == 0u) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool BlockMergePass::IsMerge(BasicBlock* block) { return IsMerge(block->id()); }
|
||||
|
||||
Pass::Status BlockMergePass::Process() {
|
||||
// Process all entry point functions.
|
||||
ProcessFunction pfn = [this](Function* fp) { return MergeBlocks(fp); };
|
||||
|
||||
@@ -54,14 +54,6 @@ class BlockMergePass : public Pass {
|
||||
// with no other predecessors. Merge these blocks into a single block.
|
||||
bool MergeBlocks(Function* func);
|
||||
|
||||
// Returns true if |block| (or |id|) contains a merge instruction.
|
||||
bool IsHeader(BasicBlock* block);
|
||||
bool IsHeader(uint32_t id);
|
||||
|
||||
// Returns true if |block| (or |id|) is the merge target of a merge
|
||||
// instruction.
|
||||
bool IsMerge(BasicBlock* block);
|
||||
bool IsMerge(uint32_t id);
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
|
||||
147
3rdparty/spirv-tools/source/opt/block_merge_util.cpp
vendored
Normal file
147
3rdparty/spirv-tools/source/opt/block_merge_util.cpp
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2017 The Khronos Group Inc.
|
||||
// Copyright (c) 2017 Valve Corporation
|
||||
// Copyright (c) 2017 LunarG Inc.
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "block_merge_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace blockmergeutil {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns true if |block| contains a merge instruction.
|
||||
bool IsHeader(BasicBlock* block) { return block->GetMergeInst() != nullptr; }
|
||||
|
||||
// Returns true if |id| contains a merge instruction.
|
||||
bool IsHeader(IRContext* context, uint32_t id) {
|
||||
return IsHeader(
|
||||
context->get_instr_block(context->get_def_use_mgr()->GetDef(id)));
|
||||
}
|
||||
|
||||
// Returns true if |id| is the merge target of a merge instruction.
|
||||
bool IsMerge(IRContext* context, uint32_t id) {
|
||||
return !context->get_def_use_mgr()->WhileEachUse(id, [](Instruction* user,
|
||||
uint32_t index) {
|
||||
SpvOp op = user->opcode();
|
||||
if ((op == SpvOpLoopMerge || op == SpvOpSelectionMerge) && index == 0u) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Returns true if |block| is the merge target of a merge instruction.
|
||||
bool IsMerge(IRContext* context, BasicBlock* block) {
|
||||
return IsMerge(context, block->id());
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) {
|
||||
// Find block with single successor which has no other predecessors.
|
||||
auto ii = block->end();
|
||||
--ii;
|
||||
Instruction* br = &*ii;
|
||||
if (br->opcode() != SpvOpBranch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t lab_id = br->GetSingleWordInOperand(0);
|
||||
if (context->cfg()->preds(lab_id).size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pred_is_merge = IsMerge(context, block);
|
||||
bool succ_is_merge = IsMerge(context, lab_id);
|
||||
if (pred_is_merge && succ_is_merge) {
|
||||
// Cannot merge two merges together.
|
||||
return false;
|
||||
}
|
||||
|
||||
Instruction* merge_inst = block->GetMergeInst();
|
||||
const bool pred_is_header = IsHeader(block);
|
||||
if (pred_is_header && lab_id != merge_inst->GetSingleWordInOperand(0u)) {
|
||||
bool succ_is_header = IsHeader(context, lab_id);
|
||||
if (pred_is_header && succ_is_header) {
|
||||
// Cannot merge two headers together when the successor is not the merge
|
||||
// block of the predecessor.
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a header block and the successor is not its merge, we must
|
||||
// be careful about which blocks we are willing to merge together.
|
||||
// OpLoopMerge must be followed by a conditional or unconditional branch.
|
||||
// The merge must be a loop merge because a selection merge cannot be
|
||||
// followed by an unconditional branch.
|
||||
BasicBlock* succ_block = context->get_instr_block(lab_id);
|
||||
SpvOp succ_term_op = succ_block->terminator()->opcode();
|
||||
assert(merge_inst->opcode() == SpvOpLoopMerge);
|
||||
if (succ_term_op != SpvOpBranch && succ_term_op != SpvOpBranchConditional) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MergeWithSuccessor(IRContext* context, Function* func,
|
||||
Function::iterator bi) {
|
||||
assert(CanMergeWithSuccessor(context, &*bi) &&
|
||||
"Precondition failure for MergeWithSuccessor: it must be legal to "
|
||||
"merge the block and its successor.");
|
||||
|
||||
auto ii = bi->end();
|
||||
--ii;
|
||||
Instruction* br = &*ii;
|
||||
const uint32_t lab_id = br->GetSingleWordInOperand(0);
|
||||
Instruction* merge_inst = bi->GetMergeInst();
|
||||
bool pred_is_header = IsHeader(&*bi);
|
||||
|
||||
// Merge blocks.
|
||||
context->KillInst(br);
|
||||
auto sbi = bi;
|
||||
for (; sbi != func->end(); ++sbi)
|
||||
if (sbi->id() == lab_id) break;
|
||||
// If bi is sbi's only predecessor, it dominates sbi and thus
|
||||
// sbi must follow bi in func's ordering.
|
||||
assert(sbi != func->end());
|
||||
|
||||
// Update the inst-to-block mapping for the instructions in sbi.
|
||||
for (auto& inst : *sbi) {
|
||||
context->set_instr_block(&inst, &*bi);
|
||||
}
|
||||
|
||||
// Now actually move the instructions.
|
||||
bi->AddInstructions(&*sbi);
|
||||
|
||||
if (merge_inst) {
|
||||
if (pred_is_header && lab_id == merge_inst->GetSingleWordInOperand(0u)) {
|
||||
// Merging the header and merge blocks, so remove the structured control
|
||||
// flow declaration.
|
||||
context->KillInst(merge_inst);
|
||||
} else {
|
||||
// Move the merge instruction to just before the terminator.
|
||||
merge_inst->InsertBefore(bi->terminator());
|
||||
}
|
||||
}
|
||||
context->ReplaceAllUsesWith(lab_id, bi->id());
|
||||
context->KillInst(sbi->GetLabelInst());
|
||||
(void)sbi.Erase();
|
||||
}
|
||||
|
||||
} // namespace blockmergeutil
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
44
3rdparty/spirv-tools/source/opt/block_merge_util.h
vendored
Normal file
44
3rdparty/spirv-tools/source/opt/block_merge_util.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2017 The Khronos Group Inc.
|
||||
// Copyright (c) 2017 Valve Corporation
|
||||
// Copyright (c) 2017 LunarG Inc.
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_OPT_BLOCK_MERGE_UTIL_H_
|
||||
#define SOURCE_OPT_BLOCK_MERGE_UTIL_H_
|
||||
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// Provides functions for determining when it is safe to merge blocks, and for
|
||||
// actually merging blocks, for use by various analyses and passes.
|
||||
namespace blockmergeutil {
|
||||
|
||||
// Returns true if and only if |block| has exactly one successor and merging
|
||||
// this successor into |block| has no impact on the semantics or validity of the
|
||||
// SPIR-V module.
|
||||
bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block);
|
||||
|
||||
// Requires that |bi| has a successor that can be safely merged into |bi|, and
|
||||
// performs the merge.
|
||||
void MergeWithSuccessor(IRContext* context, Function* func,
|
||||
Function::iterator bi);
|
||||
|
||||
} // namespace blockmergeutil
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_OPT_BLOCK_MERGE_UTIL_H_
|
||||
@@ -80,7 +80,10 @@ BasicBlock* CodeSinkingPass::FindNewBasicBlockFor(Instruction* inst) {
|
||||
get_def_use_mgr()->ForEachUse(
|
||||
inst, [&bbs_with_uses, this](Instruction* use, uint32_t idx) {
|
||||
if (use->opcode() != SpvOpPhi) {
|
||||
bbs_with_uses.insert(context()->get_instr_block(use)->id());
|
||||
BasicBlock* use_bb = context()->get_instr_block(use);
|
||||
if (use_bb) {
|
||||
bbs_with_uses.insert(use_bb->id());
|
||||
}
|
||||
} else {
|
||||
bbs_with_uses.insert(use->GetSingleWordOperand(idx + 1));
|
||||
}
|
||||
|
||||
@@ -89,6 +89,11 @@ void IRContext::InvalidateAnalysesExceptFor(
|
||||
}
|
||||
|
||||
void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
|
||||
// The ConstantManager contains Type pointers. If the TypeManager goes
|
||||
// away, the ConstantManager has to go away.
|
||||
if (analyses_to_invalidate & kAnalysisTypes) {
|
||||
analyses_to_invalidate |= kAnalysisConstants;
|
||||
}
|
||||
if (analyses_to_invalidate & kAnalysisDefUse) {
|
||||
def_use_mgr_.reset(nullptr);
|
||||
}
|
||||
@@ -127,9 +132,6 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
|
||||
constant_mgr_.reset(nullptr);
|
||||
}
|
||||
if (analyses_to_invalidate & kAnalysisTypes) {
|
||||
// The ConstantManager contains Type pointers. If the TypeManager goes
|
||||
// away, the ConstantManager has to go away.
|
||||
constant_mgr_.reset(nullptr);
|
||||
type_mgr_.reset(nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,33 +14,34 @@
|
||||
set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
change_operand_reduction_opportunity.h
|
||||
change_operand_to_undef_reduction_opportunity.h
|
||||
operand_to_const_reduction_pass.h
|
||||
operand_to_undef_reduction_pass.h
|
||||
operand_to_dominating_id_reduction_pass.h
|
||||
operand_to_const_reduction_opportunity_finder.h
|
||||
operand_to_undef_reduction_opportunity_finder.h
|
||||
operand_to_dominating_id_reduction_opportunity_finder.h
|
||||
reducer.h
|
||||
reduction_opportunity.h
|
||||
reduction_opportunity_finder.h
|
||||
reduction_pass.h
|
||||
reduction_util.h
|
||||
remove_instruction_reduction_opportunity.h
|
||||
remove_opname_instruction_reduction_pass.h
|
||||
remove_unreferenced_instruction_reduction_pass.h
|
||||
remove_opname_instruction_reduction_opportunity_finder.h
|
||||
remove_unreferenced_instruction_reduction_opportunity_finder.h
|
||||
structured_loop_to_selection_reduction_opportunity.h
|
||||
structured_loop_to_selection_reduction_pass.h
|
||||
structured_loop_to_selection_reduction_opportunity_finder.h
|
||||
|
||||
change_operand_reduction_opportunity.cpp
|
||||
change_operand_to_undef_reduction_opportunity.cpp
|
||||
operand_to_const_reduction_pass.cpp
|
||||
operand_to_undef_reduction_pass.cpp
|
||||
operand_to_dominating_id_reduction_pass.cpp
|
||||
operand_to_const_reduction_opportunity_finder.cpp
|
||||
operand_to_undef_reduction_opportunity_finder.cpp
|
||||
operand_to_dominating_id_reduction_opportunity_finder.cpp
|
||||
reducer.cpp
|
||||
reduction_opportunity.cpp
|
||||
reduction_pass.cpp
|
||||
reduction_util.cpp
|
||||
remove_instruction_reduction_opportunity.cpp
|
||||
remove_unreferenced_instruction_reduction_pass.cpp
|
||||
remove_opname_instruction_reduction_pass.cpp
|
||||
remove_unreferenced_instruction_reduction_opportunity_finder.cpp
|
||||
remove_opname_instruction_reduction_opportunity_finder.cpp
|
||||
structured_loop_to_selection_reduction_opportunity.cpp
|
||||
structured_loop_to_selection_reduction_pass.cpp
|
||||
structured_loop_to_selection_reduction_opportunity_finder.cpp
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_const_reduction_opportunity_finder.h"
|
||||
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/reduce/change_operand_reduction_opportunity.h"
|
||||
@@ -23,7 +23,7 @@ namespace reduce {
|
||||
using namespace opt;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
OperandToConstReductionPass::GetAvailableOpportunities(
|
||||
OperandToConstReductionOpportunityFinder::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
assert(result.empty());
|
||||
@@ -75,8 +75,8 @@ OperandToConstReductionPass::GetAvailableOpportunities(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string OperandToConstReductionPass::GetName() const {
|
||||
return "OperandToConstReductionPass";
|
||||
std::string OperandToConstReductionOpportunityFinder::GetName() const {
|
||||
return "OperandToConstReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
@@ -12,30 +12,26 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_
|
||||
#define SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_
|
||||
#ifndef SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "source/reduce/reduction_pass.h"
|
||||
#include "source/reduce/reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A reduction pass for replacing id operands of instructions with ids of
|
||||
// A finder for opportunities to replace id operands of instructions with ids of
|
||||
// constants. This reduces the extent to which ids of non-constants are used,
|
||||
// paving the way for instructions that generate them to be eliminated by other
|
||||
// passes.
|
||||
class OperandToConstReductionPass : public ReductionPass {
|
||||
// paving the way for instructions that generate them to be eliminated.
|
||||
class OperandToConstReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
// Creates the reduction pass in the context of the given target environment
|
||||
// |target_env|
|
||||
explicit OperandToConstReductionPass(const spv_target_env target_env)
|
||||
: ReductionPass(target_env) {}
|
||||
OperandToConstReductionOpportunityFinder() = default;
|
||||
|
||||
~OperandToConstReductionPass() override = default;
|
||||
~OperandToConstReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
@@ -45,4 +41,4 @@ class OperandToConstReductionPass : public ReductionPass {
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_
|
||||
#endif // SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "operand_to_dominating_id_reduction_pass.h"
|
||||
#include "operand_to_dominating_id_reduction_opportunity_finder.h"
|
||||
#include "change_operand_reduction_opportunity.h"
|
||||
#include "source/opt/instruction.h"
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace reduce {
|
||||
using namespace opt;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
OperandToDominatingIdReductionPass::GetAvailableOpportunities(
|
||||
OperandToDominatingIdReductionOpportunityFinder::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
|
||||
@@ -55,11 +55,12 @@ OperandToDominatingIdReductionPass::GetAvailableOpportunities(
|
||||
return result;
|
||||
}
|
||||
|
||||
void OperandToDominatingIdReductionPass::GetOpportunitiesForDominatingInst(
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>* opportunities,
|
||||
opt::Instruction* candidate_dominator,
|
||||
opt::Function::iterator candidate_dominator_block, opt::Function* function,
|
||||
opt::IRContext* context) const {
|
||||
void OperandToDominatingIdReductionOpportunityFinder::
|
||||
GetOpportunitiesForDominatingInst(
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>* opportunities,
|
||||
opt::Instruction* candidate_dominator,
|
||||
opt::Function::iterator candidate_dominator_block,
|
||||
opt::Function* function, opt::IRContext* context) const {
|
||||
assert(candidate_dominator->HasResultId());
|
||||
assert(candidate_dominator->type_id());
|
||||
auto dominator_analysis = context->GetDominatorAnalysis(function);
|
||||
@@ -106,8 +107,8 @@ void OperandToDominatingIdReductionPass::GetOpportunitiesForDominatingInst(
|
||||
}
|
||||
}
|
||||
|
||||
std::string OperandToDominatingIdReductionPass::GetName() const {
|
||||
return "OperandToDominatingIdReductionPass";
|
||||
std::string OperandToDominatingIdReductionOpportunityFinder::GetName() const {
|
||||
return "OperandToDominatingIdReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
@@ -12,36 +12,33 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_PASS_H_
|
||||
#define SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_PASS_H_
|
||||
#ifndef SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "reduction_pass.h"
|
||||
#include "reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A reduction pass that aims to bring to SPIR-V (and generalize) the idea from
|
||||
// human-readable languages of e.g. replacing an expression with one of its
|
||||
// arguments, (x + y) -> x, or with a reference to an identifier that was
|
||||
// assigned to higher up in the program. The generalization of this is to
|
||||
// replace an id with a different id of the same type defined in some
|
||||
// dominating instruction.
|
||||
// A finder that aims to bring to SPIR-V (and generalize) the idea from
|
||||
// human-readable languages of e.g. finding opportunities to replace an
|
||||
// expression with one of its arguments, (x + y) -> x, or with a reference to an
|
||||
// identifier that was assigned to higher up in the program. The generalization
|
||||
// of this is to replace an id with a different id of the same type defined in
|
||||
// some dominating instruction.
|
||||
//
|
||||
// If id x is defined and then used several times, changing each use of x to
|
||||
// some dominating definition may eventually allow the statement defining x
|
||||
// to be eliminated by another pass.
|
||||
class OperandToDominatingIdReductionPass : public ReductionPass {
|
||||
class OperandToDominatingIdReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
// Creates the reduction pass in the context of the given target environment
|
||||
// |target_env|
|
||||
explicit OperandToDominatingIdReductionPass(const spv_target_env target_env)
|
||||
: ReductionPass(target_env) {}
|
||||
OperandToDominatingIdReductionOpportunityFinder() = default;
|
||||
|
||||
~OperandToDominatingIdReductionPass() override = default;
|
||||
~OperandToDominatingIdReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
@@ -56,4 +53,4 @@ class OperandToDominatingIdReductionPass : public ReductionPass {
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_PASS_H_
|
||||
#endif // SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/reduce/operand_to_undef_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h"
|
||||
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/reduce/change_operand_to_undef_reduction_opportunity.h"
|
||||
@@ -23,7 +23,7 @@ namespace reduce {
|
||||
using namespace opt;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
OperandToUndefReductionPass::GetAvailableOpportunities(
|
||||
OperandToUndefReductionOpportunityFinder::GetAvailableOpportunities(
|
||||
IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
|
||||
@@ -86,8 +86,8 @@ OperandToUndefReductionPass::GetAvailableOpportunities(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string OperandToUndefReductionPass::GetName() const {
|
||||
return "OperandToUndefReductionPass";
|
||||
std::string OperandToUndefReductionOpportunityFinder::GetName() const {
|
||||
return "OperandToUndefReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
@@ -12,27 +12,25 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_PASS_H_
|
||||
#define SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_PASS_H_
|
||||
#ifndef SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "source/reduce/reduction_pass.h"
|
||||
#include "source/reduce/reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A reduction pass for replacing id operands of instructions with ids of undef.
|
||||
class OperandToUndefReductionPass : public ReductionPass {
|
||||
// A finder of opportunities to replace id operands of instructions with ids of
|
||||
// undef.
|
||||
class OperandToUndefReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
// Creates the reduction pass in the context of the given target environment
|
||||
// |target_env|
|
||||
explicit OperandToUndefReductionPass(const spv_target_env target_env)
|
||||
: ReductionPass(target_env) {}
|
||||
OperandToUndefReductionOpportunityFinder() = default;
|
||||
|
||||
~OperandToUndefReductionPass() override = default;
|
||||
~OperandToUndefReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
@@ -42,4 +40,4 @@ class OperandToUndefReductionPass : public ReductionPass {
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_PASS_H_
|
||||
#endif // SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
@@ -16,8 +16,8 @@
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include "source/reduce/change_operand_reduction_opportunity.h"
|
||||
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_const_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/reduction_opportunity.h"
|
||||
#include "source/reduce/reduction_pass.h"
|
||||
#include "source/reduce/remove_instruction_reduction_opportunity.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h"
|
||||
|
||||
@@ -141,8 +141,9 @@ Reducer::ReductionResultStatus Reducer::Run(
|
||||
}
|
||||
|
||||
void Reducer::AddReductionPass(
|
||||
std::unique_ptr<ReductionPass>&& reduction_pass) {
|
||||
impl_->passes.push_back(std::move(reduction_pass));
|
||||
std::unique_ptr<ReductionOpportunityFinder>&& finder) {
|
||||
impl_->passes.push_back(spvtools::MakeUnique<ReductionPass>(
|
||||
impl_->target_env, std::move(finder)));
|
||||
}
|
||||
|
||||
bool Reducer::Impl::ReachedStepLimit(uint32_t current_step,
|
||||
|
||||
6
3rdparty/spirv-tools/source/reduce/reducer.h
vendored
6
3rdparty/spirv-tools/source/reduce/reducer.h
vendored
@@ -75,9 +75,9 @@ class Reducer {
|
||||
void SetInterestingnessFunction(
|
||||
InterestingnessFunction interestingness_function);
|
||||
|
||||
// Adds a reduction pass to the sequence of passes that will be iterated
|
||||
// over.
|
||||
void AddReductionPass(std::unique_ptr<ReductionPass>&& reduction_pass);
|
||||
// Adds a reduction pass based on the given finder to the sequence of passes
|
||||
// that will be iterated over.
|
||||
void AddReductionPass(std::unique_ptr<ReductionOpportunityFinder>&& finder);
|
||||
|
||||
// Reduces the given SPIR-V module |binary_out|.
|
||||
// The reduced binary ends up in |binary_out|.
|
||||
|
||||
43
3rdparty/spirv-tools/source/reduce/reduction_opportunity_finder.h
vendored
Normal file
43
3rdparty/spirv-tools/source/reduce/reduction_opportunity_finder.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "reduction_opportunity.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// Abstract class for finding opportunities for reducing a SPIR-V module.
|
||||
class ReductionOpportunityFinder {
|
||||
public:
|
||||
ReductionOpportunityFinder() = default;
|
||||
|
||||
virtual ~ReductionOpportunityFinder() = default;
|
||||
|
||||
// Finds and returns the reduction opportunities relevant to this pass that
|
||||
// could be applied to the given SPIR-V module.
|
||||
virtual std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
GetAvailableOpportunities(opt::IRContext* context) const = 0;
|
||||
|
||||
// Provides a name for the finder.
|
||||
virtual std::string GetName() const = 0;
|
||||
};
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
@@ -34,7 +34,7 @@ std::vector<uint32_t> ReductionPass::TryApplyReduction(
|
||||
assert(context);
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> opportunities =
|
||||
GetAvailableOpportunities(context.get());
|
||||
finder_->GetAvailableOpportunities(context.get());
|
||||
|
||||
if (!is_initialized_) {
|
||||
is_initialized_ = true;
|
||||
@@ -82,5 +82,7 @@ bool ReductionPass::ReachedMinimumGranularity() const {
|
||||
return granularity_ == 1;
|
||||
}
|
||||
|
||||
std::string ReductionPass::GetName() const { return finder_->GetName(); }
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
#include "reduction_opportunity.h"
|
||||
#include "reduction_opportunity_finder.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
@@ -32,12 +32,14 @@ namespace reduce {
|
||||
// again, until the minimum granularity is reached.
|
||||
class ReductionPass {
|
||||
public:
|
||||
// Constructs a reduction pass with a given target environment, |target_env|.
|
||||
// Initially the pass is uninitialized.
|
||||
explicit ReductionPass(const spv_target_env target_env)
|
||||
: target_env_(target_env), is_initialized_(false) {}
|
||||
|
||||
virtual ~ReductionPass() = default;
|
||||
// Constructs a reduction pass with a given target environment, |target_env|,
|
||||
// and a given finder of reduction opportunities, |finder|. Initially the
|
||||
// pass is uninitialized.
|
||||
explicit ReductionPass(const spv_target_env target_env,
|
||||
std::unique_ptr<ReductionOpportunityFinder> finder)
|
||||
: target_env_(target_env),
|
||||
finder_(std::move(finder)),
|
||||
is_initialized_(false) {}
|
||||
|
||||
// Applies the reduction pass to the given binary.
|
||||
std::vector<uint32_t> TryApplyReduction(const std::vector<uint32_t>& binary);
|
||||
@@ -49,18 +51,13 @@ class ReductionPass {
|
||||
// applied has reached a minimum.
|
||||
bool ReachedMinimumGranularity() const;
|
||||
|
||||
// Returns the name of the reduction pass (useful for monitoring reduction
|
||||
// progress).
|
||||
virtual std::string GetName() const = 0;
|
||||
|
||||
protected:
|
||||
// Finds and returns the reduction opportunities relevant to this pass that
|
||||
// could be applied to the given SPIR-V module.
|
||||
virtual std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
GetAvailableOpportunities(opt::IRContext* context) const = 0;
|
||||
// Returns the name associated with this reduction pass (based on its
|
||||
// associated finder).
|
||||
std::string GetName() const;
|
||||
|
||||
private:
|
||||
const spv_target_env target_env_;
|
||||
const std::unique_ptr<ReductionOpportunityFinder> finder_;
|
||||
MessageConsumer consumer_;
|
||||
bool is_initialized_;
|
||||
uint32_t index_;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "remove_opname_instruction_reduction_pass.h"
|
||||
#include "remove_opname_instruction_reduction_opportunity_finder.h"
|
||||
#include "remove_instruction_reduction_opportunity.h"
|
||||
#include "source/opcode.h"
|
||||
#include "source/opt/instruction.h"
|
||||
@@ -23,7 +23,7 @@ namespace reduce {
|
||||
using namespace opt;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
RemoveOpNameInstructionReductionPass::GetAvailableOpportunities(
|
||||
RemoveOpNameInstructionReductionOpportunityFinder::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
|
||||
@@ -36,8 +36,8 @@ RemoveOpNameInstructionReductionPass::GetAvailableOpportunities(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string RemoveOpNameInstructionReductionPass::GetName() const {
|
||||
return "RemoveOpNameInstructionReductionPass";
|
||||
std::string RemoveOpNameInstructionReductionOpportunityFinder::GetName() const {
|
||||
return "RemoveOpNameInstructionReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
@@ -12,30 +12,27 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_PASS_H_
|
||||
#define SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_PASS_H_
|
||||
#ifndef SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "reduction_pass.h"
|
||||
#include "reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A reduction pass for removing OpName instructions. As well as making the
|
||||
// module smaller, removing an OpName instruction may create opportunities
|
||||
// A finder for opportunities to remove OpName instructions. As well as making
|
||||
// the module smaller, removing an OpName instruction may create opportunities
|
||||
// for subsequently removing the instructions that create the ids to which the
|
||||
// OpName applies.
|
||||
class RemoveOpNameInstructionReductionPass : public ReductionPass {
|
||||
class RemoveOpNameInstructionReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
// Creates the reduction pass in the context of the given target environment
|
||||
// |target_env|
|
||||
explicit RemoveOpNameInstructionReductionPass(const spv_target_env target_env)
|
||||
: ReductionPass(target_env) {}
|
||||
RemoveOpNameInstructionReductionOpportunityFinder() = default;
|
||||
|
||||
~RemoveOpNameInstructionReductionPass() override = default;
|
||||
~RemoveOpNameInstructionReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
@@ -45,4 +42,4 @@ class RemoveOpNameInstructionReductionPass : public ReductionPass {
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_REMOVE_OpName_INSTRUCTION_REDUCTION_PASS_H_
|
||||
#endif // SOURCE_REDUCE_REMOVE_OPNAME_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "remove_unreferenced_instruction_reduction_pass.h"
|
||||
#include "remove_unreferenced_instruction_reduction_opportunity_finder.h"
|
||||
#include "remove_instruction_reduction_opportunity.h"
|
||||
#include "source/opcode.h"
|
||||
#include "source/opt/instruction.h"
|
||||
@@ -23,8 +23,8 @@ namespace reduce {
|
||||
using namespace opt;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
RemoveUnreferencedInstructionReductionPass::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
RemoveUnreferencedInstructionReductionOpportunityFinder::
|
||||
GetAvailableOpportunities(opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
|
||||
for (auto& function : *context->module()) {
|
||||
@@ -52,8 +52,9 @@ RemoveUnreferencedInstructionReductionPass::GetAvailableOpportunities(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string RemoveUnreferencedInstructionReductionPass::GetName() const {
|
||||
return "RemoveUnreferencedInstructionReductionPass";
|
||||
std::string RemoveUnreferencedInstructionReductionOpportunityFinder::GetName()
|
||||
const {
|
||||
return "RemoveUnreferencedInstructionReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
@@ -12,32 +12,28 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_PASS_H_
|
||||
#define SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_PASS_H_
|
||||
#ifndef SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "reduction_pass.h"
|
||||
#include "reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A reduction pass for removing non-control-flow instructions in blocks in
|
||||
// cases where the instruction's id is not referenced. As well as making the
|
||||
// A finder for opportunities to remove non-control-flow instructions in blocks
|
||||
// in cases where the instruction's id is not referenced. As well as making the
|
||||
// module smaller, removing an instruction that references particular ids may
|
||||
// create opportunities for subsequently removing the instructions that
|
||||
// generated those ids.
|
||||
class RemoveUnreferencedInstructionReductionPass : public ReductionPass {
|
||||
class RemoveUnreferencedInstructionReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
// Creates the reduction pass in the context of the given target environment
|
||||
// |target_env|
|
||||
explicit RemoveUnreferencedInstructionReductionPass(
|
||||
const spv_target_env target_env)
|
||||
: ReductionPass(target_env) {}
|
||||
RemoveUnreferencedInstructionReductionOpportunityFinder() = default;
|
||||
|
||||
~RemoveUnreferencedInstructionReductionPass() override = default;
|
||||
~RemoveUnreferencedInstructionReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
@@ -47,4 +43,4 @@ class RemoveUnreferencedInstructionReductionPass : public ReductionPass {
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_PASS_H_
|
||||
#endif // SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "structured_loop_to_selection_reduction_pass.h"
|
||||
#include "structured_loop_to_selection_reduction_opportunity_finder.h"
|
||||
#include "structured_loop_to_selection_reduction_opportunity.h"
|
||||
|
||||
namespace spvtools {
|
||||
@@ -26,7 +26,7 @@ const uint32_t kContinueNodeIndex = 1;
|
||||
} // namespace
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
StructuredLoopToSelectionReductionPass::GetAvailableOpportunities(
|
||||
StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
|
||||
@@ -87,8 +87,9 @@ StructuredLoopToSelectionReductionPass::GetAvailableOpportunities(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string StructuredLoopToSelectionReductionPass::GetName() const {
|
||||
return "StructuredLoopToSelectionReductionPass";
|
||||
std::string StructuredLoopToSelectionReductionOpportunityFinder::GetName()
|
||||
const {
|
||||
return "StructuredLoopToSelectionReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
@@ -12,16 +12,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_REDUCE_CUT_LOOP_REDUCTION_PASS_H_
|
||||
#define SOURCE_REDUCE_CUT_LOOP_REDUCTION_PASS_H_
|
||||
#ifndef SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H
|
||||
#define SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H
|
||||
|
||||
#include "reduction_pass.h"
|
||||
#include "reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// Turns structured loops into selections, generalizing from a human-writable
|
||||
// language the idea of turning a loop:
|
||||
// A finder for opportunities to turn structured loops into selections,
|
||||
// generalizing from a human-writable language the idea of turning a loop:
|
||||
//
|
||||
// while (c) {
|
||||
// body;
|
||||
@@ -33,22 +33,18 @@ namespace reduce {
|
||||
// body;
|
||||
// }
|
||||
//
|
||||
// The pass results in continue constructs of transformed loops becoming
|
||||
// unreachable; another pass for eliminating blocks may end up being able to
|
||||
// remove them.
|
||||
class StructuredLoopToSelectionReductionPass : public ReductionPass {
|
||||
// Applying such opportunities results in continue constructs of transformed
|
||||
// loops becoming unreachable, so that it may be possible to remove them
|
||||
// subsequently.
|
||||
class StructuredLoopToSelectionReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
// Creates the reduction pass in the context of the given target environment
|
||||
// |target_env|
|
||||
explicit StructuredLoopToSelectionReductionPass(
|
||||
const spv_target_env target_env)
|
||||
: ReductionPass(target_env) {}
|
||||
StructuredLoopToSelectionReductionOpportunityFinder() = default;
|
||||
|
||||
~StructuredLoopToSelectionReductionPass() override = default;
|
||||
~StructuredLoopToSelectionReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
@@ -58,4 +54,4 @@ class StructuredLoopToSelectionReductionPass : public ReductionPass {
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_CUT_LOOP_REDUCTION_PASS_H_
|
||||
#endif // SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H
|
||||
40
3rdparty/spirv-tools/source/spirv_target_env.cpp
vendored
40
3rdparty/spirv-tools/source/spirv_target_env.cpp
vendored
@@ -248,3 +248,43 @@ bool spvIsWebGPUEnv(spv_target_env env) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spvIsVulkanOrWebGPUEnv(spv_target_env env) {
|
||||
return spvIsVulkanEnv(env) || spvIsWebGPUEnv(env);
|
||||
}
|
||||
|
||||
std::string spvLogStringForEnv(spv_target_env env) {
|
||||
switch (env) {
|
||||
case SPV_ENV_OPENCL_1_2:
|
||||
case SPV_ENV_OPENCL_2_0:
|
||||
case SPV_ENV_OPENCL_2_1:
|
||||
case SPV_ENV_OPENCL_2_2:
|
||||
case SPV_ENV_OPENCL_EMBEDDED_1_2:
|
||||
case SPV_ENV_OPENCL_EMBEDDED_2_0:
|
||||
case SPV_ENV_OPENCL_EMBEDDED_2_1:
|
||||
case SPV_ENV_OPENCL_EMBEDDED_2_2: {
|
||||
return "OpenCL";
|
||||
}
|
||||
case SPV_ENV_OPENGL_4_0:
|
||||
case SPV_ENV_OPENGL_4_1:
|
||||
case SPV_ENV_OPENGL_4_2:
|
||||
case SPV_ENV_OPENGL_4_3:
|
||||
case SPV_ENV_OPENGL_4_5: {
|
||||
return "OpenGL";
|
||||
}
|
||||
case SPV_ENV_VULKAN_1_0:
|
||||
case SPV_ENV_VULKAN_1_1: {
|
||||
return "Vulkan";
|
||||
}
|
||||
case SPV_ENV_WEBGPU_0: {
|
||||
return "WebGPU";
|
||||
}
|
||||
case SPV_ENV_UNIVERSAL_1_0:
|
||||
case SPV_ENV_UNIVERSAL_1_1:
|
||||
case SPV_ENV_UNIVERSAL_1_2:
|
||||
case SPV_ENV_UNIVERSAL_1_3: {
|
||||
return "Universal";
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef SOURCE_SPIRV_TARGET_ENV_H_
|
||||
#define SOURCE_SPIRV_TARGET_ENV_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
// Parses s into *env and returns true if successful. If unparsable, returns
|
||||
@@ -30,7 +32,14 @@ bool spvIsOpenCLEnv(spv_target_env env);
|
||||
// Returns true if |env| is an WEBGPU environment, false otherwise.
|
||||
bool spvIsWebGPUEnv(spv_target_env env);
|
||||
|
||||
// Returns true if |env| is a VULKAN or WEBGPU environment, false otherwise.
|
||||
bool spvIsVulkanOrWebGPUEnv(spv_target_env env);
|
||||
|
||||
// Returns the version number for the given SPIR-V target environment.
|
||||
uint32_t spvVersionForTargetEnv(spv_target_env env);
|
||||
|
||||
// Returns a string to use in logging messages that indicates the class of
|
||||
// environment, i.e. "Vulkan", "WebGPU", "OpenCL", etc.
|
||||
std::string spvLogStringForEnv(spv_target_env env);
|
||||
|
||||
#endif // SOURCE_SPIRV_TARGET_ENV_H_
|
||||
|
||||
3
3rdparty/spirv-tools/source/val/validate.cpp
vendored
3
3rdparty/spirv-tools/source/val/validate.cpp
vendored
@@ -249,8 +249,7 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
|
||||
|
||||
// For Vulkan and WebGPU, the static function-call graph for an entry point
|
||||
// must not contain cycles.
|
||||
if (spvIsWebGPUEnv(_.context()->target_env) ||
|
||||
spvIsVulkanEnv(_.context()->target_env)) {
|
||||
if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
|
||||
if (_.recursive_entry_points().find(entry_point) !=
|
||||
_.recursive_entry_points().end()) {
|
||||
return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(entry_point))
|
||||
|
||||
@@ -1617,6 +1617,46 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference(
|
||||
}
|
||||
}
|
||||
|
||||
if (spvIsWebGPUEnv(_.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)
|
||||
<< "WebGPU spec allows BuiltIn Position 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: {
|
||||
if (spv_result_t error = ValidateF32Vec(
|
||||
decoration, built_in_inst, 4,
|
||||
[this, &referenced_from_inst](
|
||||
const std::string& message) -> spv_result_t {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
|
||||
<< "According to the WebGPU spec BuiltIn Position "
|
||||
"variable needs to be a 4-component 32-bit float "
|
||||
"vector. "
|
||||
<< message;
|
||||
})) {
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
|
||||
<< "WebGPU spec allows BuiltIn Position to be used only "
|
||||
"with the Vertex 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(
|
||||
@@ -2656,14 +2696,15 @@ spv_result_t BuiltInsValidator::Run() {
|
||||
|
||||
// Validates correctness of built-in variables.
|
||||
spv_result_t ValidateBuiltIns(ValidationState_t& _) {
|
||||
if (!spvIsVulkanEnv(_.context()->target_env)) {
|
||||
// Early return. All currently implemented rules are based on Vulkan spec.
|
||||
if (!spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
|
||||
// Early return. All currently implemented rules are based on Vulkan or
|
||||
// WebGPU spec.
|
||||
//
|
||||
// TODO: If you are adding validation rules for environments other than
|
||||
// Vulkan (or general rules which are not environment independent), then you
|
||||
// need to modify or remove this condition. Consider also adding early
|
||||
// returns into BuiltIn-specific rules, so that the system doesn't spawn new
|
||||
// rules which don't do anything.
|
||||
// Vulkan or WebGPU (or general rules which are not environment
|
||||
// independent), then you need to modify or remove this condition. Consider
|
||||
// also adding early returns into BuiltIn-specific rules, so that the system
|
||||
// doesn't spawn new rules which don't do anything.
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
39
3rdparty/spirv-tools/source/val/validate_cfg.cpp
vendored
39
3rdparty/spirv-tools/source/val/validate_cfg.cpp
vendored
@@ -112,6 +112,19 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) {
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateBranch(ValidationState_t& _, const Instruction* inst) {
|
||||
// target operands must be OpLabel
|
||||
const auto id = inst->GetOperandAs<uint32_t>(0);
|
||||
const auto target = _.FindDef(id);
|
||||
if (!target || SpvOpLabel != target->opcode()) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "'Target Label' operands for OpBranch must be the ID "
|
||||
"of an OpLabel instruction";
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateBranchConditional(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
// num_operands is either 3 or 5 --- if 5, the last two need to be literal
|
||||
@@ -155,6 +168,26 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _,
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateSwitch(ValidationState_t& _, const Instruction* inst) {
|
||||
const auto num_operands = inst->operands().size();
|
||||
// At least two operands (selector, default), any more than that are
|
||||
// literal/target.
|
||||
|
||||
// target operands must be OpLabel
|
||||
for (size_t i = 2; i < num_operands; i += 2) {
|
||||
// literal, id
|
||||
const auto id = inst->GetOperandAs<uint32_t>(i + 1);
|
||||
const auto target = _.FindDef(id);
|
||||
if (!target || SpvOpLabel != target->opcode()) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "'Target Label' operands for OpSwitch must be IDs of an "
|
||||
"OpLabel instruction";
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateReturnValue(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
const auto value_id = inst->GetOperandAs<uint32_t>(0);
|
||||
@@ -764,12 +797,18 @@ spv_result_t ControlFlowPass(ValidationState_t& _, const Instruction* inst) {
|
||||
case SpvOpPhi:
|
||||
if (auto error = ValidatePhi(_, inst)) return error;
|
||||
break;
|
||||
case SpvOpBranch:
|
||||
if (auto error = ValidateBranch(_, inst)) return error;
|
||||
break;
|
||||
case SpvOpBranchConditional:
|
||||
if (auto error = ValidateBranchConditional(_, inst)) return error;
|
||||
break;
|
||||
case SpvOpReturnValue:
|
||||
if (auto error = ValidateReturnValue(_, inst)) return error;
|
||||
break;
|
||||
case SpvOpSwitch:
|
||||
if (auto error = ValidateSwitch(_, inst)) return error;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -214,6 +214,21 @@ spv_result_t ValidateStruct(ValidationState_t& _, const Instruction* inst) {
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
// Validates that any undefined type of the array is a forward pointer.
|
||||
// It is valid to declare a forward pointer, and use its <id> as the element
|
||||
// type of the array.
|
||||
spv_result_t ValidateArray(ValidationState_t& _, const Instruction* inst) {
|
||||
auto element_type_id = inst->GetOperandAs<const uint32_t>(1);
|
||||
auto element_type_instruction = _.FindDef(element_type_id);
|
||||
if (element_type_instruction == nullptr &&
|
||||
!_.IsForwardPointer(element_type_id)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Forward reference operands in an OpTypeArray must first be "
|
||||
"declared using OpTypeForwardPointer.";
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Validates that Data Rules are followed according to the specifications.
|
||||
@@ -256,6 +271,10 @@ spv_result_t DataRulesPass(ValidationState_t& _, const Instruction* inst) {
|
||||
if (auto error = ValidateStruct(_, inst)) return error;
|
||||
break;
|
||||
}
|
||||
case SpvOpTypeArray: {
|
||||
if (auto error = ValidateArray(_, inst)) return error;
|
||||
break;
|
||||
}
|
||||
// TODO(ehsan): add more data rules validation here.
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
@@ -379,6 +379,7 @@ bool IsAlignedTo(uint32_t offset, uint32_t alignment) {
|
||||
// or row major-ness.
|
||||
spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
|
||||
const char* decoration_str, bool blockRules,
|
||||
uint32_t incoming_offset,
|
||||
MemberConstraints& constraints,
|
||||
ValidationState_t& vstate) {
|
||||
if (vstate.options()->skip_block_layout) return SPV_SUCCESS;
|
||||
@@ -429,7 +430,8 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
|
||||
}
|
||||
}
|
||||
}
|
||||
member_offsets.push_back(MemberOffsetPair{memberIdx, offset});
|
||||
member_offsets.push_back(
|
||||
MemberOffsetPair{memberIdx, incoming_offset + offset});
|
||||
}
|
||||
std::stable_sort(
|
||||
member_offsets.begin(), member_offsets.end(),
|
||||
@@ -493,9 +495,9 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
|
||||
// Check struct members recursively.
|
||||
spv_result_t recursive_status = SPV_SUCCESS;
|
||||
if (SpvOpTypeStruct == opcode &&
|
||||
SPV_SUCCESS != (recursive_status =
|
||||
checkLayout(id, storage_class_str, decoration_str,
|
||||
blockRules, constraints, vstate)))
|
||||
SPV_SUCCESS != (recursive_status = checkLayout(
|
||||
id, storage_class_str, decoration_str, blockRules,
|
||||
offset, constraints, vstate)))
|
||||
return recursive_status;
|
||||
// Check matrix stride.
|
||||
if (SpvOpTypeMatrix == opcode) {
|
||||
@@ -507,23 +509,53 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
|
||||
<< " not satisfying alignment to " << alignment;
|
||||
}
|
||||
}
|
||||
// Check arrays and runtime arrays.
|
||||
if (SpvOpTypeArray == opcode || SpvOpTypeRuntimeArray == opcode) {
|
||||
const auto typeId = inst->word(2);
|
||||
const auto arrayInst = vstate.FindDef(typeId);
|
||||
if (SpvOpTypeStruct == arrayInst->opcode() &&
|
||||
SPV_SUCCESS != (recursive_status = checkLayout(
|
||||
typeId, storage_class_str, decoration_str,
|
||||
blockRules, constraints, vstate)))
|
||||
return recursive_status;
|
||||
|
||||
// Check arrays and runtime arrays recursively.
|
||||
auto array_inst = inst;
|
||||
auto array_alignment = alignment;
|
||||
while (array_inst->opcode() == SpvOpTypeArray ||
|
||||
array_inst->opcode() == SpvOpTypeRuntimeArray) {
|
||||
const auto typeId = array_inst->word(2);
|
||||
const auto element_inst = vstate.FindDef(typeId);
|
||||
// Check array stride.
|
||||
for (auto& decoration : vstate.id_decorations(id)) {
|
||||
if (SpvDecorationArrayStride == decoration.dec_type() &&
|
||||
!IsAlignedTo(decoration.params()[0], alignment))
|
||||
return fail(memberIdx)
|
||||
<< "is an array with stride " << decoration.params()[0]
|
||||
<< " not satisfying alignment to " << alignment;
|
||||
auto array_stride = 0;
|
||||
for (auto& decoration : vstate.id_decorations(array_inst->id())) {
|
||||
if (SpvDecorationArrayStride == decoration.dec_type()) {
|
||||
array_stride = decoration.params()[0];
|
||||
if (!IsAlignedTo(array_stride, array_alignment))
|
||||
return fail(memberIdx)
|
||||
<< "contains an array with stride " << decoration.params()[0]
|
||||
<< " not satisfying alignment to " << alignment;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_int32 = false;
|
||||
bool is_const = false;
|
||||
uint32_t num_elements = 0;
|
||||
if (array_inst->opcode() == SpvOpTypeArray) {
|
||||
std::tie(is_int32, is_const, num_elements) =
|
||||
vstate.EvalInt32IfConst(array_inst->word(3));
|
||||
}
|
||||
num_elements = std::max(1u, num_elements);
|
||||
// Check each element recursively if it is a struct. There is a
|
||||
// limitation to this check if the array size is a spec constant or is a
|
||||
// runtime array then we will only check a single element. This means
|
||||
// some improper straddles might be missed.
|
||||
for (uint32_t i = 0; i < num_elements; ++i) {
|
||||
uint32_t next_offset = i * array_stride + offset;
|
||||
if (SpvOpTypeStruct == element_inst->opcode() &&
|
||||
SPV_SUCCESS != (recursive_status = checkLayout(
|
||||
typeId, storage_class_str, decoration_str,
|
||||
blockRules, next_offset, constraints, vstate)))
|
||||
return recursive_status;
|
||||
}
|
||||
|
||||
// Proceed to the element in case it is an array.
|
||||
array_inst = element_inst;
|
||||
array_alignment = scalar_block_layout
|
||||
? getScalarAlignment(array_inst->id(), vstate)
|
||||
: getBaseAlignment(array_inst->id(), blockRules,
|
||||
constraint, constraints, vstate);
|
||||
}
|
||||
nextValidOffset = offset + size;
|
||||
if (!scalar_block_layout && blockRules &&
|
||||
@@ -859,8 +891,15 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
|
||||
if (uniform || push_constant || storage_buffer || phys_storage_buffer) {
|
||||
const auto ptrInst = vstate.FindDef(words[1]);
|
||||
assert(SpvOpTypePointer == ptrInst->opcode());
|
||||
const auto id = ptrInst->words()[3];
|
||||
if (SpvOpTypeStruct != vstate.FindDef(id)->opcode()) continue;
|
||||
auto id = ptrInst->words()[3];
|
||||
auto id_inst = vstate.FindDef(id);
|
||||
// Jump through one level of arraying.
|
||||
if (id_inst->opcode() == SpvOpTypeArray ||
|
||||
id_inst->opcode() == SpvOpTypeRuntimeArray) {
|
||||
id = id_inst->GetOperandAs<uint32_t>(1u);
|
||||
id_inst = vstate.FindDef(id);
|
||||
}
|
||||
if (SpvOpTypeStruct != id_inst->opcode()) continue;
|
||||
MemberConstraints constraints;
|
||||
ComputeMemberConstraintsForStruct(&constraints, id, LayoutConstraints(),
|
||||
vstate);
|
||||
@@ -942,12 +981,12 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
|
||||
"decorations.";
|
||||
} else if (blockRules &&
|
||||
(SPV_SUCCESS != (recursive_status = checkLayout(
|
||||
id, sc_str, deco_str, true,
|
||||
id, sc_str, deco_str, true, 0,
|
||||
constraints, vstate)))) {
|
||||
return recursive_status;
|
||||
} else if (bufferRules &&
|
||||
(SPV_SUCCESS != (recursive_status = checkLayout(
|
||||
id, sc_str, deco_str, false,
|
||||
id, sc_str, deco_str, false, 0,
|
||||
constraints, vstate)))) {
|
||||
return recursive_status;
|
||||
}
|
||||
@@ -959,42 +998,64 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns true if |decoration| cannot be applied to the same id more than once.
|
||||
bool AtMostOncePerId(SpvDecoration decoration) {
|
||||
return decoration == SpvDecorationArrayStride;
|
||||
}
|
||||
|
||||
// Returns true if |decoration| cannot be applied to the same member more than
|
||||
// once.
|
||||
bool AtMostOncePerMember(SpvDecoration decoration) {
|
||||
switch (decoration) {
|
||||
case SpvDecorationOffset:
|
||||
case SpvDecorationMatrixStride:
|
||||
case SpvDecorationRowMajor:
|
||||
case SpvDecorationColMajor:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the string name for |decoration|.
|
||||
const char* GetDecorationName(SpvDecoration decoration) {
|
||||
switch (decoration) {
|
||||
case SpvDecorationArrayStride:
|
||||
return "ArrayStride";
|
||||
case SpvDecorationOffset:
|
||||
return "Offset";
|
||||
case SpvDecorationMatrixStride:
|
||||
return "MatrixStride";
|
||||
case SpvDecorationRowMajor:
|
||||
return "RowMajor";
|
||||
case SpvDecorationColMajor:
|
||||
return "ColMajor";
|
||||
case SpvDecorationBlock:
|
||||
return "Block";
|
||||
case SpvDecorationBufferBlock:
|
||||
return "BufferBlock";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) {
|
||||
using AtMostOnceSet = std::unordered_set<SpvDecoration, SpvDecorationHash>;
|
||||
using MutuallyExclusiveSets =
|
||||
std::vector<std::unordered_set<SpvDecoration, SpvDecorationHash>>;
|
||||
using PerIDKey = std::tuple<SpvDecoration, uint32_t>;
|
||||
using PerMemberKey = std::tuple<SpvDecoration, uint32_t, uint32_t>;
|
||||
using DecorationNameTable =
|
||||
std::unordered_map<SpvDecoration, std::string, SpvDecorationHash>;
|
||||
|
||||
static const auto* const at_most_once_per_id = new AtMostOnceSet{
|
||||
SpvDecorationArrayStride,
|
||||
};
|
||||
static const auto* const at_most_once_per_member = new AtMostOnceSet{
|
||||
SpvDecorationOffset,
|
||||
SpvDecorationMatrixStride,
|
||||
SpvDecorationRowMajor,
|
||||
SpvDecorationColMajor,
|
||||
};
|
||||
static const auto* const mutually_exclusive_per_id =
|
||||
new MutuallyExclusiveSets{
|
||||
{SpvDecorationBlock, SpvDecorationBufferBlock},
|
||||
};
|
||||
static const auto* const mutually_exclusive_per_member =
|
||||
new MutuallyExclusiveSets{
|
||||
{SpvDecorationRowMajor, SpvDecorationColMajor},
|
||||
};
|
||||
// For printing the decoration name.
|
||||
static const auto* const decoration_name = new DecorationNameTable{
|
||||
{SpvDecorationArrayStride, "ArrayStride"},
|
||||
{SpvDecorationOffset, "Offset"},
|
||||
{SpvDecorationMatrixStride, "MatrixStride"},
|
||||
{SpvDecorationRowMajor, "RowMajor"},
|
||||
{SpvDecorationColMajor, "ColMajor"},
|
||||
{SpvDecorationBlock, "Block"},
|
||||
{SpvDecorationBufferBlock, "BufferBlock"},
|
||||
};
|
||||
// An Array of pairs where the decorations in the pair cannot both be applied
|
||||
// to the same id.
|
||||
static const SpvDecoration mutually_exclusive_per_id[][2] = {
|
||||
{SpvDecorationBlock, SpvDecorationBufferBlock}};
|
||||
static const auto num_mutually_exclusive_per_id_pairs =
|
||||
sizeof(mutually_exclusive_per_id) / (2 * sizeof(SpvDecoration));
|
||||
|
||||
// An Array of pairs where the decorations in the pair cannot both be applied
|
||||
// to the same member.
|
||||
static const SpvDecoration mutually_exclusive_per_member[][2] = {
|
||||
{SpvDecorationRowMajor, SpvDecorationColMajor}};
|
||||
static const auto num_mutually_exclusive_per_mem_pairs =
|
||||
sizeof(mutually_exclusive_per_member) / (2 * sizeof(SpvDecoration));
|
||||
|
||||
std::set<PerIDKey> seen_per_id;
|
||||
std::set<PerMemberKey> seen_per_member;
|
||||
@@ -1006,26 +1067,31 @@ spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) {
|
||||
const auto dec_type = static_cast<SpvDecoration>(words[2]);
|
||||
const auto k = PerIDKey(dec_type, id);
|
||||
const auto already_used = !seen_per_id.insert(k).second;
|
||||
if (already_used &&
|
||||
at_most_once_per_id->find(dec_type) != at_most_once_per_id->end()) {
|
||||
if (already_used && AtMostOncePerId(dec_type)) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
|
||||
<< "ID '" << id << "' decorated with "
|
||||
<< decoration_name->at(dec_type)
|
||||
<< GetDecorationName(dec_type)
|
||||
<< " multiple times is not allowed.";
|
||||
}
|
||||
// Verify certain mutually exclusive decorations are not both applied on
|
||||
// an ID.
|
||||
for (const auto& s : *mutually_exclusive_per_id) {
|
||||
if (s.find(dec_type) == s.end()) continue;
|
||||
for (auto excl_dec_type : s) {
|
||||
if (excl_dec_type == dec_type) continue;
|
||||
const auto excl_k = PerIDKey(excl_dec_type, id);
|
||||
if (seen_per_id.find(excl_k) != seen_per_id.end()) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
|
||||
<< "ID '" << id << "' decorated with both "
|
||||
<< decoration_name->at(dec_type) << " and "
|
||||
<< decoration_name->at(excl_dec_type) << " is not allowed.";
|
||||
}
|
||||
for (uint32_t pair_idx = 0;
|
||||
pair_idx < num_mutually_exclusive_per_id_pairs; ++pair_idx) {
|
||||
SpvDecoration excl_dec_type = SpvDecorationMax;
|
||||
if (mutually_exclusive_per_id[pair_idx][0] == dec_type) {
|
||||
excl_dec_type = mutually_exclusive_per_id[pair_idx][1];
|
||||
} else if (mutually_exclusive_per_id[pair_idx][1] == dec_type) {
|
||||
excl_dec_type = mutually_exclusive_per_id[pair_idx][0];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto excl_k = PerIDKey(excl_dec_type, id);
|
||||
if (seen_per_id.find(excl_k) != seen_per_id.end()) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
|
||||
<< "ID '" << id << "' decorated with both "
|
||||
<< GetDecorationName(dec_type) << " and "
|
||||
<< GetDecorationName(excl_dec_type) << " is not allowed.";
|
||||
}
|
||||
}
|
||||
} else if (SpvOpMemberDecorate == inst.opcode()) {
|
||||
@@ -1034,27 +1100,32 @@ spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) {
|
||||
const auto dec_type = static_cast<SpvDecoration>(words[3]);
|
||||
const auto k = PerMemberKey(dec_type, id, member_id);
|
||||
const auto already_used = !seen_per_member.insert(k).second;
|
||||
if (already_used && at_most_once_per_member->find(dec_type) !=
|
||||
at_most_once_per_member->end()) {
|
||||
if (already_used && AtMostOncePerMember(dec_type)) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
|
||||
<< "ID '" << id << "', member '" << member_id
|
||||
<< "' decorated with " << decoration_name->at(dec_type)
|
||||
<< "' decorated with " << GetDecorationName(dec_type)
|
||||
<< " multiple times is not allowed.";
|
||||
}
|
||||
// Verify certain mutually exclusive decorations are not both applied on
|
||||
// a (ID, member) tuple.
|
||||
for (const auto& s : *mutually_exclusive_per_member) {
|
||||
if (s.find(dec_type) == s.end()) continue;
|
||||
for (auto excl_dec_type : s) {
|
||||
if (excl_dec_type == dec_type) continue;
|
||||
const auto excl_k = PerMemberKey(excl_dec_type, id, member_id);
|
||||
if (seen_per_member.find(excl_k) != seen_per_member.end()) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
|
||||
<< "ID '" << id << "', member '" << member_id
|
||||
<< "' decorated with both " << decoration_name->at(dec_type)
|
||||
<< " and " << decoration_name->at(excl_dec_type)
|
||||
<< " is not allowed.";
|
||||
}
|
||||
for (uint32_t pair_idx = 0;
|
||||
pair_idx < num_mutually_exclusive_per_mem_pairs; ++pair_idx) {
|
||||
SpvDecoration excl_dec_type = SpvDecorationMax;
|
||||
if (mutually_exclusive_per_member[pair_idx][0] == dec_type) {
|
||||
excl_dec_type = mutually_exclusive_per_member[pair_idx][1];
|
||||
} else if (mutually_exclusive_per_member[pair_idx][1] == dec_type) {
|
||||
excl_dec_type = mutually_exclusive_per_member[pair_idx][0];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto excl_k = PerMemberKey(excl_dec_type, id, member_id);
|
||||
if (seen_per_member.find(excl_k) != seen_per_member.end()) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
|
||||
<< "ID '" << id << "', member '" << member_id
|
||||
<< "' decorated with both " << GetDecorationName(dec_type)
|
||||
<< " and " << GetDecorationName(excl_dec_type)
|
||||
<< " is not allowed.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,23 +515,13 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
if (inst->operands().size() > 3 && storage_class != SpvStorageClassOutput &&
|
||||
storage_class != SpvStorageClassPrivate &&
|
||||
storage_class != SpvStorageClassFunction) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable, <id> '" << _.getIdName(inst->id())
|
||||
<< "', has a disallowed initializer & storage class "
|
||||
<< "combination.\n"
|
||||
<< "From Vulkan spec, Appendix A:\n"
|
||||
<< "Variable declarations that include initializers must have "
|
||||
<< "one of the following storage classes: Output, Private, or "
|
||||
<< "Function";
|
||||
}
|
||||
|
||||
if (spvIsWebGPUEnv(_.context()->target_env)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable, <id> '" << _.getIdName(inst->id())
|
||||
<< "', has a disallowed initializer & storage class "
|
||||
<< "combination.\n"
|
||||
<< "From WebGPU execution environment spec:\n"
|
||||
<< "From " << spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec:\n"
|
||||
<< "Variable declarations that include initializers must have "
|
||||
<< "one of the following storage classes: Output, Private, or "
|
||||
<< "Function";
|
||||
|
||||
@@ -107,14 +107,12 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) {
|
||||
<< "' is a void type.";
|
||||
}
|
||||
|
||||
if ((spvIsVulkanEnv(_.context()->target_env) ||
|
||||
spvIsWebGPUEnv(_.context()->target_env)) &&
|
||||
if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) &&
|
||||
element_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
const char* env_text =
|
||||
spvIsVulkanEnv(_.context()->target_env) ? "Vulkan" : "WebGPU";
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpTypeArray Element Type <id> '" << _.getIdName(element_type_id)
|
||||
<< "' is not valid in " << env_text << " environment.";
|
||||
<< "' is not valid in "
|
||||
<< spvLogStringForEnv(_.context()->target_env) << " environments.";
|
||||
}
|
||||
|
||||
const auto length_index = 2;
|
||||
@@ -172,15 +170,12 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _,
|
||||
<< _.getIdName(element_id) << "' is a void type.";
|
||||
}
|
||||
|
||||
if ((spvIsVulkanEnv(_.context()->target_env) ||
|
||||
spvIsWebGPUEnv(_.context()->target_env)) &&
|
||||
if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) &&
|
||||
element_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
const char* env_text =
|
||||
spvIsVulkanEnv(_.context()->target_env) ? "Vulkan" : "WebGPU";
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpTypeRuntimeArray Element Type <id> '"
|
||||
<< _.getIdName(element_id) << "' is not valid in " << env_text
|
||||
<< " environment.";
|
||||
<< _.getIdName(element_id) << "' is not valid in "
|
||||
<< spvLogStringForEnv(_.context()->target_env) << " environments.";
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
@@ -229,17 +224,15 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
}
|
||||
|
||||
if ((spvIsVulkanEnv(_.context()->target_env) ||
|
||||
spvIsWebGPUEnv(_.context()->target_env)) &&
|
||||
if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) &&
|
||||
member_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
const bool is_last_member =
|
||||
member_type_index == inst->operands().size() - 1;
|
||||
if (!is_last_member) {
|
||||
const char* env_text =
|
||||
spvIsVulkanEnv(_.context()->target_env) ? "Vulkan" : "WebGPU";
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In " << env_text << ", OpTypeRuntimeArray must only be used "
|
||||
<< "for the last member of an OpTypeStruct";
|
||||
<< "In " << spvLogStringForEnv(_.context()->target_env)
|
||||
<< ", OpTypeRuntimeArray must only be used for the last member "
|
||||
"of an OpTypeStruct";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
3rdparty/spirv-tools/test/opt/code_sink_test.cpp
vendored
24
3rdparty/spirv-tools/test/opt/code_sink_test.cpp
vendored
@@ -528,6 +528,30 @@ TEST_F(CodeSinkTest, MoveWithAtomicWithoutSync) {
|
||||
EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(CodeSinkTest, DecorationOnLoad) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %1 "main" %2
|
||||
OpDecorate %3 RelaxedPrecision
|
||||
%void = OpTypeVoid
|
||||
%5 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%2 = OpVariable %_ptr_Input_float Input
|
||||
%1 = OpFunction %void None %5
|
||||
%8 = OpLabel
|
||||
%3 = OpLoad %float %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// We just want to make sure the code does not crash.
|
||||
auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
|
||||
text, /* skip_nop = */ true, /* do_validation = */ true);
|
||||
EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
12
3rdparty/spirv-tools/test/reduce/CMakeLists.txt
vendored
12
3rdparty/spirv-tools/test/reduce/CMakeLists.txt
vendored
@@ -13,15 +13,15 @@
|
||||
# limitations under the License.
|
||||
|
||||
add_spvtools_unittest(TARGET reduce
|
||||
SRCS operand_to_constant_reduction_pass_test.cpp
|
||||
operand_to_undef_reduction_pass_test.cpp
|
||||
operand_to_dominating_id_reduction_pass_test.cpp
|
||||
SRCS operand_to_constant_test.cpp
|
||||
operand_to_undef_test.cpp
|
||||
operand_to_dominating_id_test.cpp
|
||||
reduce_test_util.cpp
|
||||
reduce_test_util.h
|
||||
reducer_test.cpp
|
||||
remove_opname_instruction_reduction_pass_test.cpp
|
||||
remove_unreferenced_instruction_reduction_pass_test.cpp
|
||||
structured_loop_to_selection_reduction_pass_test.cpp
|
||||
remove_opname_instruction_test.cpp
|
||||
remove_unreferenced_instruction_test.cpp
|
||||
structured_loop_to_selection_test.cpp
|
||||
validation_during_reduction_test.cpp
|
||||
LIBS SPIRV-Tools-reduce
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "reduce_test_util.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_const_reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
@@ -97,8 +97,9 @@ TEST(OperandToConstantReductionPassTest, BasicCheck) {
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<OperandToConstReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops =
|
||||
OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(17, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
@@ -146,8 +147,9 @@ TEST(OperandToConstantReductionPassTest, WithCalledFunction) {
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<OperandToConstReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops =
|
||||
OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/reduce/operand_to_dominating_id_reduction_pass.h"
|
||||
#include "reduce_test_util.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
@@ -53,8 +53,8 @@ TEST(OperandToDominatingIdReductionPassTest, BasicCheck) {
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<OperandToDominatingIdReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = OperandToDominatingIdReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(10, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/reduce/operand_to_undef_reduction_pass.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h"
|
||||
#include "test/reduce/reduce_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
@@ -163,8 +163,9 @@ TEST(OperandToUndefReductionPassTest, BasicCheck) {
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<OperandToUndefReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops =
|
||||
OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
|
||||
ASSERT_EQ(10, ops.size());
|
||||
|
||||
@@ -216,8 +217,9 @@ TEST(OperandToUndefReductionPassTest, WithCalledFunction) {
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<OperandToUndefReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops =
|
||||
OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
@@ -24,23 +24,6 @@
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A helper class that subclasses a given reduction pass class in order to
|
||||
// provide a wrapper for its protected methods.
|
||||
template <class ReductionPassT>
|
||||
class TestSubclass : public ReductionPassT {
|
||||
public:
|
||||
// Creates an instance of the reduction pass subclass with respect to target
|
||||
// environment |env|.
|
||||
explicit TestSubclass(const spv_target_env env) : ReductionPassT(env) {}
|
||||
~TestSubclass() = default;
|
||||
|
||||
// A wrapper for GetAvailableOpportunities(...)
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
WrapGetAvailableOpportunities(opt::IRContext* context) const {
|
||||
return ReductionPassT::GetAvailableOpportunities(context);
|
||||
}
|
||||
};
|
||||
|
||||
// Checks whether the given binaries are bit-wise equal.
|
||||
void CheckEqual(spv_target_env env,
|
||||
const std::vector<uint32_t>& expected_binary,
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
#include "reduce_test_util.h"
|
||||
|
||||
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_const_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/reducer.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_pass.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
@@ -217,9 +217,10 @@ TEST(ReducerTest, ExprToConstantAndRemoveUnreferenced) {
|
||||
[&](const std::vector<uint32_t>& binary, uint32_t) -> bool {
|
||||
return ping_pong_interesting.IsInteresting(binary);
|
||||
});
|
||||
reducer.AddReductionPass(MakeUnique<OperandToConstReductionPass>(env));
|
||||
reducer.AddReductionPass(
|
||||
MakeUnique<RemoveUnreferencedInstructionReductionPass>(env));
|
||||
MakeUnique<OperandToConstReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
MakeUnique<RemoveUnreferencedInstructionReductionOpportunityFinder>());
|
||||
|
||||
std::vector<uint32_t> binary_in;
|
||||
SpirvTools t(env);
|
||||
@@ -288,9 +289,9 @@ TEST(ReducerTest, RemoveOpnameAndRemoveUnreferenced) {
|
||||
return ping_pong_interesting.IsInteresting(binary);
|
||||
});
|
||||
reducer.AddReductionPass(
|
||||
MakeUnique<RemoveOpNameInstructionReductionPass>(env));
|
||||
MakeUnique<RemoveOpNameInstructionReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
MakeUnique<RemoveUnreferencedInstructionReductionPass>(env));
|
||||
MakeUnique<RemoveUnreferencedInstructionReductionOpportunityFinder>());
|
||||
|
||||
std::vector<uint32_t> binary_in;
|
||||
SpirvTools t(env);
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/reduction_opportunity.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_pass.h"
|
||||
#include "source/reduce/reduction_pass.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
@@ -42,8 +43,8 @@ TEST(RemoveOpnameInstructionReductionPassTest, NothingToRemove) {
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, source, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<RemoveOpNameInstructionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = RemoveOpNameInstructionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
@@ -76,8 +77,8 @@ TEST(RemoveOpnameInstructionReductionPassTest, RemoveSingleOpName) {
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<RemoveOpNameInstructionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = RemoveOpNameInstructionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
@@ -126,14 +127,14 @@ TEST(RemoveOpnameInstructionReductionPassTest, TryApplyRemovesAllOpName) {
|
||||
const std::string expected = prologue + epilogue;
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
auto pass = TestSubclass<RemoveOpNameInstructionReductionPass>(env);
|
||||
|
||||
{
|
||||
// Check the right number of opportunities is detected
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = RemoveOpNameInstructionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(5, ops.size());
|
||||
}
|
||||
|
||||
@@ -142,7 +143,11 @@ TEST(RemoveOpnameInstructionReductionPassTest, TryApplyRemovesAllOpName) {
|
||||
std::vector<uint32_t> binary;
|
||||
SpirvTools t(env);
|
||||
ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption));
|
||||
auto reduced_binary = pass.TryApplyReduction(binary);
|
||||
auto reduced_binary =
|
||||
ReductionPass(env,
|
||||
spvtools::MakeUnique<
|
||||
RemoveOpNameInstructionReductionOpportunityFinder>())
|
||||
.TryApplyReduction(binary);
|
||||
CheckEqual(env, expected, reduced_binary);
|
||||
}
|
||||
}
|
||||
@@ -190,14 +195,14 @@ TEST(RemoveOpnameInstructionReductionPassTest,
|
||||
const std::string expected = prologue + epilogue;
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
auto pass = TestSubclass<RemoveOpNameInstructionReductionPass>(env);
|
||||
|
||||
{
|
||||
// Check the right number of opportunities is detected
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = RemoveOpNameInstructionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(6, ops.size());
|
||||
}
|
||||
|
||||
@@ -206,7 +211,11 @@ TEST(RemoveOpnameInstructionReductionPassTest,
|
||||
std::vector<uint32_t> binary;
|
||||
SpirvTools t(env);
|
||||
ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption));
|
||||
auto reduced_binary = pass.TryApplyReduction(binary);
|
||||
auto reduced_binary =
|
||||
ReductionPass(env,
|
||||
spvtools::MakeUnique<
|
||||
RemoveOpNameInstructionReductionOpportunityFinder>())
|
||||
.TryApplyReduction(binary);
|
||||
CheckEqual(env, expected, reduced_binary);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/reduction_opportunity.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
|
||||
#include "source/reduce/reduction_pass.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h"
|
||||
#include "source/util/make_unique.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
@@ -73,9 +75,8 @@ TEST(RemoveUnreferencedInstructionReductionPassTest, RemoveStores) {
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||
const auto pass =
|
||||
TestSubclass<RemoveUnreferencedInstructionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = RemoveUnreferencedInstructionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(4, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
@@ -132,7 +133,9 @@ TEST(RemoveUnreferencedInstructionReductionPassTest, ApplyReduction) {
|
||||
SpirvTools t(env);
|
||||
ASSERT_TRUE(t.Assemble(original, &binary, kReduceAssembleOption));
|
||||
|
||||
auto pass = TestSubclass<RemoveUnreferencedInstructionReductionPass>(env);
|
||||
ReductionPass pass(
|
||||
env, spvtools::MakeUnique<
|
||||
RemoveUnreferencedInstructionReductionOpportunityFinder>());
|
||||
|
||||
{
|
||||
// Attempt 1 should remove everything removable.
|
||||
@@ -12,9 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/reduce/structured_loop_to_selection_reduction_pass.h"
|
||||
#include "reduce_test_util.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
@@ -62,8 +62,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader1) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -208,8 +208,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader2) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(4, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -677,8 +677,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader3) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(0, ops.size());
|
||||
}
|
||||
|
||||
@@ -755,8 +755,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader4) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
// Initially there are two opportunities.
|
||||
ASSERT_EQ(2, ops.size());
|
||||
@@ -878,8 +878,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak1) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -953,8 +953,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak2) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -1021,8 +1021,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, UnconditionalBreak) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -1221,8 +1221,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, Complex) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(2, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -1688,8 +1688,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, ComplexOptimized) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(2, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2005,8 +2005,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, DominanceIssue) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2153,8 +2153,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, AccessChainIssue) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2310,8 +2310,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, DominanceAndPhiIssue) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2418,8 +2418,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, OpLineBeforeOpPhi) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2508,8 +2508,8 @@ TEST(StructuredLoopToSelectionReductionPassTest,
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
// There should be no opportunities.
|
||||
ASSERT_EQ(0, ops.size());
|
||||
@@ -2552,8 +2552,8 @@ TEST(StructuredLoopToSelectionReductionPassTest,
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
// There should be no opportunities.
|
||||
ASSERT_EQ(0, ops.size());
|
||||
@@ -2592,8 +2592,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, ContinueTargetIsSwitchTarget) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(1, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2667,8 +2667,8 @@ TEST(StructuredLoopToSelectionReductionPassTest,
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(1, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2730,8 +2730,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LoopBranchesStraightToMerge) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(1, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2787,8 +2787,8 @@ TEST(StructuredLoopToSelectionReductionPassTest,
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(1, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2871,8 +2871,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, MultipleAccessChains) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(1, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -2967,8 +2967,8 @@ TEST(StructuredLoopToSelectionReductionPassTest,
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(2, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -3086,8 +3086,8 @@ TEST(StructuredLoopToSelectionReductionPassTest,
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(2, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -3206,8 +3206,8 @@ TEST(StructuredLoopToSelectionReductionPassTest,
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
// We cannot transform the inner loop due to its header jumping straight to
|
||||
// the outer loop merge (the inner loop's merge does not post-dominate its
|
||||
@@ -3251,7 +3251,8 @@ TEST(StructuredLoopToSelectionReductionPassTest,
|
||||
CheckEqual(env, after_op_0, context.get());
|
||||
|
||||
// Now look again for more opportunities.
|
||||
ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
// What was the inner loop should now be transformable, as the jump to the
|
||||
// outer loop's merge has been redirected.
|
||||
@@ -3418,8 +3419,8 @@ TEST(StructuredLoopToSelectionReductionPassTest, LongAccessChains) {
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
|
||||
const auto pass = TestSubclass<StructuredLoopToSelectionReductionPass>(env);
|
||||
auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||
auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
|
||||
.GetAvailableOpportunities(context.get());
|
||||
|
||||
ASSERT_EQ(1, ops.size());
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
@@ -22,24 +22,21 @@ namespace spvtools {
|
||||
namespace reduce {
|
||||
namespace {
|
||||
|
||||
// A dumb reduction pass that removes global values regardless of whether they
|
||||
// are referenced. This is very likely to make the resulting module invalid. We
|
||||
// use this to test the reducer's behavior in the scenario where a bad reduction
|
||||
// pass leads to an invalid module.
|
||||
class BlindlyRemoveGlobalValuesPass : public ReductionPass {
|
||||
// A dumb reduction opportunity finder that finds opportunities to remove global
|
||||
// values regardless of whether they are referenced. This is very likely to make
|
||||
// the resulting module invalid. We use this to test the reducer's behavior in
|
||||
// the scenario where a bad reduction pass leads to an invalid module.
|
||||
class BlindlyRemoveGlobalValuesReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
// Creates the reduction pass in the context of the given target environment
|
||||
// |target_env|
|
||||
explicit BlindlyRemoveGlobalValuesPass(const spv_target_env target_env)
|
||||
: ReductionPass(target_env) {}
|
||||
BlindlyRemoveGlobalValuesReductionOpportunityFinder() = default;
|
||||
|
||||
~BlindlyRemoveGlobalValuesPass() override = default;
|
||||
~BlindlyRemoveGlobalValuesReductionOpportunityFinder() override = default;
|
||||
|
||||
// The name of this pass.
|
||||
std::string GetName() const final { return "BlindlyRemoveGlobalValuesPass"; };
|
||||
|
||||
protected:
|
||||
// Adds opportunities to remove all global values. Assuming they are all
|
||||
// Finds opportunities to remove all global values. Assuming they are all
|
||||
// referenced (directly or indirectly) from elsewhere in the module, each such
|
||||
// opportunity will make the module invalid.
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
@@ -153,7 +150,8 @@ TEST(ValidationDuringReductionTest, CheckInvalidPassMakesNoProgress) {
|
||||
reducer.SetInterestingnessFunction(
|
||||
[](const std::vector<uint32_t>&, uint32_t) -> bool { return true; });
|
||||
|
||||
reducer.AddReductionPass(MakeUnique<BlindlyRemoveGlobalValuesPass>(env));
|
||||
reducer.AddReductionPass(
|
||||
MakeUnique<BlindlyRemoveGlobalValuesReductionOpportunityFinder>());
|
||||
|
||||
std::vector<uint32_t> binary_in;
|
||||
SpirvTools t(env);
|
||||
@@ -357,7 +355,8 @@ TEST(ValidationDuringReductionTest, CheckNotAlwaysInvalidCanMakeProgress) {
|
||||
reducer.SetInterestingnessFunction(
|
||||
[](const std::vector<uint32_t>&, uint32_t) -> bool { return true; });
|
||||
|
||||
reducer.AddReductionPass(MakeUnique<BlindlyRemoveGlobalValuesPass>(env));
|
||||
reducer.AddReductionPass(
|
||||
MakeUnique<BlindlyRemoveGlobalValuesReductionOpportunityFinder>());
|
||||
|
||||
std::vector<uint32_t> binary_in;
|
||||
SpirvTools t(env);
|
||||
|
||||
361
3rdparty/spirv-tools/test/val/val_builtins_test.cpp
vendored
361
3rdparty/spirv-tools/test/val/val_builtins_test.cpp
vendored
@@ -24,6 +24,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/spirv_target_env.h"
|
||||
#include "test/unit_spirv.h"
|
||||
#include "test/val/val_fixtures.h"
|
||||
|
||||
@@ -53,8 +54,13 @@ using ValidateBuiltIns = spvtest::ValidateBase<bool>;
|
||||
using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult =
|
||||
spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
|
||||
const char*, TestResult>>;
|
||||
using ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult =
|
||||
spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
|
||||
const char*, TestResult>>;
|
||||
using ValidateVulkanCombineBuiltInArrayedVariable = spvtest::ValidateBase<
|
||||
std::tuple<const char*, const char*, const char*, const char*, TestResult>>;
|
||||
using ValidateWebGPUCombineBuiltInArrayedVariable = spvtest::ValidateBase<
|
||||
std::tuple<const char*, const char*, const char*, const char*, TestResult>>;
|
||||
|
||||
struct EntryPoint {
|
||||
std::string name;
|
||||
@@ -124,6 +130,13 @@ OpCapability SampleRateShading
|
||||
)";
|
||||
}
|
||||
|
||||
std::string GetWebGPUShaderCapabilities() {
|
||||
return R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
)";
|
||||
}
|
||||
|
||||
std::string GetDefaultShaderTypes() {
|
||||
return R"(
|
||||
%void = OpTypeVoid
|
||||
@@ -201,6 +214,55 @@ std::string GetDefaultShaderTypes() {
|
||||
)";
|
||||
}
|
||||
|
||||
std::string GetWebGPUShaderTypes() {
|
||||
return R"(
|
||||
%void = OpTypeVoid
|
||||
%func = OpTypeFunction %void
|
||||
%bool = OpTypeBool
|
||||
%f32 = OpTypeFloat 32
|
||||
%u32 = OpTypeInt 32 0
|
||||
%f32vec2 = OpTypeVector %f32 2
|
||||
%f32vec3 = OpTypeVector %f32 3
|
||||
%f32vec4 = OpTypeVector %f32 4
|
||||
%u32vec2 = OpTypeVector %u32 2
|
||||
%u32vec3 = OpTypeVector %u32 3
|
||||
%u32vec4 = OpTypeVector %u32 4
|
||||
|
||||
%f32_0 = OpConstant %f32 0
|
||||
%f32_1 = OpConstant %f32 1
|
||||
%f32_2 = OpConstant %f32 2
|
||||
%f32_3 = OpConstant %f32 3
|
||||
%f32_4 = OpConstant %f32 4
|
||||
%f32_h = OpConstant %f32 0.5
|
||||
%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1
|
||||
%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2
|
||||
%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2
|
||||
%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3
|
||||
%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
|
||||
%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4
|
||||
|
||||
%u32_0 = OpConstant %u32 0
|
||||
%u32_1 = OpConstant %u32 1
|
||||
%u32_2 = OpConstant %u32 2
|
||||
%u32_3 = OpConstant %u32 3
|
||||
%u32_4 = OpConstant %u32 4
|
||||
|
||||
%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1
|
||||
%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2
|
||||
%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
|
||||
|
||||
%u32arr2 = OpTypeArray %u32 %u32_2
|
||||
%u32arr3 = OpTypeArray %u32 %u32_3
|
||||
%u32arr4 = OpTypeArray %u32 %u32_4
|
||||
%f32arr2 = OpTypeArray %f32 %u32_2
|
||||
%f32arr3 = OpTypeArray %f32 %u32_3
|
||||
%f32arr4 = OpTypeArray %f32 %u32_4
|
||||
|
||||
%f32vec3arr3 = OpTypeArray %f32vec3 %u32_3
|
||||
%f32vec4arr3 = OpTypeArray %f32vec4 %u32_3
|
||||
)";
|
||||
}
|
||||
|
||||
CodeGenerator GetDefaultShaderCodeGenerator() {
|
||||
CodeGenerator generator;
|
||||
generator.capabilities_ = GetDefaultShaderCapabilities();
|
||||
@@ -209,24 +271,47 @@ CodeGenerator GetDefaultShaderCodeGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
CodeGenerator GetWebGPUShaderCodeGenerator() {
|
||||
CodeGenerator generator;
|
||||
generator.capabilities_ = GetWebGPUShaderCapabilities();
|
||||
generator.memory_model_ = "OpMemoryModel Logical VulkanKHR\n";
|
||||
generator.extensions_ = "OpExtension \"SPV_KHR_vulkan_memory_model\"\n";
|
||||
generator.types_ = GetWebGPUShaderTypes();
|
||||
return generator;
|
||||
}
|
||||
|
||||
bool InitializerRequired(spv_target_env env, const char* const storage_class) {
|
||||
return spvIsWebGPUEnv(env) && (strncmp(storage_class, "Output", 6) == 0 ||
|
||||
strncmp(storage_class, "Private", 7) == 0 ||
|
||||
strncmp(storage_class, "Function", 8) == 0);
|
||||
}
|
||||
|
||||
CodeGenerator GetInMainCodeGenerator(spv_target_env env,
|
||||
const char* const built_in,
|
||||
const char* const execution_model,
|
||||
const char* const storage_class,
|
||||
const char* const data_type) {
|
||||
CodeGenerator generator = spvIsWebGPUEnv(env)
|
||||
? GetWebGPUShaderCodeGenerator()
|
||||
: GetDefaultShaderCodeGenerator();
|
||||
|
||||
CodeGenerator generator = GetDefaultShaderCodeGenerator();
|
||||
generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn ";
|
||||
generator.before_types_ += built_in;
|
||||
generator.before_types_ += "\n";
|
||||
|
||||
std::ostringstream after_types;
|
||||
|
||||
after_types << "%built_in_type = OpTypeStruct " << data_type << "\n";
|
||||
if (InitializerRequired(env, storage_class)) {
|
||||
after_types << "%built_in_null = OpConstantNull %built_in_type\n";
|
||||
}
|
||||
after_types << "%built_in_ptr = OpTypePointer " << storage_class
|
||||
<< " %built_in_type\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class
|
||||
<< "\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
|
||||
if (InitializerRequired(env, storage_class)) {
|
||||
after_types << " %built_in_null";
|
||||
}
|
||||
after_types << "\n";
|
||||
after_types << "%data_ptr = OpTypePointer " << storage_class << " "
|
||||
<< data_type << "\n";
|
||||
generator.after_types_ = after_types.str();
|
||||
@@ -265,6 +350,19 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) {
|
||||
)";
|
||||
generator.entry_points_.push_back(std::move(entry_point));
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = GetInMainCodeGenerator(
|
||||
SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type);
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||
@@ -276,24 +374,52 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) {
|
||||
TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InMain) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = GetDefaultShaderCodeGenerator();
|
||||
CodeGenerator generator = GetInMainCodeGenerator(
|
||||
SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type);
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
if (test_result.error_str) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
|
||||
}
|
||||
if (test_result.error_str2) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
|
||||
}
|
||||
}
|
||||
|
||||
CodeGenerator GetInFunctionCodeGenerator(spv_target_env env,
|
||||
const char* const built_in,
|
||||
const char* const execution_model,
|
||||
const char* const storage_class,
|
||||
const char* const data_type) {
|
||||
CodeGenerator generator = spvIsWebGPUEnv(env)
|
||||
? GetWebGPUShaderCodeGenerator()
|
||||
: GetDefaultShaderCodeGenerator();
|
||||
|
||||
generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn ";
|
||||
generator.before_types_ += built_in;
|
||||
generator.before_types_ += "\n";
|
||||
|
||||
std::ostringstream after_types;
|
||||
after_types << "%built_in_type = OpTypeStruct " << data_type << "\n";
|
||||
if (InitializerRequired(env, storage_class)) {
|
||||
after_types << "%built_in_null = OpConstantNull %built_in_type\n";
|
||||
}
|
||||
after_types << "%built_in_ptr = OpTypePointer " << storage_class
|
||||
<< " %built_in_type\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class
|
||||
<< "\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
|
||||
if (InitializerRequired(env, storage_class)) {
|
||||
after_types << " %built_in_null";
|
||||
}
|
||||
after_types << "\n";
|
||||
after_types << "%data_ptr = OpTypePointer " << storage_class << " "
|
||||
<< data_type << "\n";
|
||||
generator.after_types_ = after_types.str();
|
||||
@@ -331,15 +457,35 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) {
|
||||
%val2 = OpFunctionCall %void %foo
|
||||
)";
|
||||
|
||||
generator.add_at_the_end_ = R"(
|
||||
std::string function_body = R"(
|
||||
%foo = OpFunction %void None %func
|
||||
%foo_entry = OpLabel
|
||||
%ptr = OpAccessChain %data_ptr %built_in_var %u32_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
if (spvIsWebGPUEnv(env)) {
|
||||
generator.after_types_ += function_body;
|
||||
} else {
|
||||
generator.add_at_the_end_ = function_body;
|
||||
}
|
||||
|
||||
generator.entry_points_.push_back(std::move(entry_point));
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = GetInFunctionCodeGenerator(
|
||||
SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type);
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||
@@ -351,23 +497,51 @@ OpFunctionEnd
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) {
|
||||
TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InFunction) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = GetDefaultShaderCodeGenerator();
|
||||
CodeGenerator generator = GetInFunctionCodeGenerator(
|
||||
SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type);
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
if (test_result.error_str) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
|
||||
}
|
||||
if (test_result.error_str2) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
|
||||
}
|
||||
}
|
||||
|
||||
CodeGenerator GetVariableCodeGenerator(spv_target_env env,
|
||||
const char* const built_in,
|
||||
const char* const execution_model,
|
||||
const char* const storage_class,
|
||||
const char* const data_type) {
|
||||
CodeGenerator generator = spvIsWebGPUEnv(env)
|
||||
? GetWebGPUShaderCodeGenerator()
|
||||
: GetDefaultShaderCodeGenerator();
|
||||
|
||||
generator.before_types_ = "OpDecorate %built_in_var BuiltIn ";
|
||||
generator.before_types_ += built_in;
|
||||
generator.before_types_ += "\n";
|
||||
|
||||
std::ostringstream after_types;
|
||||
if (InitializerRequired(env, storage_class)) {
|
||||
after_types << "%built_in_null = OpConstantNull " << data_type << "\n";
|
||||
}
|
||||
after_types << "%built_in_ptr = OpTypePointer " << storage_class << " "
|
||||
<< data_type << "\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class
|
||||
<< "\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
|
||||
if (InitializerRequired(env, storage_class)) {
|
||||
after_types << " %built_in_null";
|
||||
}
|
||||
after_types << "\n";
|
||||
generator.after_types_ = after_types.str();
|
||||
|
||||
EntryPoint entry_point;
|
||||
@@ -379,7 +553,7 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) {
|
||||
}
|
||||
// Any kind of reference would do.
|
||||
entry_point.body = R"(
|
||||
%val = OpBitcast %u64 %built_in_var
|
||||
%val = OpBitcast %u32 %built_in_var
|
||||
)";
|
||||
|
||||
std::ostringstream execution_modes;
|
||||
@@ -405,6 +579,19 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) {
|
||||
|
||||
generator.entry_points_.push_back(std::move(entry_point));
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = GetVariableCodeGenerator(
|
||||
SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type);
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||
@@ -416,6 +603,27 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, Variable) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = GetVariableCodeGenerator(
|
||||
SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type);
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
if (test_result.error_str) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
|
||||
}
|
||||
if (test_result.error_str2) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
ClipAndCullDistanceOutputSuccess,
|
||||
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
|
||||
@@ -1023,6 +1231,21 @@ INSTANTIATE_TEST_CASE_P(
|
||||
"TessellationEvaluation"),
|
||||
Values("Output"), Values("%f32vec4"), Values(TestResult())), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionOutputSuccess,
|
||||
ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
|
||||
Combine(Values("Position"), Values("Vertex"), Values("Output"),
|
||||
Values("%f32vec4"), Values(TestResult())), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionOutputFailure,
|
||||
ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
|
||||
Combine(Values("Position"), Values("Fragment", "GLCompute"),
|
||||
Values("Output"), Values("%f32vec4"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"WebGPU spec allows BuiltIn Position to be used "
|
||||
"only with the Vertex execution model."))), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionInputSuccess,
|
||||
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
|
||||
@@ -1030,6 +1253,16 @@ INSTANTIATE_TEST_CASE_P(
|
||||
Values("Geometry", "TessellationControl", "TessellationEvaluation"),
|
||||
Values("Input"), Values("%f32vec4"), Values(TestResult())), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionInputFailure,
|
||||
ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
|
||||
Combine(
|
||||
Values("Position"), Values("Vertex", "Fragment", "GLCompute"),
|
||||
Values("Input"), Values("%f32vec4"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"WebGPU spec allows BuiltIn Position to be only used "
|
||||
"for variables with Output storage class"))), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionVertexInput,
|
||||
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
|
||||
@@ -1061,6 +1294,15 @@ INSTANTIATE_TEST_CASE_P(
|
||||
"needs to be a 4-component 32-bit float vector",
|
||||
"is not a float vector"))), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionNotFloatVector,
|
||||
ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
|
||||
Combine(
|
||||
Values("Position"), Values("Vertex"), Values("Output"),
|
||||
Values("%f32arr4", "%u32vec4"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"needs to be a 4-component 32-bit float vector"))), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionNotFloatVec4,
|
||||
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
|
||||
@@ -1070,6 +1312,15 @@ INSTANTIATE_TEST_CASE_P(
|
||||
"needs to be a 4-component 32-bit float vector",
|
||||
"has 3 components"))), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionNotFloatVec4,
|
||||
ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
|
||||
Combine(
|
||||
Values("Position"), Values("Vertex"), Values("Output"),
|
||||
Values("%f32vec3"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"needs to be a 4-component 32-bit float vector"))), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionNotF32Vec4,
|
||||
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
|
||||
@@ -1549,24 +1800,32 @@ INSTANTIATE_TEST_CASE_P(
|
||||
"needs to be a 32-bit int scalar",
|
||||
"has bit width 64"))), );
|
||||
|
||||
TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env,
|
||||
const char* const built_in,
|
||||
const char* const execution_model,
|
||||
const char* const storage_class,
|
||||
const char* const data_type) {
|
||||
CodeGenerator generator = spvIsWebGPUEnv(env)
|
||||
? GetWebGPUShaderCodeGenerator()
|
||||
: GetDefaultShaderCodeGenerator();
|
||||
|
||||
CodeGenerator generator = GetDefaultShaderCodeGenerator();
|
||||
generator.before_types_ = "OpDecorate %built_in_var BuiltIn ";
|
||||
generator.before_types_ += built_in;
|
||||
generator.before_types_ += "\n";
|
||||
|
||||
std::ostringstream after_types;
|
||||
after_types << "%built_in_array = OpTypeArray " << data_type << " %u32_3\n";
|
||||
if (InitializerRequired(env, storage_class)) {
|
||||
after_types << "%built_in_array_null = OpConstantNull %built_in_array\n";
|
||||
}
|
||||
|
||||
after_types << "%built_in_ptr = OpTypePointer " << storage_class
|
||||
<< " %built_in_array\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class
|
||||
<< "\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
|
||||
if (InitializerRequired(env, storage_class)) {
|
||||
after_types << " %built_in_array_null";
|
||||
}
|
||||
after_types << "\n";
|
||||
generator.after_types_ = after_types.str();
|
||||
|
||||
EntryPoint entry_point;
|
||||
@@ -1575,7 +1834,7 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) {
|
||||
entry_point.interfaces = "%built_in_var";
|
||||
// Any kind of reference would do.
|
||||
entry_point.body = R"(
|
||||
%val = OpBitcast %u64 %built_in_var
|
||||
%val = OpBitcast %u32 %built_in_var
|
||||
)";
|
||||
|
||||
std::ostringstream execution_modes;
|
||||
@@ -1601,6 +1860,19 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) {
|
||||
|
||||
generator.entry_points_.push_back(std::move(entry_point));
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = GetArrayedVariableCodeGenerator(
|
||||
SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type);
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||
@@ -1612,6 +1884,27 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ValidateWebGPUCombineBuiltInArrayedVariable, Variable) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = GetArrayedVariableCodeGenerator(
|
||||
SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type);
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
if (test_result.error_str) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
|
||||
}
|
||||
if (test_result.error_str2) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(PointSizeArrayedF32TessControl,
|
||||
ValidateVulkanCombineBuiltInArrayedVariable,
|
||||
Combine(Values("PointSize"),
|
||||
@@ -1652,7 +1945,15 @@ INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionArrayedF32Vec4Vertex, ValidateVulkanCombineBuiltInArrayedVariable,
|
||||
Combine(Values("Position"), Values("Vertex"), Values("Output"),
|
||||
Values("%f32"),
|
||||
Values("%f32vec4"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"needs to be a 4-component 32-bit float vector",
|
||||
"is not a float vector"))), );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PositionArrayedF32Vec4Vertex, ValidateWebGPUCombineBuiltInArrayedVariable,
|
||||
Combine(Values("Position"), Values("Vertex"), Values("Output"),
|
||||
Values("%f32vec4"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"needs to be a 4-component 32-bit float vector",
|
||||
"is not a float vector"))), );
|
||||
|
||||
62
3rdparty/spirv-tools/test/val/val_cfg_test.cpp
vendored
62
3rdparty/spirv-tools/test/val/val_cfg_test.cpp
vendored
@@ -493,13 +493,10 @@ TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) {
|
||||
str += "OpFunctionEnd\n";
|
||||
|
||||
CompileSuccessfully(str);
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
MatchesRegex("Block\\(s\\) \\{11\\[%11\\]\\} are referenced but not "
|
||||
"defined in function .\\[%Main\\]\n %Main = OpFunction "
|
||||
"%void None %10\n"))
|
||||
<< str;
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("'Target Label' operands for OpBranch must "
|
||||
"be the ID of an OpLabel instruction"));
|
||||
}
|
||||
|
||||
TEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) {
|
||||
@@ -2060,6 +2057,57 @@ TEST_F(ValidateCFG, KernelWithPhiPtr) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateCFG, SwitchTargetMustBeLabel) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %1 "foo"
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%void = OpTypeVoid
|
||||
%5 = OpTypeFunction %void
|
||||
%1 = OpFunction %void None %5
|
||||
%6 = OpLabel
|
||||
%7 = OpCopyObject %uint %uint_0
|
||||
OpSelectionMerge %8 None
|
||||
OpSwitch %uint_0 %8 0 %7
|
||||
%8 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("'Target Label' operands for OpSwitch must "
|
||||
"be IDs of an OpLabel instruction"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateCFG, BranchTargetMustBeLabel) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %1 "foo"
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%void = OpTypeVoid
|
||||
%5 = OpTypeFunction %void
|
||||
%1 = OpFunction %void None %5
|
||||
%2 = OpLabel
|
||||
%7 = OpCopyObject %uint %uint_0
|
||||
OpBranch %7
|
||||
%8 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("'Target Label' operands for OpBranch must "
|
||||
"be the ID of an OpLabel instruction"));
|
||||
}
|
||||
|
||||
/// TODO(umar): Nested CFG constructs
|
||||
|
||||
} // namespace
|
||||
|
||||
17
3rdparty/spirv-tools/test/val/val_data_test.cpp
vendored
17
3rdparty/spirv-tools/test/val/val_data_test.cpp
vendored
@@ -934,6 +934,23 @@ TEST_F(ValidateData, webgpu_RTA_not_at_end_of_struct) {
|
||||
"OpTypeStruct %_runtimearr_uint %uint\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, invalid_forward_reference_in_array) {
|
||||
std::string str = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%_arr_3_uint_1 = OpTypeArray %_arr_3_uint_1 %uint_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_UNIVERSAL_1_3);
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Forward reference operands in an OpTypeArray must "
|
||||
"first be declared using OpTypeForwardPointer."));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -3285,7 +3285,7 @@ TEST_F(ValidateDecorations,
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Structure id 6 decorated as Block for variable in Uniform "
|
||||
"storage class must follow standard uniform buffer layout "
|
||||
"rules: member 2 at offset 24 is not aligned to 16"));
|
||||
"rules: member 2 at offset 152 is not aligned to 16"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations,
|
||||
@@ -3418,7 +3418,8 @@ TEST_F(ValidateDecorations, BlockUniformBufferLayoutIncorrectArrayStrideBad) {
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Structure id 6 decorated as Block for variable in Uniform storage "
|
||||
"class must follow standard uniform buffer layout rules: member 4 is "
|
||||
"class must follow standard uniform buffer layout rules: member 4 "
|
||||
"contains "
|
||||
"an array with stride 49 not satisfying alignment to 16"));
|
||||
}
|
||||
|
||||
@@ -5302,6 +5303,194 @@ OpFunctionEnd
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, InvalidStraddle) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpMemberDecorate %inner_struct 0 Offset 0
|
||||
OpMemberDecorate %inner_struct 1 Offset 4
|
||||
OpDecorate %outer_struct Block
|
||||
OpMemberDecorate %outer_struct 0 Offset 0
|
||||
OpMemberDecorate %outer_struct 1 Offset 8
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float2 = OpTypeVector %float 2
|
||||
%inner_struct = OpTypeStruct %float %float2
|
||||
%outer_struct = OpTypeStruct %float2 %inner_struct
|
||||
%ptr_ssbo_outer = OpTypePointer StorageBuffer %outer_struct
|
||||
%var = OpVariable %ptr_ssbo_outer StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Structure id 2 decorated as Block for variable in "
|
||||
"StorageBuffer storage class must follow relaxed "
|
||||
"storage buffer layout rules: member 1 is an "
|
||||
"improperly straddling vector at offset 12"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, DescriptorArray) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpMemberDecorate %struct 1 Offset 1
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%int = OpTypeInt 32 0
|
||||
%int_2 = OpConstant %int 2
|
||||
%float2 = OpTypeVector %float 2
|
||||
%struct = OpTypeStruct %float %float2
|
||||
%struct_array = OpTypeArray %struct %int_2
|
||||
%ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array
|
||||
%var = OpVariable %ptr_ssbo_array StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Structure id 2 decorated as Block for variable in "
|
||||
"StorageBuffer storage class must follow standard "
|
||||
"storage buffer layout rules: member 1 at offset 1 is "
|
||||
"not aligned to 8"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, DescriptorRuntimeArray) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpMemberDecorate %struct 1 Offset 1
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%int = OpTypeInt 32 0
|
||||
%float2 = OpTypeVector %float 2
|
||||
%struct = OpTypeStruct %float %float2
|
||||
%struct_array = OpTypeRuntimeArray %struct
|
||||
%ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array
|
||||
%var = OpVariable %ptr_ssbo_array StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Structure id 2 decorated as Block for variable in "
|
||||
"StorageBuffer storage class must follow standard "
|
||||
"storage buffer layout rules: member 1 at offset 1 is "
|
||||
"not aligned to 8"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, MultiDimensionalArray) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpDecorate %array_4 ArrayStride 4
|
||||
OpDecorate %array_3 ArrayStride 48
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_3 = OpConstant %int 3
|
||||
%int_4 = OpConstant %int 4
|
||||
%array_4 = OpTypeArray %int %int_4
|
||||
%array_3 = OpTypeArray %array_4 %int_3
|
||||
%struct = OpTypeStruct %array_3
|
||||
%ptr_struct = OpTypePointer Uniform %struct
|
||||
%var = OpVariable %ptr_struct Uniform
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Structure id 2 decorated as Block for variable in "
|
||||
"Uniform storage class must follow standard uniform "
|
||||
"buffer layout rules: member 0 contains an array with "
|
||||
"stride 4 not satisfying alignment to 16"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, ImproperStraddleInArray) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
OpDecorate %array ArrayStride 24
|
||||
OpMemberDecorate %inner 0 Offset 0
|
||||
OpMemberDecorate %inner 1 Offset 4
|
||||
OpMemberDecorate %inner 2 Offset 12
|
||||
OpMemberDecorate %inner 3 Offset 16
|
||||
OpDecorate %var DescriptorSet 0
|
||||
OpDecorate %var Binding 0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_2 = OpConstant %int 2
|
||||
%int2 = OpTypeVector %int 2
|
||||
%inner = OpTypeStruct %int %int2 %int %int
|
||||
%array = OpTypeArray %inner %int_2
|
||||
%struct = OpTypeStruct %array
|
||||
%ptr_struct = OpTypePointer StorageBuffer %struct
|
||||
%var = OpVariable %ptr_struct StorageBuffer
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Structure id 4 decorated as Block for variable in "
|
||||
"StorageBuffer storage class must follow relaxed "
|
||||
"storage buffer layout rules: member 1 is an "
|
||||
"improperly straddling vector at offset 28"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -449,12 +449,11 @@ OpFunctionEnd
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpVariable, <id> '5[%5]', has a disallowed initializer & storage "
|
||||
"class combination.\nFrom WebGPU execution environment spec:\n"
|
||||
"Variable declarations that include initializers must have one of "
|
||||
"the following storage classes: Output, Private, or Function\n"
|
||||
" %5 = OpVariable %_ptr_Uniform_float Uniform %float_1\n"));
|
||||
HasSubstr("OpVariable, <id> '5[%5]', has a disallowed initializer & "
|
||||
"storage class combination.\nFrom WebGPU spec:\nVariable "
|
||||
"declarations that include initializers must have one of the "
|
||||
"following storage classes: Output, Private, or Function\n %5 "
|
||||
"= OpVariable %_ptr_Uniform_float Uniform %float_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, WebGPUOutputStorageClassWithoutInitializerBad) {
|
||||
@@ -628,12 +627,11 @@ OpFunctionEnd
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpVariable, <id> '5[%5]', has a disallowed initializer & storage "
|
||||
"class combination.\nFrom Vulkan spec, Appendix A:\n"
|
||||
"Variable declarations that include initializers must have one of "
|
||||
"the following storage classes: Output, Private, or Function\n "
|
||||
"%5 = OpVariable %_ptr_Input_float Input %float_1\n"));
|
||||
HasSubstr("OpVariable, <id> '5[%5]', has a disallowed initializer & "
|
||||
"storage class combination.\nFrom Vulkan spec:\nVariable "
|
||||
"declarations that include initializers must have one of the "
|
||||
"following storage classes: Output, Private, or Function\n %5 "
|
||||
"= OpVariable %_ptr_Input_float Input %float_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, ArrayLenCorrectResultType) {
|
||||
@@ -2179,7 +2177,7 @@ OpFunctionEnd
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '3[%_runtimearr_2]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_2 = "
|
||||
"valid in Vulkan environments.\n %_runtimearr__runtimearr_2 = "
|
||||
"OpTypeRuntimeArray %_runtimearr_2\n"));
|
||||
}
|
||||
|
||||
@@ -2210,7 +2208,7 @@ OpFunctionEnd
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '3[%_runtimearr_2]' is not "
|
||||
"valid in WebGPU environment.\n %_runtimearr__runtimearr_2 = "
|
||||
"valid in WebGPU environments.\n %_runtimearr__runtimearr_2 = "
|
||||
"OpTypeRuntimeArray %_runtimearr_2\n"));
|
||||
}
|
||||
|
||||
@@ -2242,7 +2240,7 @@ OpFunctionEnd
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '4[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = "
|
||||
"valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = "
|
||||
"OpTypeRuntimeArray %_runtimearr_uint\n"));
|
||||
}
|
||||
|
||||
@@ -2304,7 +2302,7 @@ OpFunctionEnd
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '5[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = "
|
||||
"valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = "
|
||||
"OpTypeRuntimeArray %_runtimearr_uint\n"));
|
||||
}
|
||||
|
||||
@@ -2340,7 +2338,7 @@ OpFunctionEnd
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '5[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = "
|
||||
"valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = "
|
||||
"OpTypeRuntimeArray %_runtimearr_uint\n"));
|
||||
}
|
||||
|
||||
@@ -2370,7 +2368,7 @@ OpFunctionEnd
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpTypeArray Element Type <id> '5[%_runtimearr_4]' is not "
|
||||
"valid in Vulkan environment.\n %_arr__runtimearr_4_uint_1 = "
|
||||
"valid in Vulkan environments.\n %_arr__runtimearr_4_uint_1 = "
|
||||
"OpTypeArray %_runtimearr_4 %uint_1\n"));
|
||||
}
|
||||
|
||||
@@ -2402,7 +2400,7 @@ OpFunctionEnd
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpTypeArray Element Type <id> '5[%_runtimearr_4]' is not "
|
||||
"valid in WebGPU environment.\n %_arr__runtimearr_4_uint_1 = "
|
||||
"valid in WebGPU environments.\n %_arr__runtimearr_4_uint_1 = "
|
||||
"OpTypeArray %_runtimearr_4 %uint_1\n"));
|
||||
}
|
||||
|
||||
@@ -2436,7 +2434,7 @@ OpFunctionEnd
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '6[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = "
|
||||
"valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = "
|
||||
"OpTypeRuntimeArray %_runtimearr_uint\n"));
|
||||
}
|
||||
|
||||
@@ -2468,9 +2466,10 @@ OpFunctionEnd
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_arr__runtimearr_uint_uint_1 "
|
||||
"= OpTypeArray %_runtimearr_uint %uint_1\n"));
|
||||
HasSubstr(
|
||||
"OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environments.\n %_arr__runtimearr_uint_uint_1 "
|
||||
"= OpTypeArray %_runtimearr_uint %uint_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory,
|
||||
@@ -2504,9 +2503,10 @@ OpFunctionEnd
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_arr__runtimearr_uint_uint_1 "
|
||||
"= OpTypeArray %_runtimearr_uint %uint_1\n"));
|
||||
HasSubstr(
|
||||
"OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environments.\n %_arr__runtimearr_uint_uint_1 "
|
||||
"= OpTypeArray %_runtimearr_uint %uint_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAStructInsideRTAWithRuntimeDescriptorArrayGood) {
|
||||
|
||||
53
3rdparty/spirv-tools/tools/reduce/reduce.cpp
vendored
53
3rdparty/spirv-tools/tools/reduce/reduce.cpp
vendored
@@ -20,13 +20,13 @@
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/opt/log.h"
|
||||
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_dominating_id_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_undef_reduction_pass.h"
|
||||
#include "source/reduce/operand_to_const_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/reducer.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_pass.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
|
||||
#include "source/reduce/structured_loop_to_selection_reduction_pass.h"
|
||||
#include "source/reduce/remove_opname_instruction_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h"
|
||||
#include "source/spirv_reducer_options.h"
|
||||
#include "source/util/make_unique.h"
|
||||
#include "source/util/string_utils.h"
|
||||
@@ -77,7 +77,26 @@ USAGE: %s [options] <input> <interestingness-test>
|
||||
The SPIR-V binary is read from <input>.
|
||||
|
||||
Whether a binary is interesting is determined by <interestingness-test>, which
|
||||
is typically a script.
|
||||
should be the path to a script.
|
||||
|
||||
* The script must be executable.
|
||||
|
||||
* The script should take the path to a SPIR-V binary file (.spv) as its single
|
||||
argument, and exit with code 0 if and only if the binary file is
|
||||
interesting.
|
||||
|
||||
* Example: an interestingness test for reducing a SPIR-V binary file that
|
||||
causes tool "foo" to exit with error code 1 and print "Fatal error: bar" to
|
||||
standard error should:
|
||||
- invoke "foo" on the binary passed as the script argument;
|
||||
- capture the return code and standard error from "bar";
|
||||
- exit with code 0 if and only if the return code of "foo" was 1 and the
|
||||
standard error from "bar" contained "Fatal error: bar".
|
||||
|
||||
* The reducer does not place a time limit on how long the interestingness test
|
||||
takes to run, so it is advisable to use per-command timeouts inside the
|
||||
script when invoking SPIR-V-processing tools (such as "foo" in the above
|
||||
example).
|
||||
|
||||
NOTE: The reducer is a work in progress.
|
||||
|
||||
@@ -85,8 +104,8 @@ Options (in lexicographical order):
|
||||
-h, --help
|
||||
Print this help.
|
||||
--step-limit
|
||||
32-bit unsigned integer specifying maximum number of
|
||||
steps the reducer will take before giving up.
|
||||
32-bit unsigned integer specifying maximum number of steps the
|
||||
reducer will take before giving up.
|
||||
--version
|
||||
Display reducer version information.
|
||||
)",
|
||||
@@ -207,18 +226,20 @@ int main(int argc, const char** argv) {
|
||||
});
|
||||
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<RemoveOpNameInstructionReductionPass>(target_env));
|
||||
spvtools::MakeUnique<
|
||||
RemoveOpNameInstructionReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<OperandToUndefReductionPass>(target_env));
|
||||
spvtools::MakeUnique<OperandToUndefReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<OperandToConstReductionPass>(target_env));
|
||||
spvtools::MakeUnique<OperandToConstReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<OperandToDominatingIdReductionPass>(target_env));
|
||||
spvtools::MakeUnique<OperandToDominatingIdReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<RemoveUnreferencedInstructionReductionPass>(
|
||||
target_env));
|
||||
spvtools::MakeUnique<
|
||||
RemoveUnreferencedInstructionReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<StructuredLoopToSelectionReductionPass>(target_env));
|
||||
spvtools::MakeUnique<
|
||||
StructuredLoopToSelectionReductionOpportunityFinder>());
|
||||
|
||||
reducer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ project "spirv-opt"
|
||||
files {
|
||||
path.join(SPIRV_TOOLS, "source/opt/**.cpp"),
|
||||
path.join(SPIRV_TOOLS, "source/opt/**.h"),
|
||||
path.join(SPIRV_TOOLS, "source/reduce/**.cpp"),
|
||||
path.join(SPIRV_TOOLS, "source/reduce/**.h"),
|
||||
|
||||
-- libspirv
|
||||
path.join(SPIRV_TOOLS, "source/assembly_grammar.cpp"),
|
||||
|
||||
Reference in New Issue
Block a user