Parcourir la source

Updated spirv-tools.

Бранимир Караџић il y a 6 ans
Parent
commit
896f9952f3
23 fichiers modifiés avec 1941 ajouts et 132 suppressions
  1. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  2. 2 1
      3rdparty/spirv-tools/include/generated/enum_string_mapping.inc
  3. 1 0
      3rdparty/spirv-tools/include/generated/extension_enum.inc
  4. 50 47
      3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc
  5. 5 1
      3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
  6. 268 6
      3rdparty/spirv-tools/source/fuzz/fact_manager.cpp
  7. 56 0
      3rdparty/spirv-tools/source/fuzz/fact_manager.h
  8. 52 1
      3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto
  9. 200 0
      3rdparty/spirv-tools/source/fuzz/replayer.cpp
  10. 74 0
      3rdparty/spirv-tools/source/fuzz/replayer.h
  11. 39 0
      3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp
  12. 41 0
      3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h
  13. 42 38
      3rdparty/spirv-tools/source/opt/log.h
  14. 196 9
      3rdparty/spirv-tools/source/val/validate_builtins.cpp
  15. 5 0
      3rdparty/spirv-tools/source/val/validate_memory.cpp
  16. 2 1
      3rdparty/spirv-tools/test/fuzz/CMakeLists.txt
  17. 534 0
      3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp
  18. 34 12
      3rdparty/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp
  19. 1 1
      3rdparty/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp
  20. 1 1
      3rdparty/spirv-tools/test/opt/dead_variable_elim_test.cpp
  21. 222 0
      3rdparty/spirv-tools/test/val/val_builtins_test.cpp
  22. 23 0
      3rdparty/spirv-tools/test/val/val_memory_test.cpp
  23. 92 13
      3rdparty/spirv-tools/tools/fuzz/fuzz.cpp

+ 1 - 1
3rdparty/spirv-tools/include/generated/build-version.inc

@@ -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"

Fichier diff supprimé car celui-ci est trop grand
+ 2 - 1
3rdparty/spirv-tools/include/generated/enum_string_mapping.inc


+ 1 - 0
3rdparty/spirv-tools/include/generated/extension_enum.inc

@@ -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,

+ 50 - 47
3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc

@@ -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[] = {

+ 5 - 1
3rdparty/spirv-tools/source/fuzz/CMakeLists.txt

@@ -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
         )
 

+ 268 - 6
3rdparty/spirv-tools/source/fuzz/fact_manager.cpp

@@ -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

+ 56 - 0
3rdparty/spirv-tools/source/fuzz/fact_manager.h

@@ -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

+ 52 - 1
3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto

@@ -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 {

+ 200 - 0
3rdparty/spirv-tools/source/fuzz/replayer.cpp

@@ -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

+ 74 - 0
3rdparty/spirv-tools/source/fuzz/replayer.h

@@ -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_

+ 39 - 0
3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp

@@ -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

+ 41 - 0
3rdparty/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h

@@ -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_

+ 42 - 38
3rdparty/spirv-tools/source/opt/log.h

@@ -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, ...) \

+ 196 - 9
3rdparty/spirv-tools/source/val/validate_builtins.cpp

@@ -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:

+ 5 - 0
3rdparty/spirv-tools/source/val/validate_memory.cpp

@@ -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 =

+ 2 - 1
3rdparty/spirv-tools/test/fuzz/CMakeLists.txt

@@ -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

+ 534 - 0
3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp

@@ -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

+ 34 - 12
3rdparty/spirv-tools/test/fuzz/fuzzer_test.cpp → 3rdparty/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp

@@ -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

+ 1 - 1
3rdparty/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp

@@ -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

+ 1 - 1
3rdparty/spirv-tools/test/opt/dead_variable_elim_test.cpp

@@ -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

+ 222 - 0
3rdparty/spirv-tools/test/val/val_builtins_test.cpp

@@ -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

+ 23 - 0
3rdparty/spirv-tools/test/val/val_memory_test.cpp

@@ -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

+ 92 - 13
3rdparty/spirv-tools/tools/fuzz/fuzz.cpp

@@ -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(),

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff