Browse Source

Updated spirv-tools.

Бранимир Караџић 1 year ago
parent
commit
3ac2dda244
39 changed files with 1086 additions and 70 deletions
  1. 1 1
      3rdparty/spirv-tools/include/generated/DebugInfo.h
  2. 1 1
      3rdparty/spirv-tools/include/generated/NonSemanticShaderDebugInfo100.h
  3. 1 1
      3rdparty/spirv-tools/include/generated/OpenCLDebugInfo100.h
  4. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  5. 7 1
      3rdparty/spirv-tools/include/generated/core.insts-unified1.inc
  6. 8 0
      3rdparty/spirv-tools/include/generated/enum_string_mapping.inc
  7. 4 0
      3rdparty/spirv-tools/include/generated/extension_enum.inc
  8. 2 1
      3rdparty/spirv-tools/include/generated/generators.inc
  9. 23 5
      3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc
  10. 4 0
      3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp
  11. 2 0
      3rdparty/spirv-tools/source/opcode.cpp
  12. 1 0
      3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp
  13. 11 0
      3rdparty/spirv-tools/source/opt/block_merge_util.cpp
  14. 219 1
      3rdparty/spirv-tools/source/opt/const_folding_rules.cpp
  15. 22 2
      3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp
  16. 0 22
      3rdparty/spirv-tools/source/opt/def_use_manager.h
  17. 47 2
      3rdparty/spirv-tools/source/opt/desc_sroa.cpp
  18. 5 0
      3rdparty/spirv-tools/source/opt/desc_sroa.h
  19. 6 0
      3rdparty/spirv-tools/source/opt/ir_context.h
  20. 2 2
      3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp
  21. 1 0
      3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp
  22. 1 0
      3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp
  23. 103 0
      3rdparty/spirv-tools/source/opt/modify_maximal_reconvergence.cpp
  24. 53 0
      3rdparty/spirv-tools/source/opt/modify_maximal_reconvergence.h
  25. 24 0
      3rdparty/spirv-tools/source/opt/optimizer.cpp
  26. 1 0
      3rdparty/spirv-tools/source/opt/passes.h
  27. 11 0
      3rdparty/spirv-tools/source/opt/trim_capabilities_pass.cpp
  28. 2 1
      3rdparty/spirv-tools/source/opt/trim_capabilities_pass.h
  29. 4 0
      3rdparty/spirv-tools/source/val/validate.cpp
  30. 12 0
      3rdparty/spirv-tools/source/val/validate.h
  31. 28 0
      3rdparty/spirv-tools/source/val/validate_annotation.cpp
  32. 177 3
      3rdparty/spirv-tools/source/val/validate_builtins.cpp
  33. 96 0
      3rdparty/spirv-tools/source/val/validate_cfg.cpp
  34. 2 1
      3rdparty/spirv-tools/source/val/validate_instruction.cpp
  35. 1 4
      3rdparty/spirv-tools/source/val/validate_memory_semantics.cpp
  36. 169 16
      3rdparty/spirv-tools/source/val/validate_mode_setting.cpp
  37. 8 3
      3rdparty/spirv-tools/source/val/validate_non_uniform.cpp
  38. 6 2
      3rdparty/spirv-tools/source/val/validate_scopes.cpp
  39. 20 0
      3rdparty/spirv-tools/source/val/validation_state.cpp

+ 1 - 1
3rdparty/spirv-tools/include/generated/DebugInfo.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Khronos Group Inc.
+// Copyright (c) 2017-2024 The Khronos Group Inc.
 // 
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and/or associated documentation files (the "Materials"),

+ 1 - 1
3rdparty/spirv-tools/include/generated/NonSemanticShaderDebugInfo100.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Khronos Group Inc.
+// Copyright (c) 2018-2024 The Khronos Group Inc.
 // 
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and/or associated documentation files (the "Materials"),

+ 1 - 1
3rdparty/spirv-tools/include/generated/OpenCLDebugInfo100.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Khronos Group Inc.
+// Copyright (c) 2018-2024 The Khronos Group Inc.
 // 
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and/or associated documentation files (the "Materials"),

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

@@ -1 +1 @@
-"v2023.6", "SPIRV-Tools v2023.6 v2023.6.rc1-7-g57aba7ff"
+"v2023.6", "SPIRV-Tools v2023.6 v2023.6.rc1-37-g58b2f0b6"

+ 7 - 1
3rdparty/spirv-tools/include/generated/core.insts-unified1.inc

@@ -44,6 +44,7 @@ static const spv::Capability pygen_variable_caps_Kernel[] = {spv::Capability::Ke
 static const spv::Capability pygen_variable_caps_KernelImageQuery[] = {spv::Capability::Kernel, spv::Capability::ImageQuery};
 static const spv::Capability pygen_variable_caps_LiteralSampler[] = {spv::Capability::LiteralSampler};
 static const spv::Capability pygen_variable_caps_LongCompositesINTEL[] = {spv::Capability::LongCompositesINTEL};
+static const spv::Capability pygen_variable_caps_MaskedGatherScatterINTEL[] = {spv::Capability::MaskedGatherScatterINTEL};
 static const spv::Capability pygen_variable_caps_Matrix[] = {spv::Capability::Matrix};
 static const spv::Capability pygen_variable_caps_MemoryAccessAliasingINTEL[] = {spv::Capability::MemoryAccessAliasingINTEL};
 static const spv::Capability pygen_variable_caps_MeshShadingEXT[] = {spv::Capability::MeshShadingEXT};
@@ -51,6 +52,7 @@ static const spv::Capability pygen_variable_caps_MeshShadingNV[] = {spv::Capabil
 static const spv::Capability pygen_variable_caps_NamedBarrier[] = {spv::Capability::NamedBarrier};
 static const spv::Capability pygen_variable_caps_PipeStorage[] = {spv::Capability::PipeStorage};
 static const spv::Capability pygen_variable_caps_Pipes[] = {spv::Capability::Pipes};
+static const spv::Capability pygen_variable_caps_QuadControlKHR[] = {spv::Capability::QuadControlKHR};
 static const spv::Capability pygen_variable_caps_RayQueryKHR[] = {spv::Capability::RayQueryKHR};
 static const spv::Capability pygen_variable_caps_RayQueryPositionFetchKHR[] = {spv::Capability::RayQueryPositionFetchKHR};
 static const spv::Capability pygen_variable_caps_RayTracingKHR[] = {spv::Capability::RayTracingKHR};
@@ -520,6 +522,8 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
   {"FinalizeNodePayloadsAMDX", spv::Op::OpFinalizeNodePayloadsAMDX, 1, pygen_variable_caps_ShaderEnqueueAMDX, 1, {SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"FinishWritingNodePayloadAMDX", spv::Op::OpFinishWritingNodePayloadAMDX, 1, pygen_variable_caps_ShaderEnqueueAMDX, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"InitializeNodePayloadsAMDX", spv::Op::OpInitializeNodePayloadsAMDX, 1, pygen_variable_caps_ShaderEnqueueAMDX, 4, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
+  {"GroupNonUniformQuadAllKHR", spv::Op::OpGroupNonUniformQuadAllKHR, 1, pygen_variable_caps_QuadControlKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
+  {"GroupNonUniformQuadAnyKHR", spv::Op::OpGroupNonUniformQuadAnyKHR, 1, pygen_variable_caps_QuadControlKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"HitObjectRecordHitMotionNV", spv::Op::OpHitObjectRecordHitMotionNV, 2, pygen_variable_caps_ShaderInvocationReorderNVRayTracingMotionBlurNV, 14, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"HitObjectRecordHitWithIndexMotionNV", spv::Op::OpHitObjectRecordHitWithIndexMotionNV, 2, pygen_variable_caps_ShaderInvocationReorderNVRayTracingMotionBlurNV, 13, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"HitObjectRecordMissMotionNV", spv::Op::OpHitObjectRecordMissMotionNV, 2, pygen_variable_caps_ShaderInvocationReorderNVRayTracingMotionBlurNV, 7, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu},
@@ -841,5 +845,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
   {"GroupBitwiseXorKHR", spv::Op::OpGroupBitwiseXorKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"GroupLogicalAndKHR", spv::Op::OpGroupLogicalAndKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"GroupLogicalOrKHR", spv::Op::OpGroupLogicalOrKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
-  {"GroupLogicalXorKHR", spv::Op::OpGroupLogicalXorKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}
+  {"GroupLogicalXorKHR", spv::Op::OpGroupLogicalXorKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
+  {"MaskedGatherINTEL", spv::Op::OpMaskedGatherINTEL, 1, pygen_variable_caps_MaskedGatherScatterINTEL, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
+  {"MaskedScatterINTEL", spv::Op::OpMaskedScatterINTEL, 1, pygen_variable_caps_MaskedGatherScatterINTEL, 4, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}
 };

File diff suppressed because it is too large
+ 8 - 0
3rdparty/spirv-tools/include/generated/enum_string_mapping.inc


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

@@ -58,6 +58,7 @@ kSPV_INTEL_io_pipes,
 kSPV_INTEL_kernel_attributes,
 kSPV_INTEL_long_composites,
 kSPV_INTEL_loop_fuse,
+kSPV_INTEL_masked_gather_scatter,
 kSPV_INTEL_media_block_io,
 kSPV_INTEL_memory_access_aliasing,
 kSPV_INTEL_optnone,
@@ -76,15 +77,18 @@ kSPV_KHR_cooperative_matrix,
 kSPV_KHR_device_group,
 kSPV_KHR_expect_assume,
 kSPV_KHR_float_controls,
+kSPV_KHR_float_controls2,
 kSPV_KHR_fragment_shader_barycentric,
 kSPV_KHR_fragment_shading_rate,
 kSPV_KHR_integer_dot_product,
 kSPV_KHR_linkonce_odr,
+kSPV_KHR_maximal_reconvergence,
 kSPV_KHR_multiview,
 kSPV_KHR_no_integer_wrap_decoration,
 kSPV_KHR_non_semantic_info,
 kSPV_KHR_physical_storage_buffer,
 kSPV_KHR_post_depth_coverage,
+kSPV_KHR_quad_control,
 kSPV_KHR_ray_cull_mask,
 kSPV_KHR_ray_query,
 kSPV_KHR_ray_tracing,

+ 2 - 1
3rdparty/spirv-tools/include/generated/generators.inc

@@ -38,4 +38,5 @@
 {37, "heroseh", "Hero C Compiler", "heroseh Hero C Compiler"},
 {38, "Meta", "SparkSL", "Meta SparkSL"},
 {39, "SirLynix", "Nazara ShaderLang Compiler", "SirLynix Nazara ShaderLang Compiler"},
-{40, "NVIDIA", "Slang Compiler", "NVIDIA Slang Compiler"},
+{40, "NVIDIA", "Slang Compiler", "NVIDIA Slang Compiler"},
+{41, "Zig Software Foundation", "Zig Compiler", "Zig Software Foundation Zig Compiler"},

+ 23 - 5
3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc

@@ -15,7 +15,6 @@ static const spv::Capability pygen_variable_caps_DeviceEnqueue[] = {spv::Capabil
 static const spv::Capability pygen_variable_caps_DeviceGroup[] = {spv::Capability::DeviceGroup};
 static const spv::Capability pygen_variable_caps_DrawParameters[] = {spv::Capability::DrawParameters};
 static const spv::Capability pygen_variable_caps_DrawParametersMeshShadingNVMeshShadingEXT[] = {spv::Capability::DrawParameters, spv::Capability::MeshShadingNV, spv::Capability::MeshShadingEXT};
-static const spv::Capability pygen_variable_caps_FPFastMathModeINTEL[] = {spv::Capability::FPFastMathModeINTEL};
 static const spv::Capability pygen_variable_caps_FPGAArgumentInterfacesINTEL[] = {spv::Capability::FPGAArgumentInterfacesINTEL};
 static const spv::Capability pygen_variable_caps_FPGABufferLocationINTEL[] = {spv::Capability::FPGABufferLocationINTEL};
 static const spv::Capability pygen_variable_caps_FPGAClusterAttributesINTEL[] = {spv::Capability::FPGAClusterAttributesINTEL};
@@ -29,6 +28,8 @@ static const spv::Capability pygen_variable_caps_FPGALoopControlsINTEL[] = {spv:
 static const spv::Capability pygen_variable_caps_FPGAMemoryAccessesINTEL[] = {spv::Capability::FPGAMemoryAccessesINTEL};
 static const spv::Capability pygen_variable_caps_FPGAMemoryAttributesINTEL[] = {spv::Capability::FPGAMemoryAttributesINTEL};
 static const spv::Capability pygen_variable_caps_FPMaxErrorINTEL[] = {spv::Capability::FPMaxErrorINTEL};
+static const spv::Capability pygen_variable_caps_FloatControls2[] = {spv::Capability::FloatControls2};
+static const spv::Capability pygen_variable_caps_FloatControls2FPFastMathModeINTEL[] = {spv::Capability::FloatControls2, spv::Capability::FPFastMathModeINTEL};
 static const spv::Capability pygen_variable_caps_FragmentBarycentricNVFragmentBarycentricKHR[] = {spv::Capability::FragmentBarycentricNV, spv::Capability::FragmentBarycentricKHR};
 static const spv::Capability pygen_variable_caps_FragmentDensityEXTShadingRateNV[] = {spv::Capability::FragmentDensityEXT, spv::Capability::ShadingRateNV};
 static const spv::Capability pygen_variable_caps_FragmentFullyCoveredEXT[] = {spv::Capability::FragmentFullyCoveredEXT};
@@ -64,6 +65,7 @@ static const spv::Capability pygen_variable_caps_Int64[] = {spv::Capability::Int
 static const spv::Capability pygen_variable_caps_Int64ImageEXT[] = {spv::Capability::Int64ImageEXT};
 static const spv::Capability pygen_variable_caps_Int8[] = {spv::Capability::Int8};
 static const spv::Capability pygen_variable_caps_Kernel[] = {spv::Capability::Kernel};
+static const spv::Capability pygen_variable_caps_KernelFloatControls2[] = {spv::Capability::Kernel, spv::Capability::FloatControls2};
 static const spv::Capability pygen_variable_caps_KernelGroupNonUniform[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniform};
 static const spv::Capability pygen_variable_caps_KernelGroupNonUniformSubgroupBallotKHR[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniform, spv::Capability::SubgroupBallotKHR};
 static const spv::Capability pygen_variable_caps_KernelGroupNonUniformArithmeticGroupNonUniformBallot[] = {spv::Capability::Kernel, spv::Capability::GroupNonUniformArithmetic, spv::Capability::GroupNonUniformBallot};
@@ -83,6 +85,7 @@ static const spv::Capability pygen_variable_caps_OptNoneINTEL[] = {spv::Capabili
 static const spv::Capability pygen_variable_caps_PerViewAttributesNVMeshShadingNV[] = {spv::Capability::PerViewAttributesNV, spv::Capability::MeshShadingNV};
 static const spv::Capability pygen_variable_caps_PhysicalStorageBufferAddresses[] = {spv::Capability::PhysicalStorageBufferAddresses};
 static const spv::Capability pygen_variable_caps_Pipes[] = {spv::Capability::Pipes};
+static const spv::Capability pygen_variable_caps_QuadControlKHR[] = {spv::Capability::QuadControlKHR};
 static const spv::Capability pygen_variable_caps_RayCullMaskKHR[] = {spv::Capability::RayCullMaskKHR};
 static const spv::Capability pygen_variable_caps_RayQueryKHR[] = {spv::Capability::RayQueryKHR};
 static const spv::Capability pygen_variable_caps_RayQueryKHRRayTracingKHR[] = {spv::Capability::RayQueryKHR, spv::Capability::RayTracingKHR};
@@ -196,6 +199,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_io_pipes[] = {spv
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_kernel_attributes[] = {spvtools::Extension::kSPV_INTEL_kernel_attributes};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_long_composites[] = {spvtools::Extension::kSPV_INTEL_long_composites};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_loop_fuse[] = {spvtools::Extension::kSPV_INTEL_loop_fuse};
+static const spvtools::Extension pygen_variable_exts_SPV_INTEL_masked_gather_scatter[] = {spvtools::Extension::kSPV_INTEL_masked_gather_scatter};
 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_memory_access_aliasing[] = {spvtools::Extension::kSPV_INTEL_memory_access_aliasing};
 static const spvtools::Extension pygen_variable_exts_SPV_INTEL_optnone[] = {spvtools::Extension::kSPV_INTEL_optnone};
@@ -214,13 +218,16 @@ static const spvtools::Extension pygen_variable_exts_SPV_KHR_cooperative_matrix[
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_device_group[] = {spvtools::Extension::kSPV_KHR_device_group};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_expect_assume[] = {spvtools::Extension::kSPV_KHR_expect_assume};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_float_controls[] = {spvtools::Extension::kSPV_KHR_float_controls};
+static const spvtools::Extension pygen_variable_exts_SPV_KHR_float_controls2[] = {spvtools::Extension::kSPV_KHR_float_controls2};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_fragment_shader_barycentricSPV_NV_fragment_shader_barycentric[] = {spvtools::Extension::kSPV_KHR_fragment_shader_barycentric, spvtools::Extension::kSPV_NV_fragment_shader_barycentric};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_fragment_shading_rate[] = {spvtools::Extension::kSPV_KHR_fragment_shading_rate};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_integer_dot_product[] = {spvtools::Extension::kSPV_KHR_integer_dot_product};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_linkonce_odr[] = {spvtools::Extension::kSPV_KHR_linkonce_odr};
+static const spvtools::Extension pygen_variable_exts_SPV_KHR_maximal_reconvergence[] = {spvtools::Extension::kSPV_KHR_maximal_reconvergence};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_multiview[] = {spvtools::Extension::kSPV_KHR_multiview};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_no_integer_wrap_decoration[] = {spvtools::Extension::kSPV_KHR_no_integer_wrap_decoration};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_post_depth_coverage[] = {spvtools::Extension::kSPV_KHR_post_depth_coverage};
+static const spvtools::Extension pygen_variable_exts_SPV_KHR_quad_control[] = {spvtools::Extension::kSPV_KHR_quad_control};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_ray_cull_mask[] = {spvtools::Extension::kSPV_KHR_ray_cull_mask};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_ray_query[] = {spvtools::Extension::kSPV_KHR_ray_query};
 static const spvtools::Extension pygen_variable_exts_SPV_KHR_ray_querySPV_KHR_ray_tracing[] = {spvtools::Extension::kSPV_KHR_ray_query, spvtools::Extension::kSPV_KHR_ray_tracing};
@@ -290,8 +297,11 @@ static const spv_operand_desc_t pygen_variable_FPFastMathModeEntries[] = {
   {"NSZ", 0x0004, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"AllowRecip", 0x0008, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"Fast", 0x0010, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
-  {"AllowContractFastINTEL", 0x10000, 1, pygen_variable_caps_FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
-  {"AllowReassocINTEL", 0x20000, 1, pygen_variable_caps_FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
+  {"AllowContract", 0x10000, 2, pygen_variable_caps_FloatControls2FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"AllowContractFastINTEL", 0x10000, 2, pygen_variable_caps_FloatControls2FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"AllowReassoc", 0x20000, 2, pygen_variable_caps_FloatControls2FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"AllowReassocINTEL", 0x20000, 2, pygen_variable_caps_FloatControls2FPFastMathModeINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"AllowTransform", 0x40000, 1, pygen_variable_caps_FloatControls2, 0, nullptr, {}, 0xffffffffu, 0xffffffffu}
 };
 
 static const spv_operand_desc_t pygen_variable_SelectionControlEntries[] = {
@@ -408,7 +418,8 @@ static const spv_operand_desc_t pygen_variable_SourceLanguageEntries[] = {
   {"HERO_C", 8, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"NZSL", 9, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"WGSL", 10, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
-  {"Slang", 11, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}
+  {"Slang", 11, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
+  {"Zig", 12, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}
 };
 
 static const spv_operand_desc_t pygen_variable_ExecutionModelEntries[] = {
@@ -515,6 +526,8 @@ static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = {
   {"StencilRefUnchangedBackAMD", 5082, 1, pygen_variable_caps_StencilExportEXT, 2, pygen_variable_exts_SPV_AMD_shader_early_and_late_fragment_testsSPV_EXT_shader_stencil_export, {}, 0xffffffffu, 0xffffffffu},
   {"StencilRefGreaterBackAMD", 5083, 1, pygen_variable_caps_StencilExportEXT, 2, pygen_variable_exts_SPV_AMD_shader_early_and_late_fragment_testsSPV_EXT_shader_stencil_export, {}, 0xffffffffu, 0xffffffffu},
   {"StencilRefLessBackAMD", 5084, 1, pygen_variable_caps_StencilExportEXT, 2, pygen_variable_exts_SPV_AMD_shader_early_and_late_fragment_testsSPV_EXT_shader_stencil_export, {}, 0xffffffffu, 0xffffffffu},
+  {"QuadDerivativesKHR", 5088, 1, pygen_variable_caps_QuadControlKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
+  {"RequireFullQuadsKHR", 5089, 1, pygen_variable_caps_QuadControlKHR, 0, nullptr, {}, 0xffffffffu, 0xffffffffu},
   {"OutputLinesNV", 5269, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu},
   {"OutputLinesEXT", 5269, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu},
   {"OutputPrimitivesNV", 5270, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
@@ -539,6 +552,8 @@ static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = {
   {"NoGlobalOffsetINTEL", 5895, 1, pygen_variable_caps_KernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {}, 0xffffffffu, 0xffffffffu},
   {"NumSIMDWorkitemsINTEL", 5896, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 1, pygen_variable_exts_SPV_INTEL_kernel_attributes, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
   {"SchedulerTargetFmaxMhzINTEL", 5903, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
+  {"MaximallyReconvergesKHR", 6023, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_maximal_reconvergence, {}, 0xffffffffu, 0xffffffffu},
+  {"FPFastMathDefault", 6028, 1, pygen_variable_caps_FloatControls2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 0xffffffffu, 0xffffffffu},
   {"StreamingInterfaceINTEL", 6154, 1, pygen_variable_caps_FPGAKernelAttributesINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
   {"RegisterMapInterfaceINTEL", 6160, 1, pygen_variable_caps_FPGAKernelAttributesv2INTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu},
   {"NamedBarrierCountINTEL", 6417, 1, pygen_variable_caps_VectorComputeINTEL, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu}
@@ -802,7 +817,7 @@ static const spv_operand_desc_t pygen_variable_DecorationEntries[] = {
   {"XfbStride", 37, 1, pygen_variable_caps_TransformFeedback, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"FuncParamAttr", 38, 1, pygen_variable_caps_Kernel, 0, nullptr, {SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"FPRoundingMode", 39, 0, nullptr, 0, nullptr, {SPV_OPERAND_TYPE_FP_ROUNDING_MODE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
-  {"FPFastMathMode", 40, 1, pygen_variable_caps_Kernel, 0, nullptr, {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
+  {"FPFastMathMode", 40, 2, pygen_variable_caps_KernelFloatControls2, 0, nullptr, {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"LinkageAttributes", 41, 1, pygen_variable_caps_Linkage, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_STRING, SPV_OPERAND_TYPE_LINKAGE_TYPE}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"NoContraction", 42, 1, pygen_variable_caps_Shader, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
   {"InputAttachmentIndex", 43, 1, pygen_variable_caps_InputAttachment, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu},
@@ -1194,6 +1209,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
   {"Int64ImageEXT", 5016, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_shader_image_int64, {}, 0xffffffffu, 0xffffffffu},
   {"ShaderClockKHR", 5055, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_shader_clock, {}, 0xffffffffu, 0xffffffffu},
   {"ShaderEnqueueAMDX", 5067, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_AMDX_shader_enqueue, {}, 0xffffffffu, 0xffffffffu},
+  {"QuadControlKHR", 5087, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_quad_control, {}, 0xffffffffu, 0xffffffffu},
   {"SampleMaskOverrideCoverageNV", 5249, 1, pygen_variable_caps_SampleRateShading, 1, pygen_variable_exts_SPV_NV_sample_mask_override_coverage, {}, 0xffffffffu, 0xffffffffu},
   {"GeometryShaderPassthroughNV", 5251, 1, pygen_variable_caps_Geometry, 1, pygen_variable_exts_SPV_NV_geometry_shader_passthrough, {}, 0xffffffffu, 0xffffffffu},
   {"ShaderViewportIndexLayerEXT", 5254, 1, pygen_variable_caps_MultiViewport, 2, pygen_variable_exts_SPV_EXT_shader_viewport_index_layerSPV_NV_viewport_array2, {}, 0xffffffffu, 0xffffffffu},
@@ -1313,6 +1329,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
   {"CooperativeMatrixKHR", 6022, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_cooperative_matrix, {}, 0xffffffffu, 0xffffffffu},
   {"BitInstructions", 6025, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_bit_instructions, {}, 0xffffffffu, 0xffffffffu},
   {"GroupNonUniformRotateKHR", 6026, 1, pygen_variable_caps_GroupNonUniform, 1, pygen_variable_exts_SPV_KHR_subgroup_rotate, {}, 0xffffffffu, 0xffffffffu},
+  {"FloatControls2", 6029, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_float_controls2, {}, 0xffffffffu, 0xffffffffu},
   {"AtomicFloat32AddEXT", 6033, 0, nullptr, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float_add, {}, 0xffffffffu, 0xffffffffu},
   {"AtomicFloat64AddEXT", 6034, 0, nullptr, 1, pygen_variable_exts_SPV_EXT_shader_atomic_float_add, {}, 0xffffffffu, 0xffffffffu},
   {"LongCompositesINTEL", 6089, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_long_composites, {}, 0xffffffffu, 0xffffffffu},
@@ -1329,6 +1346,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
   {"GlobalVariableHostAccessINTEL", 6187, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_global_variable_host_access, {}, 0xffffffffu, 0xffffffffu},
   {"GlobalVariableFPGADecorationsINTEL", 6189, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_global_variable_fpga_decorations, {}, 0xffffffffu, 0xffffffffu},
   {"GroupUniformArithmeticKHR", 6400, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_uniform_group_instructions, {}, 0xffffffffu, 0xffffffffu},
+  {"MaskedGatherScatterINTEL", 6427, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_masked_gather_scatter, {}, 0xffffffffu, 0xffffffffu},
   {"CacheControlsINTEL", 6441, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_cache_controls, {}, 0xffffffffu, 0xffffffffu}
 };
 

+ 4 - 0
3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp

@@ -1003,6 +1003,10 @@ Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t ds_from,
 // OpBeginInterlockInvocationEXT and one OpEndInterlockInvocationEXT, in that
 // order.
 Optimizer::PassToken CreateInvocationInterlockPlacementPass();
+
+// Creates a pass to add/remove maximal reconvergence execution mode.
+// This pass either adds or removes maximal reconvergence from all entry points.
+Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add);
 }  // namespace spvtools
 
 #endif  // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_

+ 2 - 0
3rdparty/spirv-tools/source/opcode.cpp

@@ -534,6 +534,8 @@ bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
     case spv::Op::OpGroupNonUniformQuadBroadcast:
     case spv::Op::OpGroupNonUniformQuadSwap:
     case spv::Op::OpGroupNonUniformRotateKHR:
+    case spv::Op::OpGroupNonUniformQuadAllKHR:
+    case spv::Op::OpGroupNonUniformQuadAnyKHR:
       return true;
     default:
       return false;

+ 1 - 0
3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp

@@ -985,6 +985,7 @@ void AggressiveDCEPass::InitExtensions() {
       "SPV_NV_shader_image_footprint",
       "SPV_NV_shading_rate",
       "SPV_NV_mesh_shader",
+      "SPV_EXT_mesh_shader",
       "SPV_NV_ray_tracing",
       "SPV_KHR_ray_tracing",
       "SPV_KHR_ray_query",

+ 11 - 0
3rdparty/spirv-tools/source/opt/block_merge_util.cpp

@@ -98,6 +98,17 @@ bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) {
     return false;
   }
 
+  // Note: This means that the instructions in a break block will execute as if
+  // they were still diverged according to the loop iteration. This restricts
+  // potential transformations an implementation may perform on the IR to match
+  // shader author expectations. Similarly, instructions in the loop construct
+  // cannot be moved into the continue construct unless it can be proven that
+  // invocations are always converged.
+  if (succ_is_merge && context->get_feature_mgr()->HasExtension(
+                           kSPV_KHR_maximal_reconvergence)) {
+    return false;
+  }
+
   if (pred_is_merge && IsContinue(context, lab_id)) {
     // Cannot merge a continue target with a merge block.
     return false;

+ 219 - 1
3rdparty/spirv-tools/source/opt/const_folding_rules.cpp

@@ -21,6 +21,59 @@ namespace opt {
 namespace {
 constexpr uint32_t kExtractCompositeIdInIdx = 0;
 
+// Returns the value obtained by extracting the |number_of_bits| least
+// significant bits from |value|, and sign-extending it to 64-bits.
+uint64_t SignExtendValue(uint64_t value, uint32_t number_of_bits) {
+  if (number_of_bits == 64) return value;
+
+  uint64_t mask_for_sign_bit = 1ull << (number_of_bits - 1);
+  uint64_t mask_for_significant_bits = (mask_for_sign_bit << 1) - 1ull;
+  if (value & mask_for_sign_bit) {
+    // Set upper bits to 1
+    value |= ~mask_for_significant_bits;
+  } else {
+    // Clear the upper bits
+    value &= mask_for_significant_bits;
+  }
+  return value;
+}
+
+// Returns the value obtained by extracting the |number_of_bits| least
+// significant bits from |value|, and zero-extending it to 64-bits.
+uint64_t ZeroExtendValue(uint64_t value, uint32_t number_of_bits) {
+  if (number_of_bits == 64) return value;
+
+  uint64_t mask_for_first_bit_to_clear = 1ull << (number_of_bits);
+  uint64_t mask_for_bits_to_keep = mask_for_first_bit_to_clear - 1;
+  value &= mask_for_bits_to_keep;
+  return value;
+}
+
+// Returns a constant whose value is `value` and type is `type`. This constant
+// will be generated by `const_mgr`. The type must be a scalar integer type.
+const analysis::Constant* GenerateIntegerConstant(
+    const analysis::Integer* integer_type, uint64_t result,
+    analysis::ConstantManager* const_mgr) {
+  assert(integer_type != nullptr);
+
+  std::vector<uint32_t> words;
+  if (integer_type->width() == 64) {
+    // In the 64-bit case, two words are needed to represent the value.
+    words = {static_cast<uint32_t>(result),
+             static_cast<uint32_t>(result >> 32)};
+  } else {
+    // In all other cases, only a single word is needed.
+    assert(integer_type->width() <= 32);
+    if (integer_type->IsSigned()) {
+      result = SignExtendValue(result, integer_type->width());
+    } else {
+      result = ZeroExtendValue(result, integer_type->width());
+    }
+    words = {static_cast<uint32_t>(result)};
+  }
+  return const_mgr->GetConstant(integer_type, words);
+}
+
 // Returns a constants with the value NaN of the given type.  Only works for
 // 32-bit and 64-bit float point types.  Returns |nullptr| if an error occurs.
 const analysis::Constant* GetNan(const analysis::Type* type,
@@ -676,7 +729,6 @@ ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) {
   return [scalar_rule](IRContext* context, Instruction* inst,
                        const std::vector<const analysis::Constant*>& constants)
              -> const analysis::Constant* {
-
     analysis::ConstantManager* const_mgr = context->get_constant_mgr();
     analysis::TypeManager* type_mgr = context->get_type_mgr();
     const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
@@ -716,6 +768,64 @@ ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) {
   };
 }
 
+// Returns a |ConstantFoldingRule| that folds binary scalar ops
+// using |scalar_rule| and binary vectors ops by applying
+// |scalar_rule| to the elements of the vector. The folding rule assumes that op
+// has two inputs. For regular instruction, those are in operands 0 and 1. For
+// extended instruction, they are in operands 1 and 2. If an element in
+// |constants| is not nullprt, then the constant's type is |Float|, |Integer|,
+// or |Vector| whose element type is |Float| or |Integer|.
+ConstantFoldingRule FoldBinaryOp(BinaryScalarFoldingRule scalar_rule) {
+  return [scalar_rule](IRContext* context, Instruction* inst,
+                       const std::vector<const analysis::Constant*>& constants)
+             -> const analysis::Constant* {
+    assert(constants.size() == inst->NumInOperands());
+    assert(constants.size() == (inst->opcode() == spv::Op::OpExtInst ? 3 : 2));
+    analysis::ConstantManager* const_mgr = context->get_constant_mgr();
+    analysis::TypeManager* type_mgr = context->get_type_mgr();
+    const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
+    const analysis::Vector* vector_type = result_type->AsVector();
+
+    const analysis::Constant* arg1 =
+        (inst->opcode() == spv::Op::OpExtInst) ? constants[1] : constants[0];
+    const analysis::Constant* arg2 =
+        (inst->opcode() == spv::Op::OpExtInst) ? constants[2] : constants[1];
+
+    if (arg1 == nullptr || arg2 == nullptr) {
+      return nullptr;
+    }
+
+    if (vector_type == nullptr) {
+      return scalar_rule(result_type, arg1, arg2, const_mgr);
+    }
+
+    std::vector<const analysis::Constant*> a_components;
+    std::vector<const analysis::Constant*> b_components;
+    std::vector<const analysis::Constant*> results_components;
+
+    a_components = arg1->GetVectorComponents(const_mgr);
+    b_components = arg2->GetVectorComponents(const_mgr);
+    assert(a_components.size() == b_components.size());
+
+    // Fold each component of the vector.
+    for (uint32_t i = 0; i < a_components.size(); ++i) {
+      results_components.push_back(scalar_rule(vector_type->element_type(),
+                                               a_components[i], b_components[i],
+                                               const_mgr));
+      if (results_components[i] == nullptr) {
+        return nullptr;
+      }
+    }
+
+    // Build the constant object and return it.
+    std::vector<uint32_t> ids;
+    for (const analysis::Constant* member : results_components) {
+      ids.push_back(const_mgr->GetDefiningInstruction(member)->result_id());
+    }
+    return const_mgr->GetConstant(vector_type, ids);
+  };
+}
+
 // Returns a |ConstantFoldingRule| that folds unary floating point scalar ops
 // using |scalar_rule| and unary float point vectors ops by applying
 // |scalar_rule| to the elements of the vector.  The |ConstantFoldingRule|
@@ -1587,6 +1697,72 @@ BinaryScalarFoldingRule FoldFTranscendentalBinary(double (*fp)(double,
         return nullptr;
       };
 }
+
+enum Sign { Signed, Unsigned };
+
+// Returns a BinaryScalarFoldingRule that applies `op` to the scalars.
+// The `signedness` is used to determine if the operands should be interpreted
+// as signed or unsigned. If the operands are signed, the value will be sign
+// extended before the value is passed to `op`. Otherwise the values will be
+// zero extended.
+template <Sign signedness>
+BinaryScalarFoldingRule FoldBinaryIntegerOperation(uint64_t (*op)(uint64_t,
+                                                                  uint64_t)) {
+  return
+      [op](const analysis::Type* result_type, const analysis::Constant* a,
+           const analysis::Constant* b,
+           analysis::ConstantManager* const_mgr) -> const analysis::Constant* {
+        assert(result_type != nullptr && a != nullptr && b != nullptr);
+        const analysis::Integer* integer_type = result_type->AsInteger();
+        assert(integer_type != nullptr);
+        assert(integer_type == a->type()->AsInteger());
+        assert(integer_type == b->type()->AsInteger());
+
+        // In SPIR-V, all operations support unsigned types, but the way they
+        // are interpreted depends on the opcode. This is why we use the
+        // template argument to determine how to interpret the operands.
+        uint64_t ia = (signedness == Signed ? a->GetSignExtendedValue()
+                                            : a->GetZeroExtendedValue());
+        uint64_t ib = (signedness == Signed ? b->GetSignExtendedValue()
+                                            : b->GetZeroExtendedValue());
+        uint64_t result = op(ia, ib);
+
+        const analysis::Constant* result_constant =
+            GenerateIntegerConstant(integer_type, result, const_mgr);
+        return result_constant;
+      };
+}
+
+// A scalar folding rule that folds OpSConvert.
+const analysis::Constant* FoldScalarSConvert(
+    const analysis::Type* result_type, const analysis::Constant* a,
+    analysis::ConstantManager* const_mgr) {
+  assert(result_type != nullptr);
+  assert(a != nullptr);
+  assert(const_mgr != nullptr);
+  const analysis::Integer* integer_type = result_type->AsInteger();
+  assert(integer_type && "The result type of an SConvert");
+  int64_t value = a->GetSignExtendedValue();
+  return GenerateIntegerConstant(integer_type, value, const_mgr);
+}
+
+// A scalar folding rule that folds OpUConvert.
+const analysis::Constant* FoldScalarUConvert(
+    const analysis::Type* result_type, const analysis::Constant* a,
+    analysis::ConstantManager* const_mgr) {
+  assert(result_type != nullptr);
+  assert(a != nullptr);
+  assert(const_mgr != nullptr);
+  const analysis::Integer* integer_type = result_type->AsInteger();
+  assert(integer_type && "The result type of an UConvert");
+  uint64_t value = a->GetZeroExtendedValue();
+
+  // If the operand was an unsigned value with less than 32-bit, it would have
+  // been sign extended earlier, and we need to clear those bits.
+  auto* operand_type = a->type()->AsInteger();
+  value = ZeroExtendValue(value, operand_type->width());
+  return GenerateIntegerConstant(integer_type, value, const_mgr);
+}
 }  // namespace
 
 void ConstantFoldingRules::AddFoldingRules() {
@@ -1604,6 +1780,8 @@ void ConstantFoldingRules::AddFoldingRules() {
   rules_[spv::Op::OpConvertFToU].push_back(FoldFToI());
   rules_[spv::Op::OpConvertSToF].push_back(FoldIToF());
   rules_[spv::Op::OpConvertUToF].push_back(FoldIToF());
+  rules_[spv::Op::OpSConvert].push_back(FoldUnaryOp(FoldScalarSConvert));
+  rules_[spv::Op::OpUConvert].push_back(FoldUnaryOp(FoldScalarUConvert));
 
   rules_[spv::Op::OpDot].push_back(FoldOpDotWithConstants());
   rules_[spv::Op::OpFAdd].push_back(FoldFAdd());
@@ -1662,6 +1840,46 @@ void ConstantFoldingRules::AddFoldingRules() {
   rules_[spv::Op::OpSNegate].push_back(FoldSNegate());
   rules_[spv::Op::OpQuantizeToF16].push_back(FoldQuantizeToF16());
 
+  rules_[spv::Op::OpIAdd].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return a + b; })));
+  rules_[spv::Op::OpISub].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return a - b; })));
+  rules_[spv::Op::OpIMul].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return a * b; })));
+  rules_[spv::Op::OpUDiv].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return (b != 0 ? a / b : 0); })));
+  rules_[spv::Op::OpSDiv].push_back(FoldBinaryOp(
+      FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
+        return (b != 0 ? static_cast<uint64_t>(static_cast<int64_t>(a) /
+                                               static_cast<int64_t>(b))
+                       : 0);
+      })));
+  rules_[spv::Op::OpUMod].push_back(
+      FoldBinaryOp(FoldBinaryIntegerOperation<Unsigned>(
+          [](uint64_t a, uint64_t b) { return (b != 0 ? a % b : 0); })));
+
+  rules_[spv::Op::OpSRem].push_back(FoldBinaryOp(
+      FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
+        return (b != 0 ? static_cast<uint64_t>(static_cast<int64_t>(a) %
+                                               static_cast<int64_t>(b))
+                       : 0);
+      })));
+
+  rules_[spv::Op::OpSMod].push_back(FoldBinaryOp(
+      FoldBinaryIntegerOperation<Signed>([](uint64_t a, uint64_t b) {
+        if (b == 0) return static_cast<uint64_t>(0ull);
+
+        int64_t signed_a = static_cast<int64_t>(a);
+        int64_t signed_b = static_cast<int64_t>(b);
+        int64_t result = signed_a % signed_b;
+        if ((signed_b < 0) != (result < 0)) result += signed_b;
+        return static_cast<uint64_t>(result);
+      })));
+
   // Add rules for GLSLstd450
   FeatureManager* feature_manager = context_->get_feature_mgr();
   uint32_t ext_inst_glslstd450_id =

+ 22 - 2
3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp

@@ -171,6 +171,19 @@ bool ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
 
 bool ConvertToHalfPass::GenHalfArith(Instruction* inst) {
   bool modified = false;
+  // If this is a OpCompositeExtract instruction and has a struct operand, we
+  // should not relax this instruction. Doing so could cause a mismatch between
+  // the result type and the struct member type.
+  bool hasStructOperand = false;
+  if (inst->opcode() == spv::Op::OpCompositeExtract) {
+    inst->ForEachInId([&hasStructOperand, this](uint32_t* idp) {
+      Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
+      if (IsStruct(op_inst)) hasStructOperand = true;
+    });
+    if (hasStructOperand) {
+      return false;
+    }
+  }
   // Convert all float32 based operands to float16 equivalent and change
   // instruction type to float16 equivalent.
   inst->ForEachInId([&inst, &modified, this](uint32_t* idp) {
@@ -303,12 +316,19 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) {
   if (closure_ops_.count(inst->opcode()) == 0) return false;
   // Can relax if all float operands are relaxed
   bool relax = true;
-  inst->ForEachInId([&relax, this](uint32_t* idp) {
+  bool hasStructOperand = false;
+  inst->ForEachInId([&relax, &hasStructOperand, this](uint32_t* idp) {
     Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
-    if (IsStruct(op_inst)) relax = false;
+    if (IsStruct(op_inst)) hasStructOperand = true;
     if (!IsFloat(op_inst, 32)) return;
     if (!IsRelaxed(*idp)) relax = false;
   });
+  // If the instruction has a struct operand, we should not relax it, even if
+  // all its uses are relaxed. Doing so could cause a mismatch between the
+  // result type and the struct member type.
+  if (hasStructOperand) {
+    return false;
+  }
   if (relax) {
     AddRelaxed(inst->result_id());
     return true;

+ 0 - 22
3rdparty/spirv-tools/source/opt/def_use_manager.h

@@ -27,28 +27,6 @@ namespace spvtools {
 namespace opt {
 namespace analysis {
 
-// Class for representing a use of id. Note that:
-// * Result type id is a use.
-// * Ids referenced in OpSectionMerge & OpLoopMerge are considered as use.
-// * Ids referenced in OpPhi's in operands are considered as use.
-struct Use {
-  Instruction* inst;       // Instruction using the id.
-  uint32_t operand_index;  // logical operand index of the id use. This can be
-                           // the index of result type id.
-};
-
-inline bool operator==(const Use& lhs, const Use& rhs) {
-  return lhs.inst == rhs.inst && lhs.operand_index == rhs.operand_index;
-}
-
-inline bool operator!=(const Use& lhs, const Use& rhs) { return !(lhs == rhs); }
-
-inline bool operator<(const Use& lhs, const Use& rhs) {
-  if (lhs.inst < rhs.inst) return true;
-  if (lhs.inst > rhs.inst) return false;
-  return lhs.operand_index < rhs.operand_index;
-}
-
 // Definition should never be null. User can be null, however, such an entry
 // should be used only for searching (e.g. all users of a particular definition)
 // and never stored in a container.

+ 47 - 2
3rdparty/spirv-tools/source/opt/desc_sroa.cpp

@@ -54,9 +54,10 @@ Pass::Status DescriptorScalarReplacement::Process() {
 bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
   std::vector<Instruction*> access_chain_work_list;
   std::vector<Instruction*> load_work_list;
+  std::vector<Instruction*> entry_point_work_list;
   bool failed = !get_def_use_mgr()->WhileEachUser(
-      var->result_id(),
-      [this, &access_chain_work_list, &load_work_list](Instruction* use) {
+      var->result_id(), [this, &access_chain_work_list, &load_work_list,
+                         &entry_point_work_list](Instruction* use) {
         if (use->opcode() == spv::Op::OpName) {
           return true;
         }
@@ -73,6 +74,9 @@ bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
           case spv::Op::OpLoad:
             load_work_list.push_back(use);
             return true;
+          case spv::Op::OpEntryPoint:
+            entry_point_work_list.push_back(use);
+            return true;
           default:
             context()->EmitErrorMessage(
                 "Variable cannot be replaced: invalid instruction", use);
@@ -95,6 +99,11 @@ bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) {
       return false;
     }
   }
+  for (Instruction* use : entry_point_work_list) {
+    if (!ReplaceEntryPoint(var, use)) {
+      return false;
+    }
+  }
   return true;
 }
 
@@ -147,6 +156,42 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var,
   return true;
 }
 
+bool DescriptorScalarReplacement::ReplaceEntryPoint(Instruction* var,
+                                                    Instruction* use) {
+  // Build a new |OperandList| for |use| that removes |var| and adds its
+  // replacement variables.
+  Instruction::OperandList new_operands;
+
+  // Copy all operands except |var|.
+  bool found = false;
+  for (uint32_t idx = 0; idx < use->NumOperands(); idx++) {
+    Operand& op = use->GetOperand(idx);
+    if (op.type == SPV_OPERAND_TYPE_ID && op.words[0] == var->result_id()) {
+      found = true;
+    } else {
+      new_operands.emplace_back(op);
+    }
+  }
+
+  if (!found) {
+    context()->EmitErrorMessage(
+        "Variable cannot be replaced: invalid instruction", use);
+    return false;
+  }
+
+  // Add all new replacement variables.
+  uint32_t num_replacement_vars =
+      descsroautil::GetNumberOfElementsForArrayOrStruct(context(), var);
+  for (uint32_t i = 0; i < num_replacement_vars; i++) {
+    new_operands.push_back(
+        {SPV_OPERAND_TYPE_ID, {GetReplacementVariable(var, i)}});
+  }
+
+  use->ReplaceOperands(new_operands);
+  context()->UpdateDefUse(use);
+  return true;
+}
+
 uint32_t DescriptorScalarReplacement::GetReplacementVariable(Instruction* var,
                                                              uint32_t idx) {
   auto replacement_vars = replacement_variables_.find(var);

+ 5 - 0
3rdparty/spirv-tools/source/opt/desc_sroa.h

@@ -64,6 +64,11 @@ class DescriptorScalarReplacement : public Pass {
   // otherwise.
   bool ReplaceLoadedValue(Instruction* var, Instruction* value);
 
+  // Replaces the given composite variable |var| in the OpEntryPoint with the
+  // new replacement variables, one for each element of the array |var|. Returns
+  // |true| if successful, and |false| otherwise.
+  bool ReplaceEntryPoint(Instruction* var, Instruction* use);
+
   // Replaces the given OpCompositeExtract |extract| and all of its references
   // with an OpLoad of a replacement variable. |var| is the variable with
   // composite type whose value is being used by |extract|. Assumes that

+ 6 - 0
3rdparty/spirv-tools/source/opt/ir_context.h

@@ -229,6 +229,8 @@ class IRContext {
   inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
   // Set the memory model for this module.
   inline void SetMemoryModel(std::unique_ptr<Instruction>&& m);
+  // Get the memory model for this module.
+  inline const Instruction* GetMemoryModel() const;
   // Appends an entry point instruction to this module.
   inline void AddEntryPoint(std::unique_ptr<Instruction>&& e);
   // Appends an execution mode instruction to this module.
@@ -1156,6 +1158,10 @@ void IRContext::SetMemoryModel(std::unique_ptr<Instruction>&& m) {
   module()->SetMemoryModel(std::move(m));
 }
 
+const Instruction* IRContext::GetMemoryModel() const {
+  return module()->GetMemoryModel();
+}
+
 void IRContext::AddEntryPoint(std::unique_ptr<Instruction>&& e) {
   module()->AddEntryPoint(std::move(e));
 }

+ 2 - 2
3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp

@@ -420,8 +420,8 @@ void LocalAccessChainConvertPass::InitExtensions() {
        "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing",
        "SPV_NV_fragment_shader_barycentric",
        "SPV_NV_compute_shader_derivatives", "SPV_NV_shader_image_footprint",
-       "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing",
-       "SPV_KHR_ray_tracing", "SPV_KHR_ray_query",
+       "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_EXT_mesh_shader",
+       "SPV_NV_ray_tracing", "SPV_KHR_ray_tracing", "SPV_KHR_ray_query",
        "SPV_EXT_fragment_invocation_density", "SPV_KHR_terminate_invocation",
        "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product",
        "SPV_EXT_shader_image_int64", "SPV_KHR_non_semantic_info",

+ 1 - 0
3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp

@@ -273,6 +273,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
                                 "SPV_NV_shader_image_footprint",
                                 "SPV_NV_shading_rate",
                                 "SPV_NV_mesh_shader",
+                                "SPV_EXT_mesh_shader",
                                 "SPV_NV_ray_tracing",
                                 "SPV_KHR_ray_tracing",
                                 "SPV_KHR_ray_query",

+ 1 - 0
3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp

@@ -124,6 +124,7 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() {
                                 "SPV_NV_shader_image_footprint",
                                 "SPV_NV_shading_rate",
                                 "SPV_NV_mesh_shader",
+                                "SPV_EXT_mesh_shader",
                                 "SPV_NV_ray_tracing",
                                 "SPV_KHR_ray_query",
                                 "SPV_EXT_fragment_invocation_density",

+ 103 - 0
3rdparty/spirv-tools/source/opt/modify_maximal_reconvergence.cpp

@@ -0,0 +1,103 @@
+// Copyright (c) 2024 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 "modify_maximal_reconvergence.h"
+
+#include "source/opt/ir_context.h"
+#include "source/util/make_unique.h"
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status ModifyMaximalReconvergence::Process() {
+  bool changed = false;
+  if (add_) {
+    changed = AddMaximalReconvergence();
+  } else {
+    changed = RemoveMaximalReconvergence();
+  }
+  return changed ? Pass::Status::SuccessWithChange
+                 : Pass::Status::SuccessWithoutChange;
+}
+
+bool ModifyMaximalReconvergence::AddMaximalReconvergence() {
+  bool changed = false;
+  bool has_extension = false;
+  bool has_shader =
+      context()->get_feature_mgr()->HasCapability(spv::Capability::Shader);
+  for (auto extension : context()->extensions()) {
+    if (extension.GetOperand(0).AsString() == "SPV_KHR_maximal_reconvergence") {
+      has_extension = true;
+      break;
+    }
+  }
+
+  std::unordered_set<uint32_t> entry_points_with_mode;
+  for (auto mode : get_module()->execution_modes()) {
+    if (spv::ExecutionMode(mode.GetSingleWordInOperand(1)) ==
+        spv::ExecutionMode::MaximallyReconvergesKHR) {
+      entry_points_with_mode.insert(mode.GetSingleWordInOperand(0));
+    }
+  }
+
+  for (auto entry_point : get_module()->entry_points()) {
+    const uint32_t id = entry_point.GetSingleWordInOperand(1);
+    if (!entry_points_with_mode.count(id)) {
+      changed = true;
+      if (!has_extension) {
+        context()->AddExtension("SPV_KHR_maximal_reconvergence");
+        has_extension = true;
+      }
+      if (!has_shader) {
+        context()->AddCapability(spv::Capability::Shader);
+        has_shader = true;
+      }
+      context()->AddExecutionMode(MakeUnique<Instruction>(
+          context(), spv::Op::OpExecutionMode, 0, 0,
+          std::initializer_list<Operand>{
+              {SPV_OPERAND_TYPE_ID, {id}},
+              {SPV_OPERAND_TYPE_EXECUTION_MODE,
+               {static_cast<uint32_t>(
+                   spv::ExecutionMode::MaximallyReconvergesKHR)}}}));
+      entry_points_with_mode.insert(id);
+    }
+  }
+
+  return changed;
+}
+
+bool ModifyMaximalReconvergence::RemoveMaximalReconvergence() {
+  bool changed = false;
+  std::vector<Instruction*> to_remove;
+  Instruction* mode = &*get_module()->execution_mode_begin();
+  while (mode) {
+    if (mode->opcode() != spv::Op::OpExecutionMode &&
+        mode->opcode() != spv::Op::OpExecutionModeId) {
+      break;
+    }
+    if (spv::ExecutionMode(mode->GetSingleWordInOperand(1)) ==
+        spv::ExecutionMode::MaximallyReconvergesKHR) {
+      mode = context()->KillInst(mode);
+      changed = true;
+    } else {
+      mode = mode->NextNode();
+    }
+  }
+
+  changed |=
+      context()->RemoveExtension(Extension::kSPV_KHR_maximal_reconvergence);
+  return changed;
+}
+}  // namespace opt
+}  // namespace spvtools

+ 53 - 0
3rdparty/spirv-tools/source/opt/modify_maximal_reconvergence.h

@@ -0,0 +1,53 @@
+// Copyright (c) 2024 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 LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_
+#define LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_
+
+#include "pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// Modifies entry points to either add or remove MaximallyReconvergesKHR
+//
+// This pass will either add or remove MaximallyReconvergesKHR to all entry
+// points in the module. When adding the execution mode, it does not attempt to
+// determine whether any ray tracing invocation repack instructions might be
+// executed because it is a runtime restriction. That is left to the user.
+class ModifyMaximalReconvergence : public Pass {
+ public:
+  const char* name() const override { return "modify-maximal-reconvergence"; }
+  Status Process() override;
+
+  explicit ModifyMaximalReconvergence(bool add = true) : Pass(), add_(add) {}
+
+  IRContext::Analysis GetPreservedAnalyses() override {
+    return IRContext::kAnalysisDefUse |
+           IRContext::kAnalysisInstrToBlockMapping |
+           IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
+           IRContext::kAnalysisCFG | IRContext::kAnalysisNameMap |
+           IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
+  }
+
+ private:
+  bool AddMaximalReconvergence();
+  bool RemoveMaximalReconvergence();
+
+  bool add_;
+};
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_

+ 24 - 0
3rdparty/spirv-tools/source/opt/optimizer.cpp

@@ -606,6 +606,25 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag,
       return false;
     }
     RegisterPass(CreateSwitchDescriptorSetPass(from_set, to_set));
+  } else if (pass_name == "modify-maximal-reconvergence") {
+    if (pass_args.size() == 0) {
+      Error(consumer(), nullptr, {},
+            "--modify-maximal-reconvergence requires an argument");
+      return false;
+    }
+    if (pass_args == "add") {
+      RegisterPass(CreateModifyMaximalReconvergencePass(true));
+    } else if (pass_args == "remove") {
+      RegisterPass(CreateModifyMaximalReconvergencePass(false));
+    } else {
+      Errorf(consumer(), nullptr, {},
+             "Invalid argument for --modify-maximal-reconvergence: %s (must be "
+             "'add' or 'remove')",
+             pass_args.c_str());
+      return false;
+    }
+  } else if (pass_name == "trim-capabilities") {
+    RegisterPass(CreateTrimCapabilitiesPass());
   } else {
     Errorf(consumer(), nullptr, {},
            "Unknown flag '--%s'. Use --help for a list of valid flags",
@@ -1141,6 +1160,11 @@ Optimizer::PassToken CreateInvocationInterlockPlacementPass() {
   return MakeUnique<Optimizer::PassToken::Impl>(
       MakeUnique<opt::InvocationInterlockPlacementPass>());
 }
+
+Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add) {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::ModifyMaximalReconvergence>(add));
+}
 }  // namespace spvtools
 
 extern "C" {

+ 1 - 0
3rdparty/spirv-tools/source/opt/passes.h

@@ -65,6 +65,7 @@
 #include "source/opt/loop_unroller.h"
 #include "source/opt/loop_unswitch_pass.h"
 #include "source/opt/merge_return_pass.h"
+#include "source/opt/modify_maximal_reconvergence.h"
 #include "source/opt/null_pass.h"
 #include "source/opt/private_to_local_pass.h"
 #include "source/opt/reduce_load_size.h"

+ 11 - 0
3rdparty/spirv-tools/source/opt/trim_capabilities_pass.cpp

@@ -448,6 +448,17 @@ void TrimCapabilitiesPass::addInstructionRequirementsForOperand(
     return;
   }
 
+  // If the Vulkan memory model is declared and any instruction uses Device
+  // scope, the VulkanMemoryModelDeviceScope capability must be declared. This
+  // rule cannot be covered by the grammar, so must be checked explicitly.
+  if (operand.type == SPV_OPERAND_TYPE_SCOPE_ID) {
+    const Instruction* memory_model = context()->GetMemoryModel();
+    if (memory_model && memory_model->GetSingleWordInOperand(1u) ==
+                            uint32_t(spv::MemoryModel::Vulkan)) {
+      capabilities->insert(spv::Capability::VulkanMemoryModelDeviceScope);
+    }
+  }
+
   // case 1: Operand is a single value, can directly lookup.
   if (!spvOperandIsConcreteMask(operand.type)) {
     const spv_operand_desc_t* desc = {};

+ 2 - 1
3rdparty/spirv-tools/source/opt/trim_capabilities_pass.h

@@ -97,7 +97,8 @@ class TrimCapabilitiesPass : public Pass {
       spv::Capability::StorageInputOutput16,
       spv::Capability::StoragePushConstant16,
       spv::Capability::StorageUniform16,
-      spv::Capability::StorageUniformBufferBlock16
+      spv::Capability::StorageUniformBufferBlock16,
+      spv::Capability::VulkanMemoryModelDeviceScope
       // clang-format on
   };
 

+ 4 - 0
3rdparty/spirv-tools/source/val/validate.cpp

@@ -141,6 +141,10 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
     }
   }
 
+  if (auto error = ValidateFloatControls2(_)) {
+    return error;
+  }
+
   return SPV_SUCCESS;
 }
 

+ 12 - 0
3rdparty/spirv-tools/source/val/validate.h

@@ -82,6 +82,18 @@ spv_result_t ValidateAdjacency(ValidationState_t& _);
 /// @return SPV_SUCCESS if no errors are found.
 spv_result_t ValidateInterfaces(ValidationState_t& _);
 
+/// @brief Validates entry point call tree requirements of
+/// SPV_KHR_float_controls2
+///
+/// Checks that no entry point using FPFastMathDefault uses:
+/// * FPFastMathMode Fast
+/// * NoContraction
+///
+/// @param[in] _ the validation state of the module
+///
+/// @return SPV_SUCCESS if no errors are found.
+spv_result_t ValidateFloatControls2(ValidationState_t& _);
+
 /// @brief Validates memory instructions
 ///
 /// @param[in] _ the validation state of the module

+ 28 - 0
3rdparty/spirv-tools/source/val/validate_annotation.cpp

@@ -267,6 +267,34 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
     }
   }
 
+  if (decoration == spv::Decoration::FPFastMathMode) {
+    if (_.HasDecoration(target_id, spv::Decoration::NoContraction)) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "FPFastMathMode and NoContraction cannot decorate the same "
+                "target";
+    }
+    auto mask = inst->GetOperandAs<spv::FPFastMathModeMask>(2);
+    if ((mask & spv::FPFastMathModeMask::AllowTransform) !=
+            spv::FPFastMathModeMask::MaskNone &&
+        ((mask & (spv::FPFastMathModeMask::AllowContract |
+                  spv::FPFastMathModeMask::AllowReassoc)) !=
+         (spv::FPFastMathModeMask::AllowContract |
+          spv::FPFastMathModeMask::AllowReassoc))) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "AllowReassoc and AllowContract must be specified when "
+                "AllowTransform is specified";
+    }
+  }
+
+  // This is checked from both sides since we register decorations as we go.
+  if (decoration == spv::Decoration::NoContraction) {
+    if (_.HasDecoration(target_id, spv::Decoration::FPFastMathMode)) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "FPFastMathMode and NoContraction cannot decorate the same "
+                "target";
+    }
+  }
+
   if (DecorationTakesIdParameters(decoration)) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
            << "Decorations taking ID parameters may not be used with "

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

@@ -118,13 +118,15 @@ typedef enum VUIDError_ {
   VUIDErrorMax,
 } VUIDError;
 
-const static uint32_t NumVUIDBuiltins = 36;
+const static uint32_t NumVUIDBuiltins = 39;
 
 typedef struct {
   spv::BuiltIn builtIn;
   uint32_t vuid[VUIDErrorMax];  // execution mode, storage class, type VUIDs
 } BuiltinVUIDMapping;
 
+// Many built-ins have the same checks (Storage Class, Type, etc)
+// This table provides a nice LUT for the VUIDs
 std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
     // clang-format off
     {spv::BuiltIn::SubgroupEqMask,            {0,    4370, 4371}},
@@ -163,8 +165,11 @@ std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
     {spv::BuiltIn::CullMaskKHR,               {6735, 6736, 6737}},
     {spv::BuiltIn::BaryCoordKHR,              {4154, 4155, 4156}},
     {spv::BuiltIn::BaryCoordNoPerspKHR,       {4160, 4161, 4162}},
-    // clang-format off
-} };
+    {spv::BuiltIn::PrimitivePointIndicesEXT,  {7041, 7043, 7044}},
+    {spv::BuiltIn::PrimitiveLineIndicesEXT,   {7047, 7049, 7050}},
+    {spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}},
+    // clang-format on
+}};
 
 uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) {
   uint32_t vuid = 0;
@@ -356,6 +361,9 @@ class BuiltInsValidator {
   spv_result_t ValidateRayTracingBuiltinsAtDefinition(
       const Decoration& decoration, const Instruction& inst);
 
+  spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition(
+      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|
@@ -546,6 +554,11 @@ class BuiltInsValidator {
       const Instruction& referenced_inst,
       const Instruction& referenced_from_inst);
 
+  spv_result_t ValidateMeshShadingEXTBuiltinsAtReference(
+      const Decoration& decoration, const Instruction& built_in_inst,
+      const Instruction& referenced_inst,
+      const Instruction& referenced_from_inst);
+
   // Validates that |built_in_inst| is not (even indirectly) referenced from
   // within a function which can be called with |execution_model|.
   //
@@ -581,6 +594,10 @@ class BuiltInsValidator {
   spv_result_t ValidateI32Arr(
       const Decoration& decoration, const Instruction& inst,
       const std::function<spv_result_t(const std::string& message)>& diag);
+  spv_result_t ValidateArrayedI32Vec(
+      const Decoration& decoration, const Instruction& inst,
+      uint32_t num_components,
+      const std::function<spv_result_t(const std::string& message)>& diag);
   spv_result_t ValidateOptionalArrayedI32(
       const Decoration& decoration, const Instruction& inst,
       const std::function<spv_result_t(const std::string& message)>& diag);
@@ -909,6 +926,45 @@ spv_result_t BuiltInsValidator::ValidateI32Vec(
   return SPV_SUCCESS;
 }
 
+spv_result_t BuiltInsValidator::ValidateArrayedI32Vec(
+    const Decoration& decoration, const Instruction& inst,
+    uint32_t num_components,
+    const std::function<spv_result_t(const std::string& message)>& diag) {
+  uint32_t underlying_type = 0;
+  if (spv_result_t error =
+          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
+    return error;
+  }
+
+  const Instruction* const type_inst = _.FindDef(underlying_type);
+  if (type_inst->opcode() != spv::Op::OpTypeArray) {
+    return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
+  }
+
+  const uint32_t component_type = type_inst->word(2);
+  if (!_.IsIntVectorType(component_type)) {
+    return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
+  }
+
+  const uint32_t actual_num_components = _.GetDimension(component_type);
+  if (_.GetDimension(component_type) != num_components) {
+    std::ostringstream ss;
+    ss << GetDefinitionDesc(decoration, inst) << " has "
+       << actual_num_components << " components.";
+    return diag(ss.str());
+  }
+
+  const uint32_t bit_width = _.GetBitWidth(component_type);
+  if (bit_width != 32) {
+    std::ostringstream ss;
+    ss << GetDefinitionDesc(decoration, inst)
+       << " has components with bit width " << bit_width << ".";
+    return diag(ss.str());
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec(
     const Decoration& decoration, const Instruction& inst,
     uint32_t num_components,
@@ -4108,6 +4164,119 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
   return SPV_SUCCESS;
 }
 
+spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
+    const Decoration& decoration, const Instruction& inst) {
+  if (spvIsVulkanEnv(_.context()->target_env)) {
+    const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
+    uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
+    if (builtin == spv::BuiltIn::PrimitivePointIndicesEXT) {
+      if (spv_result_t error = ValidateI32Arr(
+              decoration, inst,
+              [this, &inst, &decoration,
+               &vuid](const std::string& message) -> spv_result_t {
+                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                       << _.VkErrorID(vuid) << "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 array."
+                       << message;
+              })) {
+        return error;
+      }
+    }
+    if (builtin == spv::BuiltIn::PrimitiveLineIndicesEXT) {
+      if (spv_result_t error = ValidateArrayedI32Vec(
+              decoration, inst, 2,
+              [this, &inst, &decoration,
+               &vuid](const std::string& message) -> spv_result_t {
+                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                       << _.VkErrorID(vuid) << "According to the "
+                       << spvLogStringForEnv(_.context()->target_env)
+                       << " spec BuiltIn "
+                       << _.grammar().lookupOperandName(
+                              SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
+                       << " variable needs to be a 2-component 32-bit int "
+                          "array."
+                       << message;
+              })) {
+        return error;
+      }
+    }
+    if (builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT) {
+      if (spv_result_t error = ValidateArrayedI32Vec(
+              decoration, inst, 3,
+              [this, &inst, &decoration,
+               &vuid](const std::string& message) -> spv_result_t {
+                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                       << _.VkErrorID(vuid) << "According to the "
+                       << spvLogStringForEnv(_.context()->target_env)
+                       << " spec BuiltIn "
+                       << _.grammar().lookupOperandName(
+                              SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
+                       << " variable needs to be a 3-component 32-bit int "
+                          "array."
+                       << message;
+              })) {
+        return error;
+      }
+    }
+  }
+  // Seed at reference checks with this built-in.
+  return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst,
+                                                   inst);
+}
+
+spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference(
+    const Decoration& decoration, const Instruction& built_in_inst,
+    const Instruction& referenced_inst,
+    const Instruction& referenced_from_inst) {
+  if (spvIsVulkanEnv(_.context()->target_env)) {
+    const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
+    const spv::StorageClass storage_class =
+        GetStorageClass(referenced_from_inst);
+    if (storage_class != spv::StorageClass::Max &&
+        storage_class != spv::StorageClass::Output) {
+      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
+      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
+             << " spec allows BuiltIn "
+             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                              uint32_t(builtin))
+             << " to be only used for variables with Output storage class. "
+             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+                                 referenced_from_inst)
+             << " " << GetStorageClassDesc(referenced_from_inst);
+    }
+
+    for (const spv::ExecutionModel execution_model : execution_models_) {
+      if (execution_model != spv::ExecutionModel::MeshEXT) {
+        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
+        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+               << _.VkErrorID(vuid)
+               << spvLogStringForEnv(_.context()->target_env)
+               << " spec allows BuiltIn "
+               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                                uint32_t(builtin))
+               << " to be used only with MeshEXT 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::ValidateMeshShadingEXTBuiltinsAtReference,
+                  this, decoration, built_in_inst, referenced_from_inst,
+                  std::placeholders::_1));
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
     const Decoration& decoration, const Instruction& inst) {
   const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]);
@@ -4283,6 +4452,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
     case spv::BuiltIn::CullMaskKHR: {
       return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
     }
+    case spv::BuiltIn::PrimitivePointIndicesEXT:
+    case spv::BuiltIn::PrimitiveLineIndicesEXT:
+    case spv::BuiltIn::PrimitiveTriangleIndicesEXT: {
+      return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst);
+    }
     case spv::BuiltIn::PrimitiveShadingRateKHR: {
       return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
     }

+ 96 - 0
3rdparty/spirv-tools/source/val/validate_cfg.cpp

@@ -190,6 +190,8 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _,
               "ID of an OpLabel instruction";
   }
 
+  // A similar requirement for SPV_KHR_maximal_reconvergence is deferred until
+  // entry point call trees have been reconrded.
   if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 6) && true_id == false_id) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
            << "In SPIR-V 1.6 or later, True Label and False Label must be "
@@ -875,6 +877,95 @@ spv_result_t StructuredControlFlowChecks(
   return SPV_SUCCESS;
 }
 
+spv_result_t MaximalReconvergenceChecks(ValidationState_t& _) {
+  // Find all the entry points with the MaximallyReconvergencesKHR execution
+  // mode.
+  std::unordered_set<uint32_t> maximal_funcs;
+  std::unordered_set<uint32_t> maximal_entry_points;
+  for (auto entry_point : _.entry_points()) {
+    const auto* exec_modes = _.GetExecutionModes(entry_point);
+    if (exec_modes &&
+        exec_modes->count(spv::ExecutionMode::MaximallyReconvergesKHR)) {
+      maximal_entry_points.insert(entry_point);
+      maximal_funcs.insert(entry_point);
+    }
+  }
+
+  if (maximal_entry_points.empty()) {
+    return SPV_SUCCESS;
+  }
+
+  // Find all the functions reachable from a maximal reconvergence entry point.
+  for (const auto& func : _.functions()) {
+    const auto& entry_points = _.EntryPointReferences(func.id());
+    for (auto id : entry_points) {
+      if (maximal_entry_points.count(id)) {
+        maximal_funcs.insert(func.id());
+        break;
+      }
+    }
+  }
+
+  // Check for conditional branches with the same true and false targets.
+  for (const auto& inst : _.ordered_instructions()) {
+    if (inst.opcode() == spv::Op::OpBranchConditional) {
+      const auto true_id = inst.GetOperandAs<uint32_t>(1);
+      const auto false_id = inst.GetOperandAs<uint32_t>(2);
+      if (true_id == false_id && maximal_funcs.count(inst.function()->id())) {
+        return _.diag(SPV_ERROR_INVALID_ID, &inst)
+               << "In entry points using the MaximallyReconvergesKHR execution "
+                  "mode, True Label and False Label must be different labels";
+      }
+    }
+  }
+
+  // Check for invalid multiple predecessors. Only loop headers, continue
+  // targets, merge targets or switch targets or defaults may have multiple
+  // unique predecessors.
+  for (const auto& func : _.functions()) {
+    if (!maximal_funcs.count(func.id())) continue;
+
+    for (const auto* block : func.ordered_blocks()) {
+      std::unordered_set<uint32_t> unique_preds;
+      const auto* preds = block->predecessors();
+      if (!preds) continue;
+
+      for (const auto* pred : *preds) {
+        unique_preds.insert(pred->id());
+      }
+      if (unique_preds.size() < 2) continue;
+
+      const auto* terminator = block->terminator();
+      const auto index = terminator - &_.ordered_instructions()[0];
+      const auto* pre_terminator = &_.ordered_instructions()[index - 1];
+      if (pre_terminator->opcode() == spv::Op::OpLoopMerge) continue;
+
+      const auto* label = _.FindDef(block->id());
+      bool ok = false;
+      for (const auto& pair : label->uses()) {
+        const auto* use_inst = pair.first;
+        switch (use_inst->opcode()) {
+          case spv::Op::OpSelectionMerge:
+          case spv::Op::OpLoopMerge:
+          case spv::Op::OpSwitch:
+            ok = true;
+            break;
+          default:
+            break;
+        }
+      }
+      if (!ok) {
+        return _.diag(SPV_ERROR_INVALID_CFG, label)
+               << "In entry points using the MaximallyReconvergesKHR "
+                  "execution mode, this basic block must not have multiple "
+                  "unique predecessors";
+      }
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t PerformCfgChecks(ValidationState_t& _) {
   for (auto& function : _.functions()) {
     // Check all referenced blocks are defined within a function
@@ -999,6 +1090,11 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) {
         return error;
     }
   }
+
+  if (auto error = MaximalReconvergenceChecks(_)) {
+    return error;
+  }
+
   return SPV_SUCCESS;
 }
 

+ 2 - 1
3rdparty/spirv-tools/source/val/validate_instruction.cpp

@@ -470,7 +470,8 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) {
     }
     _.set_addressing_model(inst->GetOperandAs<spv::AddressingModel>(0));
     _.set_memory_model(inst->GetOperandAs<spv::MemoryModel>(1));
-  } else if (opcode == spv::Op::OpExecutionMode) {
+  } else if (opcode == spv::Op::OpExecutionMode ||
+             opcode == spv::Op::OpExecutionModeId) {
     const uint32_t entry_point = inst->word(1);
     _.RegisterExecutionModeForEntryPoint(entry_point,
                                          spv::ExecutionMode(inst->word(2)));

+ 1 - 4
3rdparty/spirv-tools/source/val/validate_memory_semantics.cpp

@@ -203,15 +203,12 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
                 "storage class";
     }
 
-#if 0
-    // TODO([email protected]): this check fails Vulkan CTS, reenable once fixed.
     if (opcode == spv::Op::OpControlBarrier && value && !includes_storage_class) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
-             << spvOpcodeString(opcode)
+             << _.VkErrorID(4650) << spvOpcodeString(opcode)
              << ": expected Memory Semantics to include a Vulkan-supported "
                 "storage class if Memory Semantics is not None";
     }
-#endif
   }
 
   if (opcode == spv::Op::OpAtomicFlagClear &&

+ 169 - 16
3rdparty/spirv-tools/source/val/validate_mode_setting.cpp

@@ -340,29 +340,92 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
 
   const auto mode = inst->GetOperandAs<spv::ExecutionMode>(1);
   if (inst->opcode() == spv::Op::OpExecutionModeId) {
+    bool valid_mode = false;
+    switch (mode) {
+      case spv::ExecutionMode::SubgroupsPerWorkgroupId:
+      case spv::ExecutionMode::LocalSizeHintId:
+      case spv::ExecutionMode::LocalSizeId:
+      case spv::ExecutionMode::FPFastMathDefault:
+        valid_mode = true;
+        break;
+      default:
+        valid_mode = false;
+        break;
+    }
+    if (!valid_mode) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "OpExecutionModeId is only valid when the Mode operand is an "
+                "execution mode that takes Extra Operands that are id "
+                "operands.";
+    }
+
     size_t operand_count = inst->operands().size();
     for (size_t i = 2; i < operand_count; ++i) {
-      const auto operand_id = inst->GetOperandAs<uint32_t>(2);
+      const auto operand_id = inst->GetOperandAs<uint32_t>(i);
       const auto* operand_inst = _.FindDef(operand_id);
-      if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
-          mode == spv::ExecutionMode::LocalSizeHintId ||
-          mode == spv::ExecutionMode::LocalSizeId) {
-        if (!spvOpcodeIsConstant(operand_inst->opcode())) {
-          return _.diag(SPV_ERROR_INVALID_ID, inst)
-                 << "For OpExecutionModeId all Extra Operand ids must be "
-                    "constant "
-                    "instructions.";
-        }
-      } else {
-        return _.diag(SPV_ERROR_INVALID_ID, inst)
-               << "OpExecutionModeId is only valid when the Mode operand is an "
-                  "execution mode that takes Extra Operands that are id "
-                  "operands.";
+      switch (mode) {
+        case spv::ExecutionMode::SubgroupsPerWorkgroupId:
+        case spv::ExecutionMode::LocalSizeHintId:
+        case spv::ExecutionMode::LocalSizeId:
+          if (!spvOpcodeIsConstant(operand_inst->opcode())) {
+            return _.diag(SPV_ERROR_INVALID_ID, inst)
+                   << "For OpExecutionModeId all Extra Operand ids must be "
+                      "constant instructions.";
+          }
+          break;
+        case spv::ExecutionMode::FPFastMathDefault:
+          if (i == 2) {
+            if (!_.IsFloatScalarType(operand_id)) {
+              return _.diag(SPV_ERROR_INVALID_ID, inst)
+                     << "The Target Type operand must be a floating-point "
+                        "scalar type";
+            }
+          } else {
+            bool is_int32 = false;
+            bool is_const = false;
+            uint32_t value = 0;
+            std::tie(is_int32, is_const, value) =
+                _.EvalInt32IfConst(operand_id);
+            if (is_int32 && is_const) {
+              // Valid values include up to 0x00040000 (AllowTransform).
+              uint32_t invalid_mask = 0xfff80000;
+              if ((invalid_mask & value) != 0) {
+                return _.diag(SPV_ERROR_INVALID_ID, inst)
+                       << "The Fast Math Default operand is an invalid bitmask "
+                          "value";
+              }
+              if (value &
+                  static_cast<uint32_t>(spv::FPFastMathModeMask::Fast)) {
+                return _.diag(SPV_ERROR_INVALID_ID, inst)
+                       << "The Fast Math Default operand must not include Fast";
+              }
+              const auto reassoc_contract =
+                  spv::FPFastMathModeMask::AllowContract |
+                  spv::FPFastMathModeMask::AllowReassoc;
+              if ((value & static_cast<uint32_t>(
+                               spv::FPFastMathModeMask::AllowTransform)) != 0 &&
+                  ((value & static_cast<uint32_t>(reassoc_contract)) !=
+                   static_cast<uint32_t>(reassoc_contract))) {
+                return _.diag(SPV_ERROR_INVALID_ID, inst)
+                       << "The Fast Math Default operand must include "
+                          "AllowContract and AllowReassoc when AllowTransform "
+                          "is specified";
+              }
+            } else {
+              return _.diag(SPV_ERROR_INVALID_ID, inst)
+                     << "The Fast Math Default operand must be a "
+                        "non-specialization constant";
+            }
+          }
+          break;
+        default:
+          break;
       }
     }
   } else if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
              mode == spv::ExecutionMode::LocalSizeHintId ||
-             mode == spv::ExecutionMode::LocalSizeId) {
+             mode == spv::ExecutionMode::LocalSizeId ||
+             mode == spv::ExecutionMode::FPFastMathDefault) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
            << "OpExecutionMode is only valid when the Mode operand is an "
               "execution mode that takes no Extra Operands, or takes Extra "
@@ -494,6 +557,17 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
                   "model.";
       }
       break;
+    case spv::ExecutionMode::QuadDerivativesKHR:
+      if (!std::all_of(models->begin(), models->end(),
+                       [](const spv::ExecutionModel& model) {
+                         return (model == spv::ExecutionModel::Fragment ||
+                                 model == spv::ExecutionModel::GLCompute);
+                       })) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Execution mode can only be used with the Fragment or "
+                  "GLCompute execution model.";
+      }
+      break;
     case spv::ExecutionMode::PixelCenterInteger:
     case spv::ExecutionMode::OriginUpperLeft:
     case spv::ExecutionMode::OriginLowerLeft:
@@ -518,6 +592,7 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
     case spv::ExecutionMode::StencilRefUnchangedBackAMD:
     case spv::ExecutionMode::StencilRefGreaterBackAMD:
     case spv::ExecutionMode::StencilRefLessBackAMD:
+    case spv::ExecutionMode::RequireFullQuadsKHR:
       if (!std::all_of(models->begin(), models->end(),
                        [](const spv::ExecutionModel& model) {
                          return model == spv::ExecutionModel::Fragment;
@@ -579,6 +654,20 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
       break;
   }
 
+  if (mode == spv::ExecutionMode::FPFastMathDefault) {
+    const auto* modes = _.GetExecutionModes(entry_point_id);
+    if (modes && modes->count(spv::ExecutionMode::ContractionOff)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "FPFastMathDefault and ContractionOff execution modes cannot "
+                "be applied to the same entry point";
+    }
+    if (modes && modes->count(spv::ExecutionMode::SignedZeroInfNanPreserve)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, inst)
+             << "FPFastMathDefault and SignedZeroInfNanPreserve execution "
+                "modes cannot be applied to the same entry point";
+    }
+  }
+
   if (spvIsVulkanEnv(_.context()->target_env)) {
     if (mode == spv::ExecutionMode::OriginLowerLeft) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
@@ -636,6 +725,70 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _,
 
 }  // namespace
 
+spv_result_t ValidateFloatControls2(ValidationState_t& _) {
+  std::unordered_set<uint32_t> fp_fast_math_default_entry_points;
+  for (auto entry_point : _.entry_points()) {
+    const auto* exec_modes = _.GetExecutionModes(entry_point);
+    if (exec_modes &&
+        exec_modes->count(spv::ExecutionMode::FPFastMathDefault)) {
+      fp_fast_math_default_entry_points.insert(entry_point);
+    }
+  }
+
+  std::vector<std::pair<const Instruction*, spv::Decoration>> worklist;
+  for (const auto& inst : _.ordered_instructions()) {
+    if (inst.opcode() != spv::Op::OpDecorate) {
+      continue;
+    }
+
+    const auto decoration = inst.GetOperandAs<spv::Decoration>(1);
+    const auto target_id = inst.GetOperandAs<uint32_t>(0);
+    const auto target = _.FindDef(target_id);
+    if (decoration == spv::Decoration::NoContraction) {
+      worklist.push_back(std::make_pair(target, decoration));
+    } else if (decoration == spv::Decoration::FPFastMathMode) {
+      auto mask = inst.GetOperandAs<spv::FPFastMathModeMask>(2);
+      if ((mask & spv::FPFastMathModeMask::Fast) !=
+          spv::FPFastMathModeMask::MaskNone) {
+        worklist.push_back(std::make_pair(target, decoration));
+      }
+    }
+  }
+
+  std::unordered_set<const Instruction*> visited;
+  while (!worklist.empty()) {
+    const auto inst = worklist.back().first;
+    const auto decoration = worklist.back().second;
+    worklist.pop_back();
+
+    if (!visited.insert(inst).second) {
+      continue;
+    }
+
+    const auto function = inst->function();
+    if (function) {
+      const auto& entry_points = _.FunctionEntryPoints(function->id());
+      for (auto entry_point : entry_points) {
+        if (fp_fast_math_default_entry_points.count(entry_point)) {
+          const std::string dec = decoration == spv::Decoration::NoContraction
+                                      ? "NoContraction"
+                                      : "FPFastMathMode Fast";
+          return _.diag(SPV_ERROR_INVALID_DATA, inst)
+                 << dec
+                 << " cannot be used by an entry point with the "
+                    "FPFastMathDefault execution mode";
+        }
+      }
+    } else {
+      for (const auto& pair : inst->uses()) {
+        worklist.push_back(std::make_pair(pair.first, decoration));
+      }
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
   switch (inst->opcode()) {
     case spv::Op::OpEntryPoint:

+ 8 - 3
3rdparty/spirv-tools/source/val/validate_non_uniform.cpp

@@ -422,9 +422,14 @@ spv_result_t NonUniformPass(ValidationState_t& _, const Instruction* inst) {
   const spv::Op opcode = inst->opcode();
 
   if (spvOpcodeIsNonUniformGroupOperation(opcode)) {
-    const uint32_t execution_scope = inst->GetOperandAs<uint32_t>(2);
-    if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
-      return error;
+    // OpGroupNonUniformQuadAllKHR and OpGroupNonUniformQuadAnyKHR don't have
+    // scope paramter
+    if ((opcode != spv::Op::OpGroupNonUniformQuadAllKHR) &&
+        (opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) {
+      const uint32_t execution_scope = inst->GetOperandAs<uint32_t>(2);
+      if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
+        return error;
+      }
     }
   }
 

+ 6 - 2
3rdparty/spirv-tools/source/val/validate_scopes.cpp

@@ -97,8 +97,10 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
     // Vulkan 1.1 specific rules
     if (_.context()->target_env != SPV_ENV_VULKAN_1_0) {
       // Scope for Non Uniform Group Operations must be limited to Subgroup
-      if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
-          value != spv::Scope::Subgroup) {
+      if ((spvOpcodeIsNonUniformGroupOperation(opcode) &&
+           (opcode != spv::Op::OpGroupNonUniformQuadAllKHR) &&
+           (opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) &&
+          (value != spv::Scope::Subgroup)) {
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
                << _.VkErrorID(4642) << spvOpcodeString(opcode)
                << ": in Vulkan environment Execution scope is limited to "
@@ -178,6 +180,8 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
   // Scope for execution must be limited to Workgroup or Subgroup for
   // non-uniform operations
   if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
+      opcode != spv::Op::OpGroupNonUniformQuadAllKHR &&
+      opcode != spv::Op::OpGroupNonUniformQuadAnyKHR &&
       value != spv::Scope::Subgroup && value != spv::Scope::Workgroup) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
            << spvOpcodeString(opcode)

+ 20 - 0
3rdparty/spirv-tools/source/val/validation_state.cpp

@@ -2125,6 +2125,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
       return VUID_WRAP(VUID-StandaloneSpirv-None-04644);
     case 4645:
       return VUID_WRAP(VUID-StandaloneSpirv-None-04645);
+    case 4650:
+      return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04650);
     case 4651:
       return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651);
     case 4652:
@@ -2257,6 +2259,24 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
       return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06808);
     case 6925:
       return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925);
+    case 7041:
+      return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041);
+    case 7043:
+      return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043);
+    case 7044:
+      return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044);
+    case 7047:
+      return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07047);
+    case 7049:
+      return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049);
+    case 7050:
+      return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050);
+    case 7053:
+      return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07053);
+    case 7055:
+      return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055);
+    case 7056:
+      return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056);
     case 7102:
       return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102);
     case 7320:

Some files were not shown because too many files changed in this diff