Updated spirv-tools.

This commit is contained in:
Бранимир Караџић
2019-06-16 17:46:04 -07:00
parent 26ad845d85
commit 896f9952f3
23 changed files with 1971 additions and 161 deletions

View File

@@ -1 +1 @@
"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-41-ga8ae579f"
"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-47-g59983a60"

View File

@@ -38,6 +38,8 @@ const char* ExtensionToString(Extension extension) {
return "SPV_GOOGLE_decorate_string";
case Extension::kSPV_GOOGLE_hlsl_functionality1:
return "SPV_GOOGLE_hlsl_functionality1";
case Extension::kSPV_GOOGLE_user_type:
return "SPV_GOOGLE_user_type";
case Extension::kSPV_INTEL_device_side_avc_motion_estimation:
return "SPV_INTEL_device_side_avc_motion_estimation";
case Extension::kSPV_INTEL_media_block_io:
@@ -111,8 +113,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_fragment_shader_interlock", "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_device_side_avc_motion_estimation", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "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_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, 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_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
static const char* known_ext_strs[] = { "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_physical_storage_buffer", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_media_block_io", "SPV_INTEL_shader_integer_functions2", "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_cooperative_matrix", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_image_footprint", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_VALIDATOR_ignore_type_decl_unique" };
static const Extension known_ext_ids[] = { Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_shader_integer_functions2, 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_cooperative_matrix, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique };
const auto b = std::begin(known_ext_strs);
const auto e = std::end(known_ext_strs);
const auto found = std::equal_range(
@@ -330,6 +332,16 @@ const char* CapabilityToString(SpvCapability capability) {
return "FragmentFullyCoveredEXT";
case SpvCapabilityMeshShadingNV:
return "MeshShadingNV";
case SpvCapabilityImageFootprintNV:
return "ImageFootprintNV";
case SpvCapabilityFragmentBarycentricNV:
return "FragmentBarycentricNV";
case SpvCapabilityComputeDerivativeGroupQuadsNV:
return "ComputeDerivativeGroupQuadsNV";
case SpvCapabilityFragmentDensityEXT:
return "FragmentDensityEXT";
case SpvCapabilityGroupNonUniformPartitionedNV:
return "GroupNonUniformPartitionedNV";
case SpvCapabilityShaderNonUniformEXT:
return "ShaderNonUniformEXT";
case SpvCapabilityRuntimeDescriptorArrayEXT:
@@ -356,6 +368,24 @@ const char* CapabilityToString(SpvCapability capability) {
return "StorageTexelBufferArrayNonUniformIndexingEXT";
case SpvCapabilityRayTracingNV:
return "RayTracingNV";
case SpvCapabilityVulkanMemoryModelKHR:
return "VulkanMemoryModelKHR";
case SpvCapabilityVulkanMemoryModelDeviceScopeKHR:
return "VulkanMemoryModelDeviceScopeKHR";
case SpvCapabilityPhysicalStorageBufferAddressesEXT:
return "PhysicalStorageBufferAddressesEXT";
case SpvCapabilityComputeDerivativeGroupLinearNV:
return "ComputeDerivativeGroupLinearNV";
case SpvCapabilityCooperativeMatrixNV:
return "CooperativeMatrixNV";
case SpvCapabilityFragmentShaderSampleInterlockEXT:
return "FragmentShaderSampleInterlockEXT";
case SpvCapabilityFragmentShaderShadingRateInterlockEXT:
return "FragmentShaderShadingRateInterlockEXT";
case SpvCapabilityShaderSMBuiltinsNV:
return "ShaderSMBuiltinsNV";
case SpvCapabilityFragmentShaderPixelInterlockEXT:
return "FragmentShaderPixelInterlockEXT";
case SpvCapabilitySubgroupShuffleINTEL:
return "SubgroupShuffleINTEL";
case SpvCapabilitySubgroupBufferBlockIOINTEL:
@@ -372,34 +402,6 @@ const char* CapabilityToString(SpvCapability capability) {
return "SubgroupAvcMotionEstimationIntraINTEL";
case SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL:
return "SubgroupAvcMotionEstimationChromaINTEL";
case SpvCapabilityGroupNonUniformPartitionedNV:
return "GroupNonUniformPartitionedNV";
case SpvCapabilityVulkanMemoryModelKHR:
return "VulkanMemoryModelKHR";
case SpvCapabilityVulkanMemoryModelDeviceScopeKHR:
return "VulkanMemoryModelDeviceScopeKHR";
case SpvCapabilityImageFootprintNV:
return "ImageFootprintNV";
case SpvCapabilityFragmentBarycentricNV:
return "FragmentBarycentricNV";
case SpvCapabilityComputeDerivativeGroupQuadsNV:
return "ComputeDerivativeGroupQuadsNV";
case SpvCapabilityComputeDerivativeGroupLinearNV:
return "ComputeDerivativeGroupLinearNV";
case SpvCapabilityFragmentDensityEXT:
return "FragmentDensityEXT";
case SpvCapabilityPhysicalStorageBufferAddressesEXT:
return "PhysicalStorageBufferAddressesEXT";
case SpvCapabilityCooperativeMatrixNV:
return "CooperativeMatrixNV";
case SpvCapabilityFragmentShaderSampleInterlockEXT:
return "FragmentShaderSampleInterlockEXT";
case SpvCapabilityFragmentShaderShadingRateInterlockEXT:
return "FragmentShaderShadingRateInterlockEXT";
case SpvCapabilityFragmentShaderPixelInterlockEXT:
return "FragmentShaderPixelInterlockEXT";
case SpvCapabilityShaderSMBuiltinsNV:
return "ShaderSMBuiltinsNV";
case SpvCapabilityMax:
assert(0 && "Attempting to convert SpvCapabilityMax to string");
return "";

View File

@@ -17,6 +17,7 @@ kSPV_EXT_shader_stencil_export,
kSPV_EXT_shader_viewport_index_layer,
kSPV_GOOGLE_decorate_string,
kSPV_GOOGLE_hlsl_functionality1,
kSPV_GOOGLE_user_type,
kSPV_INTEL_device_side_avc_motion_estimation,
kSPV_INTEL_media_block_io,
kSPV_INTEL_shader_integer_functions2,

View File

@@ -99,6 +99,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_EXT_shader_stencil_expo
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_EXT_shader_viewport_index_layerSPV_NV_viewport_array2[] = {spvtools::Extension::kSPV_EXT_shader_viewport_index_layer, spvtools::Extension::kSPV_NV_viewport_array2};
static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1};
static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_user_type[] = {spvtools::Extension::kSPV_GOOGLE_user_type};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_device_side_avc_motion_estimation[] = {spvtools::Extension::kSPV_INTEL_device_side_avc_motion_estimation};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_media_block_io[] = {spvtools::Extension::kSPV_INTEL_media_block_io};
static const spvtools::Extension pygen_variable_exts_SPV_INTEL_shader_integer_functions2[] = {spvtools::Extension::kSPV_INTEL_shader_integer_functions2};
@@ -145,10 +146,10 @@ static const spv_operand_desc_t pygen_variable_ImageOperandsEntries[] = {
{"ConstOffsets", 0x0020, 1, pygen_variable_caps_ImageGatherExtended, 0, nullptr, {SPV_OPERAND_TYPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Sample", 0x0040, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MinLod", 0x0080, 1, pygen_variable_caps_MinLod, 0, nullptr, {SPV_OPERAND_TYPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MakeTexelAvailableKHR", 0x0100, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MakeTexelVisibleKHR", 0x0200, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"NonPrivateTexelKHR", 0x0400, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"VolatileTexelKHR", 0x0800, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MakeTexelAvailableKHR", 0x0100, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, 0xffffffffu, 0xffffffffu},
{"MakeTexelVisibleKHR", 0x0200, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, 0xffffffffu, 0xffffffffu},
{"NonPrivateTexelKHR", 0x0400, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"VolatileTexelKHR", 0x0800, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"SignExtend", 0x1000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu},
{"ZeroExtend", 0x2000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu}
};
@@ -202,9 +203,10 @@ static const spv_operand_desc_t pygen_variable_MemorySemanticsEntries[] = {
{"CrossWorkgroupMemory", 0x0200, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"AtomicCounterMemory", 0x0400, 1, pygen_variable_caps_AtomicStorage, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"ImageMemory", 0x0800, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"OutputMemoryKHR", 0x1000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MakeAvailableKHR", 0x2000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MakeVisibleKHR", 0x4000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"OutputMemoryKHR", 0x1000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"MakeAvailableKHR", 0x2000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"MakeVisibleKHR", 0x4000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"Volatile", 0x8000, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_MemoryAccessEntries[] = {
@@ -212,9 +214,9 @@ static const spv_operand_desc_t pygen_variable_MemoryAccessEntries[] = {
{"Volatile", 0x0001, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Aligned", 0x0002, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Nontemporal", 0x0004, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MakePointerAvailableKHR", 0x0008, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MakePointerVisibleKHR", 0x0010, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"NonPrivatePointerKHR", 0x0020, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"MakePointerAvailableKHR", 0x0008, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, 0xffffffffu, 0xffffffffu},
{"MakePointerVisibleKHR", 0x0010, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {SPV_OPERAND_TYPE_SCOPE_ID}, 0xffffffffu, 0xffffffffu},
{"NonPrivatePointerKHR", 0x0020, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_KernelProfilingInfoEntries[] = {
@@ -239,28 +241,28 @@ static const spv_operand_desc_t pygen_variable_ExecutionModelEntries[] = {
{"Fragment", 4, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"GLCompute", 5, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Kernel", 6, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"TaskNV", 5267, 1, pygen_variable_caps_MeshShadingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MeshNV", 5268, 1, pygen_variable_caps_MeshShadingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"RayGenerationNV", 5313, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"IntersectionNV", 5314, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"AnyHitNV", 5315, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"ClosestHitNV", 5316, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"MissNV", 5317, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"CallableNV", 5318, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"TaskNV", 5267, 1, pygen_variable_caps_MeshShadingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"MeshNV", 5268, 1, pygen_variable_caps_MeshShadingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"RayGenerationNV", 5313, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"IntersectionNV", 5314, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"AnyHitNV", 5315, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"ClosestHitNV", 5316, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"MissNV", 5317, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
{"CallableNV", 5318, 1, pygen_variable_caps_RayTracingNV, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_AddressingModelEntries[] = {
{"Logical", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Physical32", 1, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Physical64", 2, 1, pygen_variable_caps_Addresses, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"PhysicalStorageBuffer64EXT", 5348, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"PhysicalStorageBuffer64EXT", 5348, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_MemoryModelEntries[] = {
{"Simple", 0, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"GLSL450", 1, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"OpenCL", 2, 1, pygen_variable_caps_Kernel, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"VulkanKHR", 3, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"VulkanKHR", 3, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = {
@@ -336,13 +338,13 @@ static const spv_operand_desc_t pygen_variable_StorageClassEntries[] = {
{"AtomicCounter", 10, 1, pygen_variable_caps_AtomicStorage, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Image", 11, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"StorageBuffer", 12, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_KHR_storage_buffer_storage_classSPV_KHR_variable_pointers, {}, SPV_SPIRV_VERSION_WORD(1,3), 0xffffffffu},
{"CallableDataNV", 5328, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"IncomingCallableDataNV", 5329, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"RayPayloadNV", 5338, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"HitAttributeNV", 5339, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"IncomingRayPayloadNV", 5342, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"ShaderRecordBufferNV", 5343, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"PhysicalStorageBufferEXT", 5349, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"CallableDataNV", 5328, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"IncomingCallableDataNV", 5329, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"RayPayloadNV", 5338, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"HitAttributeNV", 5339, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"IncomingRayPayloadNV", 5342, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"ShaderRecordBufferNV", 5343, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"PhysicalStorageBufferEXT", 5349, 1, pygen_variable_caps_PhysicalStorageBufferAddressesEXT, 1, pygen_variable_exts_SPV_EXT_physical_storage_buffer, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_DimEntries[] = {
@@ -548,7 +550,8 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
{"CounterBuffer", 5634, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_ID}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu},
{"HlslCounterBufferGOOGLE", 5634, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_ID}, 0xffffffffu, 0xffffffffu},
{"UserSemantic", 5635, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_LITERAL_STRING}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu},
{"HlslSemanticGOOGLE", 5635, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_LITERAL_STRING}, 0xffffffffu, 0xffffffffu}
{"HlslSemanticGOOGLE", 5635, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1, {SPV_OPERAND_TYPE_LITERAL_STRING}, 0xffffffffu, 0xffffffffu},
{"UserTypeGOOGLE", 5636, 0, nullptr, 1, pygen_variable_exts_SPV_GOOGLE_user_type, {SPV_OPERAND_TYPE_LITERAL_STRING}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = {
@@ -636,24 +639,24 @@ static const spv_operand_desc_t pygen_variable_BuiltInEntries[] = {
{"FragmentSizeNV", 5292, 2, pygen_variable_caps_ShadingRateNVFragmentDensityEXT, 2, pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate, {}, 0xffffffffu, 0xffffffffu},
{"FragInvocationCountEXT", 5293, 2, pygen_variable_caps_FragmentDensityEXTShadingRateNV, 2, pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate, {}, 0xffffffffu, 0xffffffffu},
{"InvocationsPerPixelNV", 5293, 2, pygen_variable_caps_ShadingRateNVFragmentDensityEXT, 2, pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate, {}, 0xffffffffu, 0xffffffffu},
{"LaunchIdNV", 5319, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"LaunchSizeNV", 5320, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"WorldRayOriginNV", 5321, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"WorldRayDirectionNV", 5322, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"ObjectRayOriginNV", 5323, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"ObjectRayDirectionNV", 5324, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"RayTminNV", 5325, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"RayTmaxNV", 5326, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"InstanceCustomIndexNV", 5327, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"ObjectToWorldNV", 5330, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"WorldToObjectNV", 5331, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"HitTNV", 5332, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"HitKindNV", 5333, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"IncomingRayFlagsNV", 5351, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"WarpsPerSMNV", 5374, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"SMCountNV", 5375, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"WarpIDNV", 5376, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"SMIDNV", 5377, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"LaunchIdNV", 5319, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"LaunchSizeNV", 5320, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"WorldRayOriginNV", 5321, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"WorldRayDirectionNV", 5322, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"ObjectRayOriginNV", 5323, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"ObjectRayDirectionNV", 5324, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"RayTminNV", 5325, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"RayTmaxNV", 5326, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"InstanceCustomIndexNV", 5327, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"ObjectToWorldNV", 5330, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"WorldToObjectNV", 5331, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"HitTNV", 5332, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"HitKindNV", 5333, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"IncomingRayFlagsNV", 5351, 1, pygen_variable_caps_RayTracingNV, 1, pygen_variable_exts_SPV_NV_ray_tracing, {}, 0xffffffffu, 0xffffffffu},
{"WarpsPerSMNV", 5374, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu},
{"SMCountNV", 5375, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu},
{"WarpIDNV", 5376, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu},
{"SMIDNV", 5377, 1, pygen_variable_caps_ShaderSMBuiltinsNV, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_ScopeEntries[] = {
@@ -662,7 +665,7 @@ static const spv_operand_desc_t pygen_variable_ScopeEntries[] = {
{"Workgroup", 2, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Subgroup", 3, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"Invocation", 4, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu},
{"QueueFamilyKHR", 5, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}
{"QueueFamilyKHR", 5, 1, pygen_variable_caps_VulkanMemoryModelKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
};
static const spv_operand_desc_t pygen_variable_GroupOperationEntries[] = {

View File

@@ -30,8 +30,8 @@ if(SPIRV_BUILD_FUZZER)
fuzzer.h
fuzzer_context.h
fuzzer_pass.h
fuzzer_pass_add_useful_constructs.h
fuzzer_pass_add_dead_breaks.h
fuzzer_pass_add_useful_constructs.h
fuzzer_pass_permute_blocks.h
fuzzer_pass_split_blocks.h
fuzzer_util.h
@@ -39,6 +39,7 @@ if(SPIRV_BUILD_FUZZER)
protobufs/spirvfuzz_protobufs.h
pseudo_random_generator.h
random_generator.h
replayer.h
transformation_add_constant_boolean.h
transformation_add_constant_scalar.h
transformation_add_dead_break.h
@@ -48,6 +49,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_move_block_down.h
transformation_replace_boolean_constant_with_constant_binary.h
transformation_split_block.h
uniform_buffer_element_descriptor.h
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h
fact_manager.cpp
@@ -62,6 +64,7 @@ if(SPIRV_BUILD_FUZZER)
id_use_descriptor.cpp
pseudo_random_generator.cpp
random_generator.cpp
replayer.cpp
transformation_add_constant_boolean.cpp
transformation_add_constant_scalar.cpp
transformation_add_dead_break.cpp
@@ -71,6 +74,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_move_block_down.cpp
transformation_replace_boolean_constant_with_constant_binary.cpp
transformation_split_block.cpp
uniform_buffer_element_descriptor.cpp
${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc
)

View File

@@ -12,15 +12,242 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <utility>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace fuzz {
FactManager::FactManager() = default;
// The purpose of this struct is to group the fields and data used to represent
// facts about uniform constants.
struct FactManager::ConstantUniformFacts {
// See method in FactManager which delegates to this method.
bool AddFact(const protobufs::FactConstantUniform& fact,
opt::IRContext* context);
// See method in FactManager which delegates to this method.
std::vector<uint32_t> GetConstantsAvailableFromUniformsForType(
opt::IRContext* ir_context, uint32_t type_id) const;
// See method in FactManager which delegates to this method.
const std::vector<protobufs::UniformBufferElementDescriptor>
GetUniformDescriptorsForConstant(opt::IRContext* ir_context,
uint32_t constant_id) const;
// See method in FactManager which delegates to this method.
uint32_t GetConstantFromUniformDescriptor(
opt::IRContext* context,
const protobufs::UniformBufferElementDescriptor& uniform_descriptor)
const;
// See method in FactManager which delegates to this method.
std::vector<uint32_t> GetTypesForWhichUniformValuesAreKnown() const;
// Returns true if and only if the words associated with
// |constant_instruction| exactly match the words for the constant associated
// with |constant_uniform_fact|.
bool DataMatches(
const opt::Instruction& constant_instruction,
const protobufs::FactConstantUniform& constant_uniform_fact) const;
// Yields the constant words associated with |constant_uniform_fact|.
std::vector<uint32_t> GetConstantWords(
const protobufs::FactConstantUniform& constant_uniform_fact) const;
// Yields the id of a constant of type |type_id| whose data matches the
// constant data in |constant_uniform_fact|, or 0 if no such constant is
// declared.
uint32_t GetConstantId(
opt::IRContext* context,
const protobufs::FactConstantUniform& constant_uniform_fact,
uint32_t type_id) const;
std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>
facts_and_type_ids;
};
uint32_t FactManager::ConstantUniformFacts::GetConstantId(
opt::IRContext* context,
const protobufs::FactConstantUniform& constant_uniform_fact,
uint32_t type_id) const {
auto type = context->get_type_mgr()->GetType(type_id);
assert(type != nullptr && "Unknown type id.");
auto constant = context->get_constant_mgr()->GetConstant(
type, GetConstantWords(constant_uniform_fact));
return context->get_constant_mgr()->FindDeclaredConstant(constant, type_id);
}
std::vector<uint32_t> FactManager::ConstantUniformFacts::GetConstantWords(
const protobufs::FactConstantUniform& constant_uniform_fact) const {
std::vector<uint32_t> result;
for (auto constant_word : constant_uniform_fact.constant_word()) {
result.push_back(constant_word);
}
return result;
}
bool FactManager::ConstantUniformFacts::DataMatches(
const opt::Instruction& constant_instruction,
const protobufs::FactConstantUniform& constant_uniform_fact) const {
assert(constant_instruction.opcode() == SpvOpConstant);
std::vector<uint32_t> data_in_constant;
for (uint32_t i = 0; i < constant_instruction.NumInOperands(); i++) {
data_in_constant.push_back(constant_instruction.GetSingleWordInOperand(i));
}
return data_in_constant == GetConstantWords(constant_uniform_fact);
}
std::vector<uint32_t>
FactManager::ConstantUniformFacts::GetConstantsAvailableFromUniformsForType(
opt::IRContext* ir_context, uint32_t type_id) const {
std::vector<uint32_t> result;
std::set<uint32_t> already_seen;
for (auto& fact_and_type_id : facts_and_type_ids) {
if (fact_and_type_id.second != type_id) {
continue;
}
if (auto constant_id =
GetConstantId(ir_context, fact_and_type_id.first, type_id)) {
if (already_seen.find(constant_id) == already_seen.end()) {
result.push_back(constant_id);
already_seen.insert(constant_id);
}
}
}
return result;
}
const std::vector<protobufs::UniformBufferElementDescriptor>
FactManager::ConstantUniformFacts::GetUniformDescriptorsForConstant(
opt::IRContext* ir_context, uint32_t constant_id) const {
std::vector<protobufs::UniformBufferElementDescriptor> result;
auto constant_inst = ir_context->get_def_use_mgr()->GetDef(constant_id);
assert(constant_inst->opcode() == SpvOpConstant &&
"The given id must be that of a constant");
auto type_id = constant_inst->type_id();
for (auto& fact_and_type_id : facts_and_type_ids) {
if (fact_and_type_id.second != type_id) {
continue;
}
if (DataMatches(*constant_inst, fact_and_type_id.first)) {
result.emplace_back(
fact_and_type_id.first.uniform_buffer_element_descriptor());
}
}
return result;
}
uint32_t FactManager::ConstantUniformFacts::GetConstantFromUniformDescriptor(
opt::IRContext* context,
const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
// Consider each fact.
for (auto& fact_and_type : facts_and_type_ids) {
// Check whether the uniform descriptor associated with the fact matches
// |uniform_descriptor|.
if (UniformBufferElementDescriptorEquals()(
&uniform_descriptor,
&fact_and_type.first.uniform_buffer_element_descriptor())) {
return GetConstantId(context, fact_and_type.first, fact_and_type.second);
}
}
// No fact associated with the given uniform descriptor was found.
return 0;
}
std::vector<uint32_t>
FactManager::ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown()
const {
std::vector<uint32_t> result;
for (auto& fact_and_type : facts_and_type_ids) {
if (std::find(result.begin(), result.end(), fact_and_type.second) ==
result.end()) {
result.push_back(fact_and_type.second);
}
}
return result;
}
bool FactManager::ConstantUniformFacts::AddFact(
const protobufs::FactConstantUniform& fact, opt::IRContext* context) {
auto should_be_uniform_variable = context->get_def_use_mgr()->GetDef(
fact.uniform_buffer_element_descriptor().uniform_variable_id());
if (!should_be_uniform_variable) {
return false;
}
if (SpvOpVariable != should_be_uniform_variable->opcode()) {
return false;
}
if (SpvStorageClassUniform !=
should_be_uniform_variable->GetSingleWordInOperand(0)) {
return false;
}
auto should_be_uniform_pointer_type =
context->get_type_mgr()->GetType(should_be_uniform_variable->type_id());
if (!should_be_uniform_pointer_type->AsPointer()) {
return false;
}
if (should_be_uniform_pointer_type->AsPointer()->storage_class() !=
SpvStorageClassUniform) {
return false;
}
auto should_be_uniform_pointer_instruction =
context->get_def_use_mgr()->GetDef(should_be_uniform_variable->type_id());
auto element_type =
should_be_uniform_pointer_instruction->GetSingleWordInOperand(1);
for (auto index : fact.uniform_buffer_element_descriptor().index()) {
auto should_be_composite_type =
context->get_def_use_mgr()->GetDef(element_type);
if (SpvOpTypeStruct == should_be_composite_type->opcode()) {
if (index >= should_be_composite_type->NumInOperands()) {
return false;
}
element_type = should_be_composite_type->GetSingleWordInOperand(index);
} else if (SpvOpTypeArray == should_be_composite_type->opcode()) {
auto array_length_constant =
context->get_constant_mgr()
->GetConstantFromInst(context->get_def_use_mgr()->GetDef(
should_be_composite_type->GetSingleWordInOperand(1)))
->AsIntConstant();
if (array_length_constant->words().size() != 1) {
return false;
}
auto array_length = array_length_constant->GetU32();
if (index >= array_length) {
return false;
}
element_type = should_be_composite_type->GetSingleWordInOperand(0);
} else if (SpvOpTypeVector == should_be_composite_type->opcode()) {
auto vector_length = should_be_composite_type->GetSingleWordInOperand(1);
if (index >= vector_length) {
return false;
}
element_type = should_be_composite_type->GetSingleWordInOperand(0);
} else {
return false;
}
}
auto final_element_type = context->get_type_mgr()->GetType(element_type);
if (!(final_element_type->AsFloat() || final_element_type->AsInteger())) {
return false;
}
auto width = final_element_type->AsFloat()
? final_element_type->AsFloat()->width()
: final_element_type->AsInteger()->width();
auto required_words = (width + 32 - 1) / 32;
if (static_cast<uint32_t>(fact.constant_word().size()) != required_words) {
return false;
}
facts_and_type_ids.emplace_back(
std::pair<protobufs::FactConstantUniform, uint32_t>(fact, element_type));
return true;
}
FactManager::FactManager() {
uniform_constant_facts_ = MakeUnique<ConstantUniformFacts>();
}
FactManager::~FactManager() = default;
@@ -36,11 +263,46 @@ bool FactManager::AddFacts(const protobufs::FactSequence& initial_facts,
return true;
}
bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact&,
spvtools::opt::IRContext*) {
assert(0 && "No facts are yet supported.");
bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact& fact,
spvtools::opt::IRContext* context) {
assert(fact.fact_case() == protobufs::Fact::kConstantUniformFact &&
"Right now this is the only fact.");
if (!uniform_constant_facts_->AddFact(fact.constant_uniform_fact(),
context)) {
return false;
}
return true;
}
std::vector<uint32_t> FactManager::GetConstantsAvailableFromUniformsForType(
opt::IRContext* ir_context, uint32_t type_id) const {
return uniform_constant_facts_->GetConstantsAvailableFromUniformsForType(
ir_context, type_id);
}
const std::vector<protobufs::UniformBufferElementDescriptor>
FactManager::GetUniformDescriptorsForConstant(opt::IRContext* ir_context,
uint32_t constant_id) const {
return uniform_constant_facts_->GetUniformDescriptorsForConstant(ir_context,
constant_id);
}
uint32_t FactManager::GetConstantFromUniformDescriptor(
opt::IRContext* context,
const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
return uniform_constant_facts_->GetConstantFromUniformDescriptor(
context, uniform_descriptor);
}
std::vector<uint32_t> FactManager::GetTypesForWhichUniformValuesAreKnown()
const {
return uniform_constant_facts_->GetTypesForWhichUniformValuesAreKnown();
}
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
FactManager::GetConstantUniformFactsAndTypes() const {
return uniform_constant_facts_->facts_and_type_ids;
}
} // namespace fuzz
} // namespace spvtools

View File

@@ -15,7 +15,9 @@
#ifndef SOURCE_FUZZ_FACT_MANAGER_H_
#define SOURCE_FUZZ_FACT_MANAGER_H_
#include <memory>
#include <utility>
#include <vector>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/opt/constants.h"
@@ -45,6 +47,60 @@ class FactManager {
// Adds |fact| to the fact manager, checking it for validity with respect to
// |context|. Returns true if and only if the fact is valid.
bool AddFact(const protobufs::Fact& fact, opt::IRContext* context);
// The fact manager will ultimately be responsible for managing a few distinct
// categories of facts. In principle there could be different fact managers
// for each kind of fact, but in practice providing one 'go to' place for
// facts will be convenient. To keep some separation, the public methods of
// the fact manager should be grouped according to the kind of fact to which
// they relate. At present we only have one kind of fact: facts about
// uniform variables.
//==============================
// Querying facts about uniform constants
// Provides the distinct type ids for which at least one "constant ==
// uniform element" fact is known.
std::vector<uint32_t> GetTypesForWhichUniformValuesAreKnown() const;
// Provides distinct constant ids with type |type_id| for which at least one
// "constant == uniform element" fact is known. If multiple identically-
// valued constants are relevant, only one will appear in the sequence.
std::vector<uint32_t> GetConstantsAvailableFromUniformsForType(
opt::IRContext* ir_context, uint32_t type_id) const;
// Provides details of all uniform elements that are known to be equal to the
// constant associated with |constant_id| in |ir_context|.
const std::vector<protobufs::UniformBufferElementDescriptor>
GetUniformDescriptorsForConstant(opt::IRContext* ir_context,
uint32_t constant_id) const;
// Returns the id of a constant whose value is known to match that of
// |uniform_descriptor|, and whose type matches the type of the uniform
// element. If multiple such constant is exist, the one that is returned
// is arbitrary. Returns 0 if no such constant id exists.
uint32_t GetConstantFromUniformDescriptor(
opt::IRContext* context,
const protobufs::UniformBufferElementDescriptor& uniform_descriptor)
const;
// Returns all "constant == uniform element" facts known to the fact
// manager, pairing each fact with id of the type that is associated with
// both the constant and the uniform element.
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
GetConstantUniformFactsAndTypes() const;
// End of uniform constant facts
//==============================
private:
// For each distinct kind of fact to be managed, we use a separate opaque
// struct type.
struct ConstantUniformFacts; // Opaque struct for holding data about uniform
// buffer elements.
std::unique_ptr<ConstantUniformFacts>
uniform_constant_facts_; // Unique pointer to internal data.
};
} // namespace fuzz

View File

@@ -57,12 +57,63 @@ message IdUseDescriptor {
}
message UniformBufferElementDescriptor {
// Represents a data element inside a uniform buffer. The element is
// specified via (a) the result id of a uniform variable in which the element
// is contained, and (b) a series of indices that need to be followed to get
// to the element (via fields and array/vector indices).
//
// Example: suppose %42 is the id of a uniform variable, and that the uniform
// variable has the following type (using GLSL-like syntax):
//
// struct S {
// float f;
// vec3 g;
// int4 h[10];
// };
//
// Then:
// - 42[0] describes the 'f' field.
// - 42[1,1] describes the y component of the 'g' field.
// - 42[2,7,3] describes the w component of element 7 of the 'h' field
// The result id of a uniform variable.
uint32 uniform_variable_id = 1;
// An ordered sequence of indices through composite structures in the
// uniform buffer.
repeated uint32 index = 2;
}
message FactSequence {
repeated Fact fact = 1;
}
message Fact {
// Currently there are no facts.
oneof fact {
// Order the fact options by numeric id (rather than alphabetically).
FactConstantUniform constant_uniform_fact = 1;
}
}
// Keep fact message types in alphabetical order:
message FactConstantUniform {
// Records the fact that a uniform buffer element is guaranteed to be equal
// to a particular constant value. spirv-fuzz can use such guarantees to
// obfuscate code, e.g. to manufacture an expression that will (due to the
// guarantee) evaluate to a particular value at runtime but in a manner that
// cannot be predicted at compile-time.
// An element of a uniform buffer
UniformBufferElementDescriptor uniform_buffer_element_descriptor = 1;
// The words of the associated constant
repeated uint32 constant_word = 2;
}
message TransformationSequence {

View File

@@ -0,0 +1,200 @@
// 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 "source/fuzz/replayer.h"
#include <utility>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation_add_constant_boolean.h"
#include "source/fuzz/transformation_add_constant_scalar.h"
#include "source/fuzz/transformation_add_dead_break.h"
#include "source/fuzz/transformation_add_type_boolean.h"
#include "source/fuzz/transformation_add_type_float.h"
#include "source/fuzz/transformation_add_type_int.h"
#include "source/fuzz/transformation_move_block_down.h"
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
#include "source/fuzz/transformation_split_block.h"
#include "source/opt/build_module.h"
#include "source/util/make_unique.h"
namespace spvtools {
namespace fuzz {
namespace {
// Returns true if and only if the precondition for |transformation| holds, with
// respect to the given |context| and |fact_manager|.
bool IsApplicable(const protobufs::Transformation& transformation,
opt::IRContext* context, const FactManager& fact_manager) {
switch (transformation.transformation_case()) {
case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
return transformation::IsApplicable(transformation.add_constant_boolean(),
context, fact_manager);
case protobufs::Transformation::TransformationCase::kAddConstantScalar:
return transformation::IsApplicable(transformation.add_constant_scalar(),
context, fact_manager);
case protobufs::Transformation::TransformationCase::kAddDeadBreak:
return transformation::IsApplicable(transformation.add_dead_break(),
context, fact_manager);
case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
return transformation::IsApplicable(transformation.add_type_boolean(),
context, fact_manager);
case protobufs::Transformation::TransformationCase::kAddTypeFloat:
return transformation::IsApplicable(transformation.add_type_float(),
context, fact_manager);
case protobufs::Transformation::TransformationCase::kAddTypeInt:
return transformation::IsApplicable(transformation.add_type_int(),
context, fact_manager);
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
return transformation::IsApplicable(transformation.move_block_down(),
context, fact_manager);
case protobufs::Transformation::TransformationCase::
kReplaceBooleanConstantWithConstantBinary:
return transformation::IsApplicable(
transformation.replace_boolean_constant_with_constant_binary(),
context, fact_manager);
case protobufs::Transformation::TransformationCase::kSplitBlock:
return transformation::IsApplicable(transformation.split_block(), context,
fact_manager);
default:
assert(transformation.transformation_case() ==
protobufs::Transformation::TRANSFORMATION_NOT_SET &&
"Unhandled transformation type.");
assert(false && "An unset transformation was encountered.");
return false;
}
}
// Requires that IsApplicable holds. Applies |transformation| to the given
// |context| and |fact_manager|.
void Apply(const protobufs::Transformation& transformation,
opt::IRContext* context, FactManager* fact_manager) {
switch (transformation.transformation_case()) {
case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
transformation::Apply(transformation.add_constant_boolean(), context,
fact_manager);
break;
case protobufs::Transformation::TransformationCase::kAddConstantScalar:
transformation::Apply(transformation.add_constant_scalar(), context,
fact_manager);
break;
case protobufs::Transformation::TransformationCase::kAddDeadBreak:
transformation::Apply(transformation.add_dead_break(), context,
fact_manager);
break;
case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
transformation::Apply(transformation.add_type_boolean(), context,
fact_manager);
break;
case protobufs::Transformation::TransformationCase::kAddTypeFloat:
transformation::Apply(transformation.add_type_float(), context,
fact_manager);
break;
case protobufs::Transformation::TransformationCase::kAddTypeInt:
transformation::Apply(transformation.add_type_int(), context,
fact_manager);
break;
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
transformation::Apply(transformation.move_block_down(), context,
fact_manager);
break;
case protobufs::Transformation::TransformationCase::
kReplaceBooleanConstantWithConstantBinary:
transformation::Apply(
transformation.replace_boolean_constant_with_constant_binary(),
context, fact_manager);
break;
case protobufs::Transformation::TransformationCase::kSplitBlock:
transformation::Apply(transformation.split_block(), context,
fact_manager);
break;
default:
assert(transformation.transformation_case() ==
protobufs::Transformation::TRANSFORMATION_NOT_SET &&
"Unhandled transformation type.");
assert(false && "An unset transformation was encountered.");
}
}
} // namespace
struct Replayer::Impl {
explicit Impl(spv_target_env env) : target_env(env) {}
const spv_target_env target_env; // Target environment.
MessageConsumer consumer; // Message consumer.
};
Replayer::Replayer(spv_target_env env) : impl_(MakeUnique<Impl>(env)) {}
Replayer::~Replayer() = default;
void Replayer::SetMessageConsumer(MessageConsumer c) {
impl_->consumer = std::move(c);
}
Replayer::ReplayerResultStatus Replayer::Run(
const std::vector<uint32_t>& binary_in,
const protobufs::FactSequence& initial_facts,
const protobufs::TransformationSequence& transformation_sequence_in,
std::vector<uint32_t>* binary_out,
protobufs::TransformationSequence* transformation_sequence_out) const {
// Check compatibility between the library version being linked with and the
// header files being used.
GOOGLE_PROTOBUF_VERIFY_VERSION;
spvtools::SpirvTools tools(impl_->target_env);
if (!tools.IsValid()) {
impl_->consumer(SPV_MSG_ERROR, nullptr, {},
"Failed to create SPIRV-Tools interface; stopping.");
return Replayer::ReplayerResultStatus::kFailedToCreateSpirvToolsInterface;
}
// Initial binary should be valid.
if (!tools.Validate(&binary_in[0], binary_in.size())) {
impl_->consumer(SPV_MSG_INFO, nullptr, {},
"Initial binary is invalid; stopping.");
return Replayer::ReplayerResultStatus::kInitialBinaryInvalid;
}
// Build the module from the input binary.
std::unique_ptr<opt::IRContext> ir_context = BuildModule(
impl_->target_env, impl_->consumer, binary_in.data(), binary_in.size());
assert(ir_context);
FactManager fact_manager;
if (!fact_manager.AddFacts(initial_facts, ir_context.get())) {
return Replayer::ReplayerResultStatus::kInitialFactsInvalid;
}
// Consider the transformation proto messages in turn.
for (auto& transformation : transformation_sequence_in.transformation()) {
// Check whether the transformation can be applied.
if (IsApplicable(transformation, ir_context.get(), fact_manager)) {
// The transformation is applicable, so apply it, and copy it to the
// sequence of transformations that were applied.
Apply(transformation, ir_context.get(), &fact_manager);
*transformation_sequence_out->add_transformation() = transformation;
}
}
// Write out the module as a binary.
ir_context->module()->ToBinary(binary_out, false);
return Replayer::ReplayerResultStatus::kComplete;
}
} // namespace fuzz
} // namespace spvtools

View File

@@ -0,0 +1,74 @@
// 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_FUZZ_REPLAYER_H_
#define SOURCE_FUZZ_REPLAYER_H_
#include <memory>
#include <vector>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
namespace fuzz {
// Transforms a SPIR-V module into a semantically equivalent SPIR-V module by
// applying a series of pre-defined transformations.
class Replayer {
public:
// Possible statuses that can result from running the replayer.
enum ReplayerResultStatus {
kComplete,
kFailedToCreateSpirvToolsInterface,
kInitialBinaryInvalid,
kInitialFactsInvalid,
};
// Constructs a replayer from the given target environment.
explicit Replayer(spv_target_env env);
// Disables copy/move constructor/assignment operations.
Replayer(const Replayer&) = delete;
Replayer(Replayer&&) = delete;
Replayer& operator=(const Replayer&) = delete;
Replayer& operator=(Replayer&&) = delete;
~Replayer();
// Sets the message consumer to the given |consumer|. The |consumer| will be
// invoked once for each message communicated from the library.
void SetMessageConsumer(MessageConsumer consumer);
// Transforms |binary_in| to |binary_out| by attempting to apply the
// transformations from |transformation_sequence_in|. Initial facts about the
// input binary and the context in which it will execute are provided via
// |initial_facts|. The transformations that were successfully applied are
// returned via |transformation_sequence_out|.
ReplayerResultStatus Run(
const std::vector<uint32_t>& binary_in,
const protobufs::FactSequence& initial_facts,
const protobufs::TransformationSequence& transformation_sequence_in,
std::vector<uint32_t>* binary_out,
protobufs::TransformationSequence* transformation_sequence_out) const;
private:
struct Impl; // Opaque struct for holding internal data.
std::unique_ptr<Impl> impl_; // Unique pointer to internal data.
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_REPLAYER_H_

View File

@@ -0,0 +1,39 @@
// 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 "source/fuzz/uniform_buffer_element_descriptor.h"
namespace spvtools {
namespace fuzz {
protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor(
uint32_t uniform_variable_id, std::vector<uint32_t>&& indices) {
protobufs::UniformBufferElementDescriptor result;
result.set_uniform_variable_id(uniform_variable_id);
for (auto index : indices) {
result.add_index(index);
}
return result;
}
bool UniformBufferElementDescriptorEquals::operator()(
const protobufs::UniformBufferElementDescriptor* first,
const protobufs::UniformBufferElementDescriptor* second) const {
return first->uniform_variable_id() == second->uniform_variable_id() &&
std::equal(first->index().begin(), first->index().end(),
second->index().begin());
}
} // namespace fuzz
} // namespace spvtools

View File

@@ -0,0 +1,41 @@
// 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_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_
#define SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_
#include <algorithm>
#include <vector>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
namespace spvtools {
namespace fuzz {
// Factory method to create a uniform buffer element descriptor message from an
// id and list of indices.
protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor(
uint32_t uniform_variable_id, std::vector<uint32_t>&& indices);
// Equality function for uniform buffer element descriptors.
struct UniformBufferElementDescriptorEquals {
bool operator()(
const protobufs::UniformBufferElementDescriptor* first,
const protobufs::UniformBufferElementDescriptor* second) const;
};
} // namespace fuzz
} // namespace spvtools
#endif // #define SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_

View File

@@ -54,18 +54,19 @@
// Logs an error message to the consumer saying the given feature is
// unimplemented.
#define SPIRV_UNIMPLEMENTED(consumer, feature) \
do { \
spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{__LINE__, 0, 0}, "unimplemented: " feature); \
#define SPIRV_UNIMPLEMENTED(consumer, feature) \
do { \
spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{static_cast<size_t>(__LINE__), 0, 0}, \
"unimplemented: " feature); \
} while (0)
// Logs an error message to the consumer saying the code location
// should be unreachable.
#define SPIRV_UNREACHABLE(consumer) \
do { \
spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{__LINE__, 0, 0}, "unreachable"); \
#define SPIRV_UNREACHABLE(consumer) \
do { \
spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{static_cast<size_t>(__LINE__), 0, 0}, "unreachable"); \
} while (0)
// Helper macros for concatenating arguments.
@@ -154,32 +155,34 @@ inline void Errorf(const MessageConsumer& consumer, const char* source,
PP_EXPAND(SPIRV_CONCATENATE(SPIRV_DEBUG_, PP_NARGS(__VA_ARGS__))( \
consumer, __VA_ARGS__))
#define SPIRV_ASSERT_1(consumer, condition) \
do { \
if (!(condition)) { \
spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{__LINE__, 0, 0}, "assertion failed: " #condition); \
std::exit(EXIT_FAILURE); \
} \
#define SPIRV_ASSERT_1(consumer, condition) \
do { \
if (!(condition)) { \
spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{static_cast<size_t>(__LINE__), 0, 0}, \
"assertion failed: " #condition); \
std::exit(EXIT_FAILURE); \
} \
} while (0)
#define SPIRV_ASSERT_2(consumer, condition, message) \
do { \
if (!(condition)) { \
spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{__LINE__, 0, 0}, "assertion failed: " message); \
std::exit(EXIT_FAILURE); \
} \
#define SPIRV_ASSERT_2(consumer, condition, message) \
do { \
if (!(condition)) { \
spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{static_cast<size_t>(__LINE__), 0, 0}, \
"assertion failed: " message); \
std::exit(EXIT_FAILURE); \
} \
} while (0)
#define SPIRV_ASSERT_more(consumer, condition, format, ...) \
do { \
if (!(condition)) { \
spvtools::Logf(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{__LINE__, 0, 0}, "assertion failed: " format, \
__VA_ARGS__); \
std::exit(EXIT_FAILURE); \
} \
#define SPIRV_ASSERT_more(consumer, condition, format, ...) \
do { \
if (!(condition)) { \
spvtools::Logf(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \
{static_cast<size_t>(__LINE__), 0, 0}, \
"assertion failed: " format, __VA_ARGS__); \
std::exit(EXIT_FAILURE); \
} \
} while (0)
#define SPIRV_ASSERT_3(consumer, condition, format, ...) \
@@ -191,16 +194,17 @@ inline void Errorf(const MessageConsumer& consumer, const char* source,
#define SPIRV_ASSERT_5(consumer, condition, format, ...) \
SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__)
#define SPIRV_DEBUG_1(consumer, message) \
do { \
spvtools::Log(consumer, SPV_MSG_DEBUG, __FILE__, {__LINE__, 0, 0}, \
message); \
#define SPIRV_DEBUG_1(consumer, message) \
do { \
spvtools::Log(consumer, SPV_MSG_DEBUG, __FILE__, \
{static_cast<size_t>(__LINE__), 0, 0}, message); \
} while (0)
#define SPIRV_DEBUG_more(consumer, format, ...) \
do { \
spvtools::Logf(consumer, SPV_MSG_DEBUG, __FILE__, {__LINE__, 0, 0}, \
format, __VA_ARGS__); \
#define SPIRV_DEBUG_more(consumer, format, ...) \
do { \
spvtools::Logf(consumer, SPV_MSG_DEBUG, __FILE__, \
{static_cast<size_t>(__LINE__), 0, 0}, format, \
__VA_ARGS__); \
} while (0)
#define SPIRV_DEBUG_2(consumer, format, ...) \

View File

@@ -211,6 +211,17 @@ class BuiltInsValidator {
spv_result_t ValidateSMBuiltinsAtDefinition(const Decoration& decoration,
const Instruction& inst);
// Used for SubgroupEqMask, SubgroupGeMask, SubgroupGtMask, SubgroupLtMask,
// SubgroupLeMask.
spv_result_t ValidateI32Vec4InputAtDefinition(const Decoration& decoration,
const Instruction& inst);
// Used for SubgroupLocalInvocationId, SubgroupSize.
spv_result_t ValidateI32InputAtDefinition(const Decoration& decoration,
const Instruction& inst);
// Used for SubgroupId, NumSubgroups.
spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration,
const Instruction& inst);
// The following section contains functions which are called when id defined
// by |referenced_inst| is
// 1. referenced by |referenced_from_inst|
@@ -333,6 +344,11 @@ class BuiltInsValidator {
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
// Used for SubgroupId and NumSubgroups.
spv_result_t ValidateComputeI32InputAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
spv_result_t ValidateSMBuiltinsAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
@@ -2603,6 +2619,171 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " cannot be used as a member decoration ";
}
if (spv_result_t error = ValidateI32(
decoration, inst,
[this, &decoration,
&inst](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 32-bit int "
"vector. "
<< message;
})) {
return error;
}
}
// Seed at reference checks with this built-in.
return ValidateComputeI32InputAtReference(decoration, inst, inst, inst);
}
spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
<< " " << GetStorageClassDesc(referenced_from_inst);
}
for (const SpvExecutionModel execution_model : execution_models_) {
bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute ||
execution_model == SpvExecutionModelTaskNV ||
execution_model == SpvExecutionModelMeshNV;
if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be used only with GLCompute execution model. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
}
}
}
if (function_id_ == 0) {
// Propagate this rule to all dependant ids in the global scope.
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
std::bind(&BuiltInsValidator::ValidateComputeI32InputAtReference, this,
decoration, built_in_inst, referenced_from_inst,
std::placeholders::_1));
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " cannot be used as a member decoration ";
}
if (spv_result_t error = ValidateI32(
decoration, inst,
[this, &decoration,
&inst](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 32-bit int. " << message;
})) {
return error;
}
const SpvStorageClass storage_class = GetStorageClass(inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, inst, inst, inst) << " "
<< GetStorageClassDesc(inst);
}
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " cannot be used as a member decoration ";
}
if (spv_result_t error = ValidateI32Vec(
decoration, inst, 4,
[this, &decoration,
&inst](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 4-component 32-bit int "
"vector. "
<< message;
})) {
return error;
}
const SpvStorageClass storage_class = GetStorageClass(inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, inst, inst, inst) << " "
<< GetStorageClassDesc(inst);
}
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
@@ -2788,6 +2969,21 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case SpvBuiltInSamplePosition: {
return ValidateSamplePositionAtDefinition(decoration, inst);
}
case SpvBuiltInSubgroupId:
case SpvBuiltInNumSubgroups: {
return ValidateComputeI32InputAtDefinition(decoration, inst);
}
case SpvBuiltInSubgroupLocalInvocationId:
case SpvBuiltInSubgroupSize: {
return ValidateI32InputAtDefinition(decoration, inst);
}
case SpvBuiltInSubgroupEqMask:
case SpvBuiltInSubgroupGeMask:
case SpvBuiltInSubgroupGtMask:
case SpvBuiltInSubgroupLeMask:
case SpvBuiltInSubgroupLtMask: {
return ValidateI32Vec4InputAtDefinition(decoration, inst);
}
case SpvBuiltInTessCoord: {
return ValidateTessCoordAtDefinition(decoration, inst);
}
@@ -2821,17 +3017,8 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case SpvBuiltInEnqueuedWorkgroupSize:
case SpvBuiltInGlobalOffset:
case SpvBuiltInGlobalLinearId:
case SpvBuiltInSubgroupSize:
case SpvBuiltInSubgroupMaxSize:
case SpvBuiltInNumSubgroups:
case SpvBuiltInNumEnqueuedSubgroups:
case SpvBuiltInSubgroupId:
case SpvBuiltInSubgroupLocalInvocationId:
case SpvBuiltInSubgroupEqMaskKHR:
case SpvBuiltInSubgroupGeMaskKHR:
case SpvBuiltInSubgroupGtMaskKHR:
case SpvBuiltInSubgroupLeMaskKHR:
case SpvBuiltInSubgroupLtMaskKHR:
case SpvBuiltInBaseVertex:
case SpvBuiltInBaseInstance:
case SpvBuiltInDrawIndex:

View File

@@ -422,6 +422,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
<< "OpVariable Initializer <id> '" << _.getIdName(initializer_id)
<< "' is not a constant or module-scope variable.";
}
if (initializer->type_id() != result_type->GetOperandAs<uint32_t>(2u)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Initializer type must match the type pointed to by the Result "
"Type";
}
}
const auto storage_class =

View File

@@ -17,7 +17,8 @@ if (${SPIRV_BUILD_FUZZER})
set(SOURCES
fuzz_test_util.h
fuzzer_test.cpp
fuzzer_replayer_test.cpp
fact_manager_test.cpp
fuzz_test_util.cpp
transformation_add_constant_boolean_test.cpp
transformation_add_constant_scalar_test.cpp

View File

@@ -0,0 +1,534 @@
// 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 "source/fuzz/fact_manager.h"
#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
using opt::analysis::BoolConstant;
using opt::analysis::FloatConstant;
using opt::analysis::IntConstant;
using opt::analysis::ScalarConstant;
using opt::analysis::Bool;
using opt::analysis::Float;
using opt::analysis::Integer;
using opt::analysis::Type;
bool AddFactHelper(
FactManager* fact_manager, opt::IRContext* context,
std::vector<uint32_t>&& words,
const protobufs::UniformBufferElementDescriptor& descriptor) {
protobufs::FactConstantUniform constant_uniform_fact;
for (auto word : words) {
constant_uniform_fact.add_constant_word(word);
}
*constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
descriptor;
protobufs::Fact fact;
*fact.mutable_constant_uniform_fact() = constant_uniform_fact;
return fact_manager->AddFact(fact, context);
}
TEST(FactManagerTest, ConstantsAvailableViaUniforms) {
std::string shader = R"(
OpCapability Shader
OpCapability Int64
OpCapability Float64
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%10 = OpTypeInt 32 0
%11 = OpTypeInt 32 1
%12 = OpTypeInt 64 0
%13 = OpTypeInt 64 1
%15 = OpTypeFloat 32
%16 = OpTypeFloat 64
%17 = OpConstant %11 5
%18 = OpConstant %11 20
%19 = OpTypeVector %10 4
%20 = OpConstant %11 6
%21 = OpTypeVector %12 4
%22 = OpConstant %11 10
%23 = OpTypeVector %11 4
%102 = OpTypeStruct %10 %10 %23
%101 = OpTypePointer Uniform %102
%100 = OpVariable %101 Uniform
%203 = OpTypeArray %23 %17
%202 = OpTypeArray %203 %18
%201 = OpTypePointer Uniform %202
%200 = OpVariable %201 Uniform
%305 = OpTypeStruct %16 %16 %16 %11 %16
%304 = OpTypeStruct %16 %16 %305
%303 = OpTypeStruct %304
%302 = OpTypeStruct %10 %303
%301 = OpTypePointer Uniform %302
%300 = OpVariable %301 Uniform
%400 = OpVariable %101 Uniform
%500 = OpVariable %201 Uniform
%604 = OpTypeArray %13 %20
%603 = OpTypeArray %604 %20
%602 = OpTypeArray %603 %20
%601 = OpTypePointer Uniform %602
%600 = OpVariable %601 Uniform
%703 = OpTypeArray %13 %20
%702 = OpTypeArray %703 %20
%701 = OpTypePointer Uniform %702
%700 = OpVariable %701 Uniform
%802 = OpTypeStruct %702 %602 %19 %202 %302
%801 = OpTypePointer Uniform %802
%800 = OpVariable %801 Uniform
%902 = OpTypeStruct %702 %802 %19 %202 %302
%901 = OpTypePointer Uniform %902
%900 = OpVariable %901 Uniform
%1003 = OpTypeStruct %802
%1002 = OpTypeArray %1003 %20
%1001 = OpTypePointer Uniform %1002
%1000 = OpVariable %1001 Uniform
%1101 = OpTypePointer Uniform %21
%1100 = OpVariable %1101 Uniform
%1202 = OpTypeArray %21 %20
%1201 = OpTypePointer Uniform %1202
%1200 = OpVariable %1201 Uniform
%1302 = OpTypeArray %21 %20
%1301 = OpTypePointer Uniform %1302
%1300 = OpVariable %1301 Uniform
%1402 = OpTypeArray %15 %22
%1401 = OpTypePointer Uniform %1402
%1400 = OpVariable %1401 Uniform
%1501 = OpTypePointer Uniform %1402
%1500 = OpVariable %1501 Uniform
%1602 = OpTypeArray %1402 %22
%1601 = OpTypePointer Uniform %1602
%1600 = OpVariable %1601 Uniform
%1704 = OpTypeStruct %16 %16 %16
%1703 = OpTypeArray %1704 %22
%1702 = OpTypeArray %1703 %22
%1701 = OpTypePointer Uniform %1702
%1700 = OpVariable %1701 Uniform
%1800 = OpVariable %1701 Uniform
%1906 = OpTypeStruct %16
%1905 = OpTypeStruct %1906
%1904 = OpTypeStruct %1905
%1903 = OpTypeStruct %1904
%1902 = OpTypeStruct %1903
%1901 = OpTypePointer Uniform %1902
%1900 = OpVariable %1901 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
uint32_t buffer_int32_min[1];
uint32_t buffer_int64_1[2];
uint32_t buffer_int64_max[2];
uint32_t buffer_uint64_1[2];
uint32_t buffer_uint64_max[2];
uint32_t buffer_float_10[1];
uint32_t buffer_double_10[2];
uint32_t buffer_double_20[2];
{
int32_t temp = std::numeric_limits<int32_t>::min();
std::memcpy(&buffer_int32_min, &temp, sizeof(temp));
}
{
int64_t temp = 1;
std::memcpy(&buffer_int64_1, &temp, sizeof(temp));
}
{
int64_t temp = std::numeric_limits<int64_t>::max();
std::memcpy(&buffer_int64_max, &temp, sizeof(temp));
}
{
uint64_t temp = 1;
std::memcpy(&buffer_uint64_1, &temp, sizeof(temp));
}
{
uint64_t temp = std::numeric_limits<uint64_t>::max();
std::memcpy(&buffer_uint64_max, &temp, sizeof(temp));
}
{
float temp = 10.0f;
std::memcpy(&buffer_float_10, &temp, sizeof(float));
}
{
double temp = 10.0;
std::memcpy(&buffer_double_10, &temp, sizeof(temp));
}
{
double temp = 20.0;
std::memcpy(&buffer_double_20, &temp, sizeof(temp));
}
FactManager fact_manager;
uint32_t type_int32_id = 11;
uint32_t type_int64_id = 13;
uint32_t type_uint32_id = 10;
uint32_t type_uint64_id = 12;
uint32_t type_float_id = 15;
uint32_t type_double_id = 16;
// Initially there should be no facts about uniforms.
ASSERT_TRUE(fact_manager
.GetConstantsAvailableFromUniformsForType(context.get(),
type_uint32_id)
.empty());
// 100[2][3] == int(1)
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
MakeUniformBufferElementDescriptor(100, {2, 3})));
// 200[1][2][3] == int(1)
ASSERT_TRUE(
AddFactHelper(&fact_manager, context.get(), {1},
MakeUniformBufferElementDescriptor(200, {1, 2, 3})));
// 300[1][0][2][3] == int(1)
ASSERT_TRUE(
AddFactHelper(&fact_manager, context.get(), {1},
MakeUniformBufferElementDescriptor(300, {1, 0, 2, 3})));
// 400[2][3] = int32_min
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]},
MakeUniformBufferElementDescriptor(400, {2, 3})));
// 500[1][2][3] = int32_min
ASSERT_TRUE(
AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]},
MakeUniformBufferElementDescriptor(500, {1, 2, 3})));
// 600[1][2][3] = int64_max
ASSERT_TRUE(AddFactHelper(
&fact_manager, context.get(), {buffer_int64_max[0], buffer_int64_max[1]},
MakeUniformBufferElementDescriptor(600, {1, 2, 3})));
// 700[1][1] = int64_max
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
{buffer_int64_max[0], buffer_int64_max[1]},
MakeUniformBufferElementDescriptor(700, {1, 1})));
// 800[2][3] = uint(1)
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
MakeUniformBufferElementDescriptor(800, {2, 3})));
// 900[1][2][3] = uint(1)
ASSERT_TRUE(
AddFactHelper(&fact_manager, context.get(), {1},
MakeUniformBufferElementDescriptor(900, {1, 2, 3})));
// 1000[1][0][2][3] = uint(1)
ASSERT_TRUE(
AddFactHelper(&fact_manager, context.get(), {1},
MakeUniformBufferElementDescriptor(1000, {1, 0, 2, 3})));
// 1100[0] = uint64(1)
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
{buffer_uint64_1[0], buffer_uint64_1[1]},
MakeUniformBufferElementDescriptor(1100, {0})));
// 1200[0][0] = uint64_max
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
{buffer_uint64_max[0], buffer_uint64_max[1]},
MakeUniformBufferElementDescriptor(1200, {0, 0})));
// 1300[1][0] = uint64_max
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
{buffer_uint64_max[0], buffer_uint64_max[1]},
MakeUniformBufferElementDescriptor(1300, {1, 0})));
// 1400[6] = float(10.0)
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
MakeUniformBufferElementDescriptor(1400, {6})));
// 1500[7] = float(10.0)
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
MakeUniformBufferElementDescriptor(1500, {7})));
// 1600[9][9] = float(10.0)
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
MakeUniformBufferElementDescriptor(1600, {9, 9})));
// 1700[9][9][1] = double(10.0)
ASSERT_TRUE(AddFactHelper(
&fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]},
MakeUniformBufferElementDescriptor(1700, {9, 9, 1})));
// 1800[9][9][2] = double(10.0)
ASSERT_TRUE(AddFactHelper(
&fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]},
MakeUniformBufferElementDescriptor(1800, {9, 9, 2})));
// 1900[0][0][0][0][0] = double(20.0)
ASSERT_TRUE(AddFactHelper(
&fact_manager, context.get(), {buffer_double_20[0], buffer_double_20[1]},
MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0})));
opt::Instruction::OperandList operands = {
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_int32_id, 50, operands));
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int32_min[0]}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_int32_id, 51, operands));
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[0]}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[1]}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_int64_id, 52, operands));
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_uint32_id, 53, operands));
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[0]}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[1]}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_uint64_id, 54, operands));
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[0]}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[1]}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_uint64_id, 55, operands));
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_float_10[0]}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_float_id, 56, operands));
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[0]}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[1]}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_double_id, 57, operands));
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[0]}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[1]}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_double_id, 58, operands));
// A duplicate of the constant with id 59.
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context.get(), SpvOpConstant, type_int32_id, 59, operands));
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
// Constants 1 and int32_min are available.
ASSERT_EQ(2, fact_manager
.GetConstantsAvailableFromUniformsForType(context.get(),
type_int32_id)
.size());
// Constant int64_max is available.
ASSERT_EQ(1, fact_manager
.GetConstantsAvailableFromUniformsForType(context.get(),
type_int64_id)
.size());
// Constant 1u is available.
ASSERT_EQ(1, fact_manager
.GetConstantsAvailableFromUniformsForType(context.get(),
type_uint32_id)
.size());
// Constants 1u and uint64_max are available.
ASSERT_EQ(2, fact_manager
.GetConstantsAvailableFromUniformsForType(context.get(),
type_uint64_id)
.size());
// Constant 10.0 is available.
ASSERT_EQ(1, fact_manager
.GetConstantsAvailableFromUniformsForType(context.get(),
type_float_id)
.size());
// Constants 10.0 and 20.0 are available.
ASSERT_EQ(2, fact_manager
.GetConstantsAvailableFromUniformsForType(context.get(),
type_double_id)
.size());
ASSERT_EQ(std::numeric_limits<int64_t>::max(),
context->get_constant_mgr()
->FindDeclaredConstant(
fact_manager.GetConstantsAvailableFromUniformsForType(
context.get(), type_int64_id)[0])
->AsIntConstant()
->GetS64());
ASSERT_EQ(1, context->get_constant_mgr()
->FindDeclaredConstant(
fact_manager.GetConstantsAvailableFromUniformsForType(
context.get(), type_uint32_id)[0])
->AsIntConstant()
->GetU32());
ASSERT_EQ(10.0f,
context->get_constant_mgr()
->FindDeclaredConstant(
fact_manager.GetConstantsAvailableFromUniformsForType(
context.get(), type_float_id)[0])
->AsFloatConstant()
->GetFloat());
const std::vector<uint32_t>& double_constant_ids =
fact_manager.GetConstantsAvailableFromUniformsForType(context.get(),
type_double_id);
ASSERT_EQ(10.0, context->get_constant_mgr()
->FindDeclaredConstant(double_constant_ids[0])
->AsFloatConstant()
->GetDouble());
ASSERT_EQ(20.0, context->get_constant_mgr()
->FindDeclaredConstant(double_constant_ids[1])
->AsFloatConstant()
->GetDouble());
const std::vector<protobufs::UniformBufferElementDescriptor>
descriptors_for_double_10 = fact_manager.GetUniformDescriptorsForConstant(
context.get(), double_constant_ids[0]);
ASSERT_EQ(2, descriptors_for_double_10.size());
{
auto temp = MakeUniformBufferElementDescriptor(1700, {9, 9, 1});
ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
&temp, &descriptors_for_double_10[0]));
}
{
auto temp = MakeUniformBufferElementDescriptor(1800, {9, 9, 2});
ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
&temp, &descriptors_for_double_10[1]));
}
const std::vector<protobufs::UniformBufferElementDescriptor>
descriptors_for_double_20 = fact_manager.GetUniformDescriptorsForConstant(
context.get(), double_constant_ids[1]);
ASSERT_EQ(1, descriptors_for_double_20.size());
{
auto temp = MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0});
ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
&temp, &descriptors_for_double_20[0]));
}
auto constant_1_id = fact_manager.GetConstantFromUniformDescriptor(
context.get(), MakeUniformBufferElementDescriptor(1800, {9, 9, 2}));
ASSERT_TRUE(constant_1_id);
auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor(
context.get(), MakeUniformBufferElementDescriptor(1900, {0, 0, 0, 0, 0}));
ASSERT_TRUE(constant_2_id);
ASSERT_EQ(double_constant_ids[0], constant_1_id);
ASSERT_EQ(double_constant_ids[1], constant_2_id);
}
TEST(FactManagerTest, TwoConstantsWithSameValue) {
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
OpName %8 "x"
OpName %10 "buf"
OpMemberName %10 0 "a"
OpName %12 ""
OpDecorate %8 RelaxedPrecision
OpMemberDecorate %10 0 RelaxedPrecision
OpMemberDecorate %10 0 Offset 0
OpDecorate %10 Block
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 1
%20 = OpConstant %6 1
%10 = OpTypeStruct %6
%11 = OpTypePointer Uniform %10
%12 = OpVariable %11 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
OpStore %8 %9
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
auto uniform_buffer_element_descriptor =
MakeUniformBufferElementDescriptor(12, {0});
// 12[0] = int(1)
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
uniform_buffer_element_descriptor));
auto constants =
fact_manager.GetConstantsAvailableFromUniformsForType(context.get(), 6);
ASSERT_EQ(1, constants.size());
ASSERT_TRUE(constants[0] == 9 || constants[0] == 20);
auto constant = fact_manager.GetConstantFromUniformDescriptor(
context.get(), uniform_buffer_element_descriptor);
ASSERT_TRUE(constant == 9 || constant == 20);
// Because the constants with ids 9 and 20 are equal, we should get the same
// single uniform buffer element descriptor when we look up the descriptors
// for either one of them.
for (auto constant_id : {9u, 20u}) {
auto descriptors = fact_manager.GetUniformDescriptorsForConstant(
context.get(), constant_id);
ASSERT_EQ(1, descriptors.size());
ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
&uniform_buffer_element_descriptor, &descriptors[0]));
}
}
} // namespace
} // namespace fuzz
} // namespace spvtools

View File

@@ -13,6 +13,7 @@
// limitations under the License.
#include "source/fuzz/fuzzer.h"
#include "source/fuzz/replayer.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
@@ -21,9 +22,11 @@ namespace {
// Assembles the given |shader| text, and then runs the fuzzer |num_runs|
// times, using successive seeds starting from |initial_seed|. Checks that
// the binary produced after each fuzzer run is valid.
void RunFuzzer(const std::string& shader, uint32_t initial_seed,
uint32_t num_runs) {
// the binary produced after each fuzzer run is valid, and that replaying
// the transformations that were applied during fuzzing leads to an
// identical binary.
void RunFuzzerAndReplayer(const std::string& shader, uint32_t initial_seed,
uint32_t num_runs) {
const auto env = SPV_ENV_UNIVERSAL_1_3;
std::vector<uint32_t> binary_in;
@@ -33,19 +36,38 @@ void RunFuzzer(const std::string& shader, uint32_t initial_seed,
for (uint32_t seed = initial_seed; seed < initial_seed + num_runs; seed++) {
protobufs::FactSequence initial_facts;
std::vector<uint32_t> binary_out;
protobufs::TransformationSequence transformation_sequence_out;
std::vector<uint32_t> fuzzer_binary_out;
protobufs::TransformationSequence fuzzer_transformation_sequence_out;
spvtools::FuzzerOptions fuzzer_options;
spvFuzzerOptionsSetRandomSeed(fuzzer_options, seed);
Fuzzer fuzzer(env);
fuzzer.Run(binary_in, initial_facts, &binary_out,
&transformation_sequence_out, fuzzer_options);
ASSERT_TRUE(t.Validate(binary_out));
fuzzer.Run(binary_in, initial_facts, &fuzzer_binary_out,
&fuzzer_transformation_sequence_out, fuzzer_options);
ASSERT_TRUE(t.Validate(fuzzer_binary_out));
std::vector<uint32_t> replayer_binary_out;
protobufs::TransformationSequence replayer_transformation_sequence_out;
Replayer replayer(env);
replayer.Run(binary_in, initial_facts, fuzzer_transformation_sequence_out,
&replayer_binary_out, &replayer_transformation_sequence_out);
// After replaying the transformations applied by the fuzzer, exactly those
// transformations should have been applied, and the binary resulting from
// replay should be identical to that which resulted from fuzzing.
std::string fuzzer_transformations_string;
std::string replayer_transformations_string;
fuzzer_transformation_sequence_out.SerializeToString(
&fuzzer_transformations_string);
replayer_transformation_sequence_out.SerializeToString(
&replayer_transformations_string);
ASSERT_EQ(fuzzer_transformations_string, replayer_transformations_string);
ASSERT_EQ(fuzzer_binary_out, replayer_binary_out);
}
}
TEST(FuzzerTest, Miscellaneous1) {
TEST(FuzzerReplayerTest, Miscellaneous1) {
// The SPIR-V came from this GLSL:
//
// #version 310 es
@@ -211,10 +233,10 @@ TEST(FuzzerTest, Miscellaneous1) {
// Do 10 fuzzer runs, starting from an initial seed of 0 (seed value chosen
// arbitrarily).
RunFuzzer(shader, 0, 10);
RunFuzzerAndReplayer(shader, 0, 10);
}
TEST(FuzzerTest, Miscellaneous2) {
TEST(FuzzerReplayerTest, Miscellaneous2) {
// The SPIR-V came from this GLSL, which was then optimized using spirv-opt
// with the -O argument:
//
@@ -456,7 +478,7 @@ TEST(FuzzerTest, Miscellaneous2) {
// Do 10 fuzzer runs, starting from an initial seed of 10 (seed value chosen
// arbitrarily).
RunFuzzer(shader, 10, 10);
RunFuzzerAndReplayer(shader, 10, 10);
}
} // namespace

View File

@@ -3811,7 +3811,7 @@ OpName %output "output"
%6 = OpTypeFunction %void
%float = OpTypeFloat 32
%_ptr_Private_float = OpTypePointer Private %float
%initializer = OpVariable %_ptr_Private_float Private
%initializer = OpConstant %float 0
%live = OpVariable %_ptr_Private_float Private %initializer
%_ptr_Output_float = OpTypePointer Output %float
%output = OpVariable %_ptr_Output_float Output

View File

@@ -217,7 +217,7 @@ OpName %initializer "initializer"
%6 = OpTypeFunction %void
%float = OpTypeFloat 32
%_ptr_Private_float = OpTypePointer Private %float
%initializer = OpVariable %_ptr_Private_float Private
%initializer = OpConstant %float 0
%live = OpVariable %_ptr_Private_float Private %initializer
%main = OpFunction %void None %6
%9 = OpLabel

View File

@@ -52,6 +52,8 @@ using ::testing::Values;
using ::testing::ValuesIn;
using ValidateBuiltIns = spvtest::ValidateBase<bool>;
using ValidateVulkanSubgroupBuiltIns = spvtest::ValidateBase<
std::tuple<const char*, const char*, const char*, const char*, TestResult>>;
using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult =
spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
const char*, TestResult>>;
@@ -3080,6 +3082,226 @@ TEST_F(ValidateBuiltIns, GetUnderlyingTypeNoAssert) {
"type"));
}
TEST_P(ValidateVulkanSubgroupBuiltIns, 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 = CodeGenerator::GetDefaultShaderCodeGenerator();
generator.capabilities_ += R"(
OpCapability GroupNonUniformBallot
)";
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_ptr = OpTypePointer " << storage_class << " "
<< data_type << "\n";
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
after_types << "\n";
generator.after_types_ = after_types.str();
EntryPoint entry_point;
entry_point.name = "main";
entry_point.execution_model = execution_model;
if (strncmp(storage_class, "Input", 5) == 0 ||
strncmp(storage_class, "Output", 6) == 0) {
entry_point.interfaces = "%built_in_var";
}
entry_point.body =
std::string("%ld = OpLoad ") + data_type + " %built_in_var\n";
std::ostringstream execution_modes;
if (0 == std::strcmp(execution_model, "Fragment")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OriginUpperLeft\n";
if (0 == std::strcmp(built_in, "FragDepth")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
}
}
if (0 == std::strcmp(execution_model, "Geometry")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " InputPoints\n";
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OutputPoints\n";
}
if (0 == std::strcmp(execution_model, "GLCompute")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " LocalSize 1 1 1\n";
}
entry_point.execution_modes = execution_modes.str();
generator.entry_points_.push_back(std::move(entry_point));
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_1);
ASSERT_EQ(test_result.validation_result,
ValidateInstructions(SPV_ENV_VULKAN_1_1));
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_SUITE_P(
SubgroupMaskNotVec4, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask",
"SubgroupLeMask", "SubgroupLtMask"),
Values("GLCompute"), Values("Input"), Values("%u32vec3"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 4-component 32-bit int vector"))));
INSTANTIATE_TEST_SUITE_P(
SubgroupMaskNotU32, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask",
"SubgroupLeMask", "SubgroupLtMask"),
Values("GLCompute"), Values("Input"), Values("%f32vec4"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 4-component 32-bit int vector"))));
INSTANTIATE_TEST_SUITE_P(
SubgroupMaskNotInput, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask",
"SubgroupLeMask", "SubgroupLtMask"),
Values("GLCompute"), Values("Output", "Workgroup", "Private"),
Values("%u32vec4"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"to be only used for variables with Input storage class"))));
INSTANTIATE_TEST_SUITE_P(SubgroupMaskOk, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupEqMask", "SubgroupGeMask",
"SubgroupGtMask", "SubgroupLeMask",
"SubgroupLtMask"),
Values("GLCompute"), Values("Input"),
Values("%u32vec4"),
Values(TestResult(SPV_SUCCESS, ""))));
TEST_F(ValidateBuiltIns, SubgroupMaskMemberDecorate) {
const std::string text = R"(
OpCapability Shader
OpCapability GroupNonUniformBallot
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %foo "foo"
OpExecutionMode %foo LocalSize 1 1 1
OpMemberDecorate %struct 0 BuiltIn SubgroupEqMask
%void = OpTypeVoid
%int = OpTypeInt 32 0
%struct = OpTypeStruct %int
%void_fn = OpTypeFunction %void
%foo = OpFunction %void None %void_fn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"BuiltIn SubgroupEqMask cannot be used as a member decoration"));
}
INSTANTIATE_TEST_SUITE_P(
SubgroupInvocationIdAndSizeNotU32, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
Values("GLCompute"), Values("Input"), Values("%f32"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 32-bit int"))));
INSTANTIATE_TEST_SUITE_P(
SubgroupInvocationIdAndSizeNotInput, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
Values("GLCompute"), Values("Output", "Workgroup", "Private"),
Values("%u32"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"to be only used for variables with Input storage class"))));
INSTANTIATE_TEST_SUITE_P(
SubgroupInvocationIdAndSizeOk, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
Values("GLCompute"), Values("Input"), Values("%u32"),
Values(TestResult(SPV_SUCCESS, ""))));
TEST_F(ValidateBuiltIns, SubgroupSizeMemberDecorate) {
const std::string text = R"(
OpCapability Shader
OpCapability GroupNonUniform
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %foo "foo"
OpExecutionMode %foo LocalSize 1 1 1
OpMemberDecorate %struct 0 BuiltIn SubgroupSize
%void = OpTypeVoid
%int = OpTypeInt 32 0
%struct = OpTypeStruct %int
%void_fn = OpTypeFunction %void
%foo = OpFunction %void None %void_fn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("BuiltIn SubgroupSize cannot be used as a member decoration"));
}
INSTANTIATE_TEST_SUITE_P(
SubgroupNumAndIdNotU32, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"),
Values("Input"), Values("%f32"),
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 32-bit int"))));
INSTANTIATE_TEST_SUITE_P(
SubgroupNumAndIdNotInput, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"),
Values("Output", "Workgroup", "Private"), Values("%u32"),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"to be only used for variables with Input storage class"))));
INSTANTIATE_TEST_SUITE_P(SubgroupNumAndIdOk, ValidateVulkanSubgroupBuiltIns,
Combine(Values("SubgroupId", "NumSubgroups"),
Values("GLCompute"), Values("Input"),
Values("%u32"),
Values(TestResult(SPV_SUCCESS, ""))));
TEST_F(ValidateBuiltIns, SubgroupIdMemberDecorate) {
const std::string text = R"(
OpCapability Shader
OpCapability GroupNonUniform
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %foo "foo"
OpExecutionMode %foo LocalSize 1 1 1
OpMemberDecorate %struct 0 BuiltIn SubgroupId
%void = OpTypeVoid
%int = OpTypeInt 32 0
%struct = OpTypeStruct %int
%void_fn = OpTypeFunction %void
%foo = OpFunction %void None %void_fn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("BuiltIn SubgroupId cannot be used as a member decoration"));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@@ -3543,6 +3543,29 @@ OpFunctionEnd
INSTANTIATE_TEST_SUITE_P(PointerComparisons, ValidatePointerComparisons,
Values("OpPtrEqual", "OpPtrNotEqual", "OpPtrDiff"));
TEST_F(ValidateMemory, VariableInitializerWrongType) {
const std::string spirv = R"(
OpCapability Shader
OpCapability Linkage
OpCapability VariablePointersStorageBuffer
OpMemoryModel Logical GLSL450
%void = OpTypeVoid
%int = OpTypeInt 32 0
%float = OpTypeFloat 32
%ptr_wg_int = OpTypePointer Workgroup %int
%ptr_wg_float = OpTypePointer Workgroup %int
%wg_var = OpVariable %ptr_wg_int Workgroup
%ptr_private_wg_float = OpTypePointer Private %ptr_wg_float
%priv_var = OpVariable %ptr_private_wg_float Private %wg_var
)";
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Initializer type must match the type pointed to by "
"the Result Type"));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@@ -21,6 +21,7 @@
#include "source/fuzz/fuzzer.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/replayer.h"
#include "source/opt/build_module.h"
#include "source/opt/ir_context.h"
#include "source/opt/log.h"
@@ -32,7 +33,11 @@
namespace {
// Status and actions to perform after parsing command-line arguments.
enum class FuzzActions { CONTINUE, STOP };
enum class FuzzActions {
FUZZ, // Run the fuzzer to apply transformations in a randomized fashion.
REPLAY, // Replay an existing sequence of transformations.
STOP // Do nothing.
};
struct FuzzStatus {
FuzzActions action;
@@ -60,6 +65,9 @@ Options (in lexicographical order):
-h, --help
Print this help.
--replay
File from which to read a sequence of transformations to replay
(instead of fuzzing)
--seed
Unsigned 32-bit integer seed to control random number
generation.
@@ -90,6 +98,7 @@ bool EndsWithSpv(const std::string& filename) {
FuzzStatus ParseFlags(int argc, const char** argv, std::string* in_binary_file,
std::string* out_binary_file,
std::string* replay_transformations_file,
spvtools::FuzzerOptions* fuzzer_options) {
uint32_t positional_arg_index = 0;
@@ -110,6 +119,9 @@ FuzzStatus ParseFlags(int argc, const char** argv, std::string* in_binary_file,
PrintUsage(argv[0]);
return {FuzzActions::STOP, 1};
}
} else if (0 == strncmp(cur_arg, "--replay=", sizeof("--replay=") - 1)) {
const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
*replay_transformations_file = std::string(split_flag.second);
} else if (0 == strncmp(cur_arg, "--seed=", sizeof("--seed=") - 1)) {
const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg);
char* end = nullptr;
@@ -158,7 +170,64 @@ FuzzStatus ParseFlags(int argc, const char** argv, std::string* in_binary_file,
return {FuzzActions::STOP, 1};
}
return {FuzzActions::CONTINUE, 0};
if (!replay_transformations_file->empty()) {
// A replay transformations file was given, thus the tool is being invoked
// in replay mode.
return {FuzzActions::REPLAY, 0};
}
return {FuzzActions::FUZZ, 0};
}
bool Replay(const spv_target_env& target_env,
const std::vector<uint32_t>& binary_in,
const spvtools::fuzz::protobufs::FactSequence& initial_facts,
const std::string& replay_transformations_file,
std::vector<uint32_t>* binary_out,
spvtools::fuzz::protobufs::TransformationSequence*
transformations_applied) {
std::ifstream existing_transformations_file;
existing_transformations_file.open(replay_transformations_file,
std::ios::in | std::ios::binary);
spvtools::fuzz::protobufs::TransformationSequence
existing_transformation_sequence;
auto parse_success = existing_transformation_sequence.ParseFromIstream(
&existing_transformations_file);
existing_transformations_file.close();
if (!parse_success) {
spvtools::Error(FuzzDiagnostic, nullptr, {},
"Error reading transformations for replay");
return false;
}
spvtools::fuzz::Replayer replayer(target_env);
replayer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
auto replay_result_status =
replayer.Run(binary_in, initial_facts, existing_transformation_sequence,
binary_out, transformations_applied);
if (replay_result_status !=
spvtools::fuzz::Replayer::ReplayerResultStatus::kComplete) {
return false;
}
return true;
}
bool Fuzz(const spv_target_env& target_env,
const spvtools::FuzzerOptions& fuzzer_options,
const std::vector<uint>& binary_in,
const spvtools::fuzz::protobufs::FactSequence& initial_facts,
std::vector<uint32_t>* binary_out,
spvtools::fuzz::protobufs::TransformationSequence*
transformations_applied) {
spvtools::fuzz::Fuzzer fuzzer(target_env);
fuzzer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
auto fuzz_result_status = fuzzer.Run(binary_in, initial_facts, binary_out,
transformations_applied, fuzzer_options);
if (fuzz_result_status !=
spvtools::fuzz::Fuzzer::FuzzerResultStatus::kComplete) {
spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error running fuzzer");
return false;
}
return true;
}
} // namespace
@@ -168,12 +237,12 @@ const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_3;
int main(int argc, const char** argv) {
std::string in_binary_file;
std::string out_binary_file;
std::string replay_transformations_file;
spv_target_env target_env = kDefaultEnvironment;
spvtools::FuzzerOptions fuzzer_options;
FuzzStatus status = ParseFlags(argc, argv, &in_binary_file, &out_binary_file,
&fuzzer_options);
&replay_transformations_file, &fuzzer_options);
if (status.action == FuzzActions::STOP) {
return status.code;
@@ -205,15 +274,25 @@ int main(int argc, const char** argv) {
std::vector<uint32_t> binary_out;
spvtools::fuzz::protobufs::TransformationSequence transformations_applied;
spvtools::fuzz::Fuzzer fuzzer(target_env);
fuzzer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
auto fuzz_result_status =
fuzzer.Run(binary_in, initial_facts, &binary_out,
&transformations_applied, fuzzer_options);
if (fuzz_result_status !=
spvtools::fuzz::Fuzzer::FuzzerResultStatus::kComplete) {
spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error running fuzzer");
return 1;
spv_target_env target_env = kDefaultEnvironment;
switch (status.action) {
case FuzzActions::FUZZ:
if (!Fuzz(target_env, fuzzer_options, binary_in, initial_facts,
&binary_out, &transformations_applied)) {
return 1;
}
break;
case FuzzActions::REPLAY:
if (!Replay(target_env, binary_in, initial_facts,
replay_transformations_file, &binary_out,
&transformations_applied)) {
return 1;
}
break;
default:
assert(false && "Unknown fuzzer action.");
break;
}
if (!WriteFile<uint32_t>(out_binary_file.c_str(), "wb", binary_out.data(),